This is a list of UNRELEASED changes for the Mojo language and tools.
When we cut a release, these notes move to changelog-released.md
and that's
what we publish.
[//]: # Here's the template to use when starting a new batch of notes: [//]: ## UNRELEASED [//]: ### ✨ Highlights [//]: ### Language changes [//]: ### Standard library changes [//]: ### Tooling changes [//]: ### ❌ Removed [//]: ### 🛠️ Fixed
-
Initializers are now treated as static methods that return an instance of
Self
. This means theout
argument of an initializer is now treated the same as a any other function result orout
argument. This is generally invisible, except that patterns likeinstance.__init__()
andx.__copyinit__(y)
no longer work. Simply replace them withinstance = T()
andx = y
respectively. -
The legacy
borrowed
/inout
keywords and-> T as foo
syntax now generate a warning. Please move toread
/mut
/out
argument syntax instead. -
The
@value
decorator now additionally derives an implementation of theExplicitlyCopyable
trait. This will ease the transition to explicit copyablility 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=6
This 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 free floating functions for constructing different types have been deprecated for actual constructors:
before after ------------------ int() Int() str() String() bool() Bool() float() Float64()
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 Case
andMatch Whole Word
search and replace forint(
toInt(
etc. -
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. -
UnsafePointer
is now parameterized on mutability. Previously,UnsafePointer
could only represent mutable pointers.The new
mut
parameter can be used to restrict anUnsafePointer
to a specific mutability:UnsafePointer[T, mut=False]
represents a pointer to an immutableT
value. 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 anUnsafePointer
whose mutability is inherited from the mutability of theref self
of the receiver at the call site. For example,ptr1
will be immutable, whileptr2
will 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()
-
-
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 takingSIMD
andSpan
. These enable growing aList[Scalar[..]]
by copying the elements of aSIMD
vector orSpan[Scalar[..]]
, simplifying the writing of some optimized SIMD-aware functionality. -
Added
Char
, for representing and storing single Unicode characters.Char
implementsCollectionElement
,EqualityComparable
,Intable
, andStringable
.- Added
String
constructor fromChar
Char
can be converted toUInt32
viaChar.to_u32()
.Char
provides methods for categorizing character types, including:Char.is_ascii()
,Char.is_posix_space()
,Char.is_python_space()
,Char.is_ascii_digit()
,Char.is_ascii_upper()
,Char.is_ascii_lower()
,Char.is_ascii_printable()
.
-
chr(Int)
will now abort if given a codepoint value that is not a validChar
. -
Added
StringSlice.from_utf()
factor method, for validated construction of aStringSlice
from 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 overChar
s. 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
StringSlice
instead ofString
. This generalizes them to be used for any appropriately encoded string in memory, without requiring that the string be heap allocated.atol()
atof()
ord()
ascii()
b64encode()
- Additionally, the
b64encode()
overload that previously tookList
has been changed to take aSpan
.
- Additionally, the
b64decode()
b16encode()
b16decode()
-
Added new
String.chars()
andString.char_slices()
iterator methods, and deprecated the existingString.__iter__()
method.Different use-cases may prefer iterating over the
Char
s 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(): # ...
-
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())
. -
Various functionality has moved from
String
andStringRef
to the more generalStringSlice
type.StringSlice
now implementsRepresentable
, and that implementation is now used byString.__repr__()
andStringRef.__repr__()
.
-
StringSlice
now implementsEqualityComparable
.Up until now,
StringSlice
has implemented a more general__eq__
and__ne__
comparision withStringSlice
types that had arbitrary other origins. However, to satisfyEqualityComparable
,StringSlice
now also has narrower comparison methods that support comparing only withStringSlice
's with the exact same origin. -
Added
StringSlice.char_length()
method, to pair with the existingStringSlice.byte_length()
method.In a future version of Mojo,
StringSlice.__len__()
may be changed to return the length in bytes, matching the convention of string length methods in languages like C++ and Rust. Callers that know they need the length in Unicode codepoints should update to callingStringSlice.char_length()
instead. -
Removed
@implicit
decorator 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.Remove
@implicit
from:String.__init__(out self, StringRef)
String.__init__(out self, StringSlice)
List.__init__(out self, owned *values: T)
List.__init__(out self, span: Span[T])
-
The
ExplicitlyCopyable
trait has changed to require afn copy(self) -> Self
method. 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
-
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. -
The
Indexer
andIntLike
traits which were previously both used for indexing have been combined. This enables SIMD scalar integer types and UInt to be used for indexing into all of the collection types, as well as optimizing away normalization checks for UInt indexing. -
The
ImplicitlyIntable
trait has been added, allowing types to be implicitly converted to anInt
by implementing the__as_int__
method:@value struct Foo(ImplicitlyIntable): var i: Int fn __as_int__(self) -> Int: return self.i
-
You can now cast SIMD types 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 SIMD vector 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]
-
You can now use
max()
andmin()
with variadic number of arguments. -
A new
LinkedList
type has been added to the standard library. -
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
String
you should do:var msg = String("my message", x, y, z, sep=" ")
Which is cleaner, and buffers to the stack so the
String
is allocated only once. -
You can now pass any
Writer
towrite_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
. -
The
__disable_del x
operation has been tightened up to treat all fields of 'x' as consumed by the point of the del, so it should be used after all the subfields are transferred or otherwise consumed (e.g. at the end of the function) not before uses of the fields.
-
mblack (aka
mojo 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.
StringRef
is being deprecated. UseStringSlice
instead.- Changed
sys.argv()
to return list ofStringSlice
. - Added
Path
explicit constructor fromStringSlice
. - removed
StringRef.startswith()
andStringRef.endswith()
- removed
StringRef.strip()
- Changed
- The
Tuple.get[i, T]()
method has been removed. Please usetup[i]
orrebind[T](tup[i])
as needed instead. StringableCollectionElement
is deprecated, useWritableCollectionElement
instead which still allows you to construct aString
, but can avoid intermediary allocations.
-
The Mojo Kernel for Jupyter Notebooks is working again on nightly releases.
-
The command
mojo debug --vscode
now sets the current working directory properly. -
Issue #3796 - Compiler crash handling for-else statement.
-
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.mojo files. Issue #3826.
-
Issue #3935 - Confusing OOM error when using Tuple.get incorrectly.
-
Issue #3955 - Unexpected copy behaviour with
def
arguments in loops -
Issue #3960 - Infinite for loop