v25.1 (2025-02-13)
✨ Highlights
-
The legacy
borrowed/inoutkeywords and-> T as foosyntax are deprecated and now generate a compiler warning. Please move toread/mut/outargument syntax instead. See Argument conventions in the Mojo Manual for more information. -
The
bool(),float(),int(), andstr()functions are deprecated and generate compiler warnings. Please use theBool(),Float64(),Int(), andString()constructors instead. See Standard library changes for more details. -
The standard library has many changes related to strings. The new
Charstruct represents a single Unicode character, and includes several methods for categorizing character types. When iterating over the characters of aStringwith aforloop, you now should use theString.chars()method to provide an iterator ofCharvalues or theString.char_slices()method to provide an iterator ofStringSliceinstances for each character.StringRefhas been removed in favor ofStringSlice. And various functionality has moved fromStringandStringLiteralto the more generalStringSlicetype. See Standard library changes for more details. -
You can now use
SIMDconstructors to cast existingSIMDvalues (includingScalarvalues) to a different type, though you can still use theSIMD.cast()method to infer the size of the new vector. See Standard library changes for more details.
Language changes
-
The legacy
borrowed/inoutkeywords and-> T as foosyntax now generate a warning. Please move toread/mut/outargument syntax instead. See Argument conventions in the Mojo Manual for more information. -
Initializers are now treated as static methods that return an instance of
Self. This means theoutargument of an initializer is now treated the same as any other function result oroutargument. This is generally invisible, except that patterns likeinstance.__init__()andx.__copyinit__(y)no longer work. Simply replace them withinstance = T()andx = yrespectively. -
The
@valuedecorator now additionally derives an implementation of theExplicitlyCopyabletrait. This will ease the transition to explicit copyability requirements by default in the Mojo collection types. -
Indexing into a homogenous tuple now produces the consistent element type without needing a rebind:
var x = (1, 2, 3, 3, 4)
var y : Int = x[idx] # Just works! -
You can now overload positional arguments with a keyword-only argument, and keyword-only arguments with different names:
struct OverloadedKwArgs:
var val: Int
fn __init__(out self, single: Int):
self.val = single
fn __init__(out self, *, double: Int):
self.val = double * 2
fn __init__(out self, *, triple: Int):
self.val = triple * 3
fn main():
OverloadedKwArgs(1) # val=1
OverloadedKwArgs(double=1) # val=2
OverloadedKwArgs(triple=2) # val=6This also works with indexing operations:
struct OverloadedKwArgs:
var vals: List[Int]
fn __init__(out self):
self.vals = List[Int](0, 1, 2)
fn __getitem__(self, idx: Int) -> Int:
return self.vals[idx]
fn __getitem__(self, *, idx2: Int) -> Int:
return self.vals[idx2 * 2]
fn __setitem__(mut self, idx: Int, val: Int):
self.vals[idx] = val
fn __setitem__(mut self, val: Int, *, idx2: Int):
self.vals[idx2 * 2] = val
fn main():
var x = OverloadedKwArgs()
print(x[1]) # 1
print(x[idx2=1]) # 2
x[1] = 42
x[idx2=1] = 84
print(x[1]) # 42
print(x[idx2=1]) # 84 -
The
__disable_del xoperation has been tightened up to treat all fields ofxas consumed by the point of the deletion, so it should be used after all the subfields are transferred or otherwise consumed (for example, at the end of the function), not before uses of the fields.
GPU programming
-
The new
gpupackage provides low-level programming constructs for working with GPUs. The MojogpuAPIs allow you to manually manage interaction between the CPU host and GPU device, manage memory between devices, synchronize threads, and more. Currently the best way to use these APIs is from inside a MAX custom operation.The following code example shows a GPU kernel written in Mojo:
from max.tensor import ManagedTensorSlice
from gpu import thread_idx, block_dim, block_idx
fn gpu_add_kernel(out: ManagedTensorSlice, x: ManagedTensorSlice[out.type, out.rank]):
tid_x = thread_idx.x + block_dim.x * block_idx.x
tid_y = thread_idx.y + block_dim.y * block_dim.y
if tid_x < x.dim_size(0) and tid_y < x.dim_size(1):
out[tid_x, tid_y] = x[tid_x, tid_y] + 1The example above includes only the actual kernel code that’s run on the GPU, not the code to define a custom operation or launch the kernel. For more complete examples, see
vector_addition.mojoandtop_k.mojo. -
The
layoutpackage includes APIs for working with layouts, which describe the organization of a tensor (for example, row-major or column-major layout), and theLayoutTensortype, which represents a tensor with a specified layout. Thelayoutpackage can be used to build efficient tensor operations that run on a GPU.We’ll continue adding code examples and documentation for the
gpuandlayoutpackages in future releases.
Standard library changes
-
The builtin functions for converting values to different types have been deprecated for actual constructors:
Before After bool()Bool()float()Float64()int()Int()str()String()These functions were a workaround before Mojo had a way to distinguish between implicit and explicit constructors. For this release you'll get a deprecation warning, and in the next release they'll become compiler errors. You can quickly update your code by doing a
Match CaseandMatch Whole Wordsearch and replace forint(toInt(etc. -
Stringand friends:-
Added
Charfor representing and storing single Unicode characters.-
CharimplementsCollectionElement,EqualityComparable,Intable, andStringable. -
Charprovides methods for categorizing character types, including:Char.is_ascii(),Char.is_ascii_digit(),Char.is_ascii_upper(),Char.is_ascii_lower(),Char.is_ascii_printable(),Char.is_posix_space(),Char.is_python_space(). -
Added a
String()constructor fromChar. -
Charcan be converted toUInt32viaChar.to_u32(). -
chr()will now abort if given a codepoint value that is not a validChar.
-
-
StringRefhas been removed in favor ofStringSlice. The two types are ABI compatible, and for the exact same behavior one can useStaticString, which is an alias toStringSlice[StaticConstantOrigin]. -
Various functionality has moved from
StringandStringLiteralto the more generalStringSlicetype. -
Added
StringSlice.from_utf8()factory method, for validated construction of aStringSlicefrom a buffer containing UTF-8 encoded data. This method will raise if the buffer contents are not valid UTF-8. -
Added
StringSlice.chars()which returns an iterator overChars. This is a compliant UTF-8 decoder that returns each Unicode codepoint encoded in the string. -
Added
StringSlice.__getitem__(Slice)which returns a substring. Only step sizes of 1 are supported. -
Several standard library functions have been changed to take
StringSliceinstead ofString. This generalizes them to be used for any appropriately encoded string in memory, without requiring that the string be heap allocated. This includes:ascii(),atol(),atof(),b16decode(),b16encode(),b64decode(),b64encode(), andord(). -
Added new
String.chars()andString.char_slices()iterator methods, and deprecated the existingString.__iter__()method.Different use-cases may prefer iterating over the
Chars encoded in a string, or iterating over subslices containing single characters. Neither iteration semantics is an obvious default, so the existing__iter__()method has been deprecated in favor of writing explicit iteration methods for the time being.Code of the form:
var s: String = ...
for c in s:
# ...can be migrated to using the
.char_slices()method:var s: String = ...
for c in s.char_slices():
# ... -
Added
StringSlice.char_length()method, to pair with the existingStringSlice.byte_length()method. -
The
String.__len__()andStringSlice.__len__()methods now return the length of the string in bytes.Previously, these methods were documented to note that they would eventually return a length in Unicode codepoints. They have been changed to guarantee a length in bytes, since the length in bytes is how they are most often used today (for example, as bounds to low-level memory manipulation logic). Additionally, length in codepoints is a more specialized notion of string length that is rarely the correct metric.
Users that know they need the length in codepoints can use the
str.char_length()method, orlen(str.chars()). -
StringSlicenow implementsRepresentable, and that implementation is now used byString.__repr__()andStringLiteral.__repr__(). -
StringSlicenow implementsEqualityComparable.Up until now,
StringSlicehas implemented a more general__eq__()and__ne__()comparison withStringSlicetypes that had arbitrary other origins. However, to satisfyEqualityComparable,StringSlicenow also has narrower comparison methods that support comparing only with anotherStringSlicewith the exact same origin. -
The
String.write()static method has moved to aString()constructor, and is now buffered. Instead of doing:var msg = "my message " + String(x) + " " + String(y) + " " + String(z)Which reallocates the
Stringyou should do:var msg = String("my message", x, y, z, sep=" ")Which is cleaner, and buffers to the stack so the
Stringis allocated only once. -
You can now pass any
Writertowrite_buffered():from utils.write import write_buffered
var string = String("existing string")
write_buffered(string, 42, 42.4, True, sep=" ")This writes to a buffer on the stack before reallocating the
String.
-
-
Collections:
-
A new
LinkedListtype has been added to the standard library. -
Added
Optional.copied()for constructing an ownedOptional[T]from anOptional[Pointer[T]]by copying the pointee value. -
Added
Dict.get_ptr()which returns anOptional[Pointer[V]]. If the given key is present in the dictionary, the optional will hold a pointer to the value. Otherwise, an empty optional is returned. -
Added new
List.extend()overloads takingSIMDandSpan. These enable growing aList[Scalar[..]]by copying the elements of aSIMDvector orSpan[Scalar[..]], simplifying the writing of some optimized SIMD-aware functionality.
-
-
UnsafePointerchanges:-
UnsafePointer'sbitcast()method has now been split intobitcast()for changing the type,origin_cast()for changing mutability,static_alignment_cast()for changing alignment, andaddress_space_cast()for changing the address space. -
UnsafePointeris now parameterized on mutability. Previously,UnsafePointercould only represent mutable pointers.The new
mutparameter can be used to restrict anUnsafePointerto a specific mutability:UnsafePointer[T, mut=False]represents a pointer to an immutableTvalue. This is analogous to aconst *pointer in C++. -
UnsafePointer.address_of()will now infer the origin and mutability of the resulting pointer from the argument. For example:var local = 10
# Constructs a mutable pointer, because `local` is a mutable memory location
var ptr = UnsafePointer.address_of(local)To force the construction of an immutable pointer to an otherwise mutable memory location, use a cast:
var local = 10
# Cast the mutable pointer to be immutable.
var ptr = UnsafePointer.address_of(local).origin_cast[mut=False]() -
The
unsafe_ptr()method on several standard library collection types have been updated to use parametric mutability: they will return anUnsafePointerwhose mutability is inherited from the mutability of theref selfof the receiver at the call site. For example,ptr1will be immutable, whileptr2will be mutable:fn take_lists(read list1: List[Int], mut list2: List[Int]):
# Immutable pointer, since receiver is immutable `read` reference
var ptr1 = list1.unsafe_ptr()
# Mutable pointer, since receiver is mutable `mut` reference
var ptr2 = list2.unsafe_ptr()
-
-
New and updated traits:
-
The
ExplicitlyCopyabletrait has changed to require afn copy(self) -> Selfmethod. Previously, an initializer with the signaturefn __init__(out self, *, other: Self)had been required byExplicitlyCopyable.This improves the "greppability" and at-a-glance readability when a programmer is looking for places in their code that may be performing copies.
-
The
IntLiketrait has been removed and its functionality incorporated into theIndexertrait. This enablesSIMDscalar integer types andUIntto be used for indexing into all of the collection types, as well as optimizing away normalization checks forUIntindexing. -
The
ImplicitlyIntabletrait has been added, allowing types to be implicitly converted to anIntby implementing the__as_int__()method:@value
struct Foo(ImplicitlyIntable):
var i: Int
fn __as_int__(self) -> Int:
return self.i
-
-
You can now cast
SIMDtypes using constructors:var val = Int8(42)
var cast = Int32(val)It also works when passing a scalar type to larger vector size:
var vector = SIMD[DType.int64, 4](cast) # [42, 42, 42, 42]For values other than scalars the size of the
SIMDvector needs to be equal:var float_vector = SIMD[DType.float64, 4](vector)SIMD.cast()still exists to infer the size of new vector:var inferred_size = float_vector.cast[DType.uint64]() # [42, 42, 42, 42] -
Added
SIMD.from_bytes()andSIMD.as_bytes()to convert a list of bytes to a list of scalars and vice versa, accepting the endianness as an argument. Similar to Pythonint.from_bytes()andint.to_bytes()functions. -
You can now use
max()andmin()with variadic number of arguments. -
bit_ceil()has been renamed tonext_power_of_two(), andbit_floor()toprev_power_of_two(). This is to improve readability and clarity in their use. -
Added a new boolean
validateparameter tob64decode(). -
The
b64encode()overload that previously took aListhas been changed to take aSpan. -
Removed the
@implicitdecorator from some standard library initializer methods that perform allocation. This reduces places where Mojo code could implicitly allocate where the user may not be aware.Removed
@implicitfrom:String.__init__(out self, StringSlice)List.__init__(out self, owned *values: T)List.__init__(out self, span: Span[T])
-
Added more aliases in
sys.ffito round out the usual needs for FFI bindings.
Tooling changes
-
mblack(akamojo format) no longer formats non-Mojo files. This prevents unexpected formatting of Python files. -
Full struct signature information is now exposed in the documentation generator, and in the symbol outline and hover markdown via the Mojo Language Server.
-
The
env_get_dtype()function has been added to thesys.param_envmodule. This allows you to get the value of aDTypefrom the param environment.
❌ Removed
-
StringRefhas been removed. UseStringSliceinstead.-
Changed
sys.argv()to return list ofStringSlice. -
Added explicit
Path()constructor fromStringSlice.
-
-
The
Tuple.get[i, T]()method has been removed. Please usetup[i]orrebind[T](tup[i])as needed instead. -
StringableCollectionElementis deprecated. UseWritableCollectionElementinstead, which still allows you to construct aString, but can avoid intermediate allocations. -
The
IntLiketrait has been removed and its functionality incorporated into theIndexertrait. -
The
Type{field1: 42, field2: 17}syntax for direct initializing register passable types has been removed. This was legacy syntax - to upgrade your code, add the@valuedecorator to your struct to get a fieldwise initializer and useType(field1=42, field2 = 17)instead.
🛠️ Fixed
-
The Mojo Kernel for Jupyter Notebooks is working again on nightly releases.
-
The command
mojo debug --vscodenow sets the current working directory properly. -
Issue #3796 - Compiler crash handling
for-elsestatement. -
Issue #3540 - Using named output slot breaks trait conformance
-
Issue #3617 - Can't generate the constructors for a type wrapping
!lit.ref -
The Mojo Language Server doesn't crash anymore on empty
__init__.mojofiles. Issue #3826. -
Issue #3935 - Confusing OOM error when using
Tuple.get()incorrectly. -
Issue #3955 - Unexpected copy behavior with
defarguments in loops -
Issue #3960 - Infinite
forloop