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.clear
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
-
Added
normpath()tostd.os.path, matching Python'sos.path.normpath(). -
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, _]]): ...
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.
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.
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.