Mojo nightly
This version is still a work in progress.
Language enhancements
-
withstatements now no longer copy when passed a reference to a context manager like inwith foo: pass. -
__exit__(self, error: E)now additionally supportsvar selfanddeinit self, similar to the non-error__exit__. -
You can bind a non-
Movablepayload from an rvalue enum or tuple subject with avarcase binding, enablingcase .Some(var value):andcase (var x, var y):without copies. This allowsmatchandif casestatements to work with non-movable and linear types, and reduces copies in general. -
Auto-parameterization now reaches
_holes nested inside other parameterized types, so an unbound parameter at any depth of an argument's type becomes an an implicit parameter of the function:def process(p: Optional[Pointer[Int, _]]): ...
Language changes
-
@explicit_destroy("<message>")on a struct is deprecated and now emits a warning. Give the message on the struct'sDeinitableconformance instead:# Before@explicit_destroy("call `close()` instead")struct File(not Deinitable):...@explicit_destroy("use `deinit_with()` for non-Deinitable elements")struct Box[T: Movable](Deinitable where conforms_to(T, Deinitable)):...# Afterstruct File(not Deinitable else "call `close()` instead"):...struct Box[T: Movable](Deinitable where conforms_to(T, Deinitable) else ("use `deinit_with()` for non-Deinitable elements"),):...The message on a conditional
Deinitable where <condition> else "<message>"conformance is now reported when a value is abandoned for parameters that don't satisfy the condition. Previously, only an always-false conformance's message was reported. -
Precompiled packages now no longer leak names and provide the same surface as the same packages compiled from source. This may break your code (especially from
std):from std.os import rmdirdef main():std.os.rmdir(...) # This no longer works - use rmdir, or import std.os.
Library stabilizations
List.insertList.clearPointer.__init__(to=)Pointer.__eq__Pointer.__ne__Pointer.unsafe_bitcast
Library performance improvements
-
Reduced the size of
Optional[T]to the size ofTwhenTis one of the following types, so code that stores them in anOptionaluses less memory:AllocationLayoutListManagedAllocationSpanStringStringSpanThinAllocation
Don't depend on this size. It relies on bit patterns that each type's current representation never uses, and that representation could change in the future.
Library changes
-
An optional mutable pointer now implicitly converts to an optional immutable pointer, as
Pointerdoes. -
Added
normpath()tostd.os.path, matching Python'sos.path.normpath(). -
Added a builtin
filter(), which takes an iterable and a predicate closure and yields the elements the predicate accepts:filter(items, lambda (x: Int) -> Bool: x > 0). -
take_while()anddrop_while()instd.itertoolsnow take the predicate as an argument instead of a compile-time parameter, so it can be a closure that captures values. Writetake_while(items, pred)instead oftake_while[pred](items). -
Span.binary_search_by()no longer takes the comparator as a compile-time parameter. Pass it as an argument,span.binary_search_by(cmp), which also lets it capture the value being searched for. -
QuickBench.run()instd.benchmarknow takes a single closure with no arguments in place of its eleven overloads for functions of 0 to 10 arguments. Capture the inputs instead of passing them separately:qb.run(lambda () {x} -> Float32: exp(x), bench_id=BenchId("exp")). -
ord()andCodepoint.ord()on a runtime string (StringSpan,String) now raise anErrorinstead of aborting when the string is empty. They also raise when the string holds more than one codepoint; previously they silently returned the first codepoint unless assertions were enabled. Callers must now handle the error withtryor araisesfunction. On a string literal, both never raise, and a literal that isn't exactly one codepoint is a compile-time error.var text = String("🔥")var codepoint = ord(text) # 128293; raises if `text` isn't one codepointcomptime letter = ord("a") # 97; never raises -
Tupleelement types no longer need to beMovable. ATupleis nowMovableonly when all of its elements are.Tuplehas a newinit_withinitializer, which constructs each element in place from a closure parameterized on the element index:comptime T = Tuple[Pinned, Pinned] # `Pinned` is not `Movable`.var t = T(init_with=lambda [i: Int]() -> T.Ts[i]: Pinned(i * 10)) -
Layoutnow names its element countlength, matchingSpanandList. Construct one withLayout[T](length=n)and read the count back withlen(layout):LayoutandManagedAllocationnow conform toSized. TheLayout(count=)initializer and theLayout.count()method are deprecated.var allocation = alloc(Layout[Int32](length=4))for i in range(len(allocation)):allocation.unsafe_ptr().unsafe_offset(i).unsafe_write(Int32(i))dealloc(allocation^) -
Raising an integral
SIMDvalue (includingInt) or aSIMDLengthto a negative power now aborts at run time instead of silently returning0. Use a floating point base instead. -
Raising an
IntLiteralto a negativeIntLiteralpower now computes the exact result as a float literal, the reciprocal of the positive power, instead of evaluating to0. The result is a float literal even when the base is1or-1, sovar x = (-1)**-3is now aFloat64holding-1.0. Zero to a negative power evaluates tonan.var a = 2**-1 # 0.5, same as 1 / 2var b = Float64(2) ** -1 # 0.5var n = 2var c = n**-1 # aborts at run time -
Added
FileDescriptortostd.io, an owning wrapper aroundRawFileDescriptor. It is a linear type: close it explicitly withfd^.close(), which raises if the close fails. It is movable but not copyable, andOptional[FileDescriptor]is the size of a single descriptor.RawFileDescriptorgains a raisingclose()method.FileDescriptor(copy_borrowed=)duplicates a descriptor with close-on-exec set, so child processes don't inherit the copy. -
RawFileDescriptor.read_bytes(),RawFileDescriptor.fchdir(),RawFileDescriptor.close(),FileDescriptor.close(), andFileDescriptor(copy_borrowed=)now raiseIOError, so callers can match on the error'skind(). Code in a plainraisesfunction still compiles unchanged. -
Added
BorrowedFileDescriptortostd.io, a copyable, non-owning view of aFileDescriptorthat carries the owner's origin, so it can be passed around without closing the descriptor or outliving its owner. -
ArcPointerelement types no longer need to beDeinitable. Destroy anArcPointerof a non-Deinitabletype with the newdeinit_with()method. -
Added an
OwnedPointer(init_with=)initializer that constructs the value in place, so the element type doesn't need to beMovable, and anOwnedPointer.deinit_with()method that destroys anOwnedPointerwhose element type isn'tDeinitable. The initializers that copied a value into the allocation are now deprecated. -
FileHandlenow owns its descriptor through aFileDescriptorand always refers to an open file. It is no longerDefaultable, andclose()consumes the handle (f^.close()) instead of leaving it in an invalid state. It still raises if the close fails. UseOptional[FileHandle], which is the same size asFileHandle, for a file that may not be open.NamedTemporaryFilefollows the same rules: it always holds an open file,close()consumes it, andOptional[NamedTemporaryFile]is the same size asNamedTemporaryFile. -
The
OptionalPointer,OptionalMutPointer, andOptionalImmPointeraliases are deprecated. WriteOptional[Pointer[T, origin]],Optional[MutPointer[T, origin]], orOptional[ImmPointer[T, origin]]instead. An_origin nested inside theOptionalmakes the function generic over it, as it did with the aliases:# Beforedef fill(buf: OptionalMutPointer[Byte, _]): ...# Afterdef fill(buf: Optional[MutPointer[Byte, _]]): ... -
The
StringSlice,ImmStringSpan, andImmStringSlicealiases are deprecated. UseStringSpaninstead.StringSpanis always immutable, so theImmvariants are redundant. -
Spannow conforms toEquatablewhen its element type does. -
Optional.value(),Optional.unsafe_value(), andOptional.__getitem__()now return a reference with an interior origin of theOptional. Reassigning theOptional, or calling amut selfmethod on it invalidates outstanding references to its value. Reading through such a reference afterward used to compile and read a destroyed value; it is now a compile error:var opt = Optional(5)ref i = opt.value()opt = Noneprint(i) # error: use of invalidated interior reference 'opt["value"]'
GPU programming
-
Added the
apple-m6andapple-m6-metal4accelerator targets, andCompilationTarget.is_apple_m6()tostd.sys. Apple M6 GPUs are now detected automatically, so you no longer need to pass--target-accelerator=apple-m5on M6 hardware. -
Bool,Scalar(includingInt),String,StringSpan, andStringLiteralnow conform toConvertibleToPython, so they can be passed to generic code bounded on that trait. The dedicatedPythonObjectconstructors for these types are removed; implicit conversion still works through the singleConvertibleToPythonconstructor.ConvertibleToPythongains an associatedConversionToPythonErrorType(defaultNever), so conversions that cannot fail, such asBoolandScalar, stay non-raising, whileStringconversions keep raisingError. This is a breaking change. If a conversion is non-raising, theraiseseffect can be removed from theConvertibleToPythonconstructor. If a conversion is raising, an error type must be assigned toConversionToPythonErrorType.
Tooling changes
-
mojo buildandmojo runcan now report what elaboration produced, to show which compile-time code makes a compile slow.--elaboration-statslists eachcomptime forloop with its iteration count and the operations its unrolled iterations produced. It also lists the calls that compile-time evaluation made to the interpreter, summed by function and by call site, with their cache hits and the CPU time spent interpreting. The report has one part for each pipeline that elaborated: the host and each accelerator target. This option is hidden; use--help-hiddento list it.Like the timing reports, the report prints as text to stderr by default.
--timing-jsonprints it as JSON instead, under anelaborationkey, and--timing-filewrites it to a file instead of stderr. If the compilation hits the cache, elaboration is skipped and nothing is reported. Clear compilation cache or pointMODULAR_CACHE_DIRat an empty directory to get a full report.
Removed
-
Legacy closures are removed. The
capturingfunction effect and the@__parameter(and@parameter),@__copy_capture, and@__move_capturedecorators are now errors. Declare a nested function's captures in a capture list instead, and pass the closure as a value:def apply[F: def(Int) -> Int](f: F, x: Int) -> Int:return f(x)def main():var offset = 10def add(x: Int) {var offset} -> Int: # was @__copy_capture(offset)return x + offsetprint(apply(add, 1))A function passed as a compile-time parameter must now be
thin, for example[f: def(Int) thin -> Int]. -
CompiledFunctionInfono longer hasnum_captures,capture_sizes, orpopulatemembers. Kernels can no longer capture implicitly, so these were always empty. -
The AMD-only intrinsics
readfirstlane(),sendmsg(), andimplicitarg_ptr()moved fromstd.sys.intrinsicstomax.gpu.intrinsics, next to the other vendor-specific GPU intrinsics. Import them from there instead.std.sys.intrinsics.ballot()is removed; usemax.gpu.primitives.warp.vote(), which works on every GPU vendor. -
The
PowableandCeilDivableRaisingtraits are removed. A type that defines__pow__()still supports the**operator without conforming to a trait, andpow()now takesSIMDvalues only. Nothing conformed toCeilDivableRaising, so the raisingceildiv()overload is removed too. -
Removed APIs that were deprecated in Mojo 1.1 or earlier. Use the replacement in each case:
-
The
UnsafePointeralias and thestd.memory.unsafe_pointermodule that defined it. UsePointer. -
The
Pointermethodsload(),store(),strided_load(),strided_store(),gather(),scatter(),free(),bitcast(),address_space_cast(), andtake_pointee(). Use theirunsafe_-prefixed spellings, such asunsafe_load(). -
Pointer.mut_cast(). Spell the mutability in the pointer type (ImmPointerorMutPointer), or useunsafe_mut_cast(). -
Subtracting an integer from a
Pointerand the+=and-=operators. Useunsafe_offset(). Adding an integer and positional indexing such asptr[i]remain deprecated. -
memmove(). Useunsafe_memmove(). -
The
alloc[T](count)overload. Usealloc(Layout[T](length=count)), which returns anAllocation, orunsafe_alloc[T](count)for a raw pointer. -
is_trivially_movable(),is_trivially_copyable(), andis_trivially_deletable(). UseIsTriviallyMovable[T],IsTriviallyCopyable[T], andIsTriviallyDeinitable[T]fromstd.traits. -
The
CStringSlicealias andas_c_string_slice()onString,StringSlice, andStringLiteral. UseCStringSpanandas_c_string_span(). -
unsafe_ptr()onArcPointer,OwnedPointer,CStringSpan, andStringLiteral. Useptr(). -
String.capacity()andString.reserve(). Usecapacity_bytes()andreserve_bytes(). -
Tuple.element_typesandVariadicPack.element_types. UseTs. -
The
AnyTypeandDeinitablealiases instd.builtin.anytype, and theMovable,Copyable, andImplicitlyCopyablealiases instd.builtin.value. These traits live instd.traitsand are still exported from the prelude.
-
Fixed
-
SIMD.slice()no longer passesllvm.vector.extractan offset that is not a multiple of the output width, which LLVM rejects. A wide slice at such an offset, likeslice[16, offset=8]()on a 32-element vector, now takes the element-wise path, and aligned slices narrower than the target's native vector width, such as the halvessplit()returns for small vectors, now use the intrinsic. -
Fixed rejection of negative integer and floating-point literals in
matchpatterns. -
A
comptime if conforms_to(T, Deinitable)guard now correctly refinesTand deinits it after its last use.