Mojo nightly
This version is still a work in progress.
Highlights
- Code that performs many implicit conversions, most visibly large collection literals, compiles faster: the compiler no longer runs parameter inference on constructors that cannot be used for an implicit conversion in the first place. Files that are mostly data, such as the standard library's Unicode lookup tables, compile about 1.3x faster.
Language enhancements
-
Unknown declaration errors now suggest a unique near-miss spelling from the enclosing scopes (for example
coun→count), with a replace-token fixit. -
Mojo now supports contextually inferred member references: a leading-dot form such as
.redor.float64resolves against the expected type of the expression, so you can omit a redundant type name when context already supplies it. Static methods, parametric static methods, parentheses, attribute chains, and typed collection literals all work:struct Color(ImplicitlyCopyable):comptime red = Color(...)comptime green = Color(...)@staticmethoddef hsb_to_rgb(h: Int, s: Int, b: Int) -> Color:return Color(...)def opacity(self, amount: Float64) -> Color:return Color(...)def __init__(out self, ...):def takes_color(c: Color):def takes_colors(colors: List[Color]):takes_color(.green)takes_color(.hsb_to_rgb(120, 100, 50))takes_color(.red.opacity(0.5))var x: Color = .redtakes_colors([.red, .green])Without a contextual type,
.memberis an error. -
A
thinfunction type can now carry trailingwhereclauses, constraining the parameters it declares. This lets a generic algorithm state what it promises the function it is handed, instead of leaving the constraint to be restated at every binding site.comptime Kernel = def[w: Int](Int) thin -> None where (w > 0, "width must be positive")def apply[F: Kernel](x: Int):F[4](x) # okF[0](x) # error: violated constraintThe clause binds to the innermost function type, so a declaration-level
wherethat follows a function-type result needs that result parenthesized:def make[n: Int]() -> (def() thin -> None) where n > 0: ...
Language changes
-
Binding a constrained function to a function type that declares no matching
whereclause is now an error, instead of silently dropping the constraint. Declare the obligation on the function type (now that athinfunction type can carry a trailingwhereclause) or bind a function that does not require it. Passing an unconstrained function where a constrained type is expected is still allowed and still free. -
Renamed the
@parameterdecorator on parametric closures to@__parameter. The deprecated@parameter if/@parameter forforms are unchanged; prefercomptime if/comptime forfor compile-time control flow. -
The module & package system:
-
Directories may now have "namespace" semantics; a single directory name may resolve across distinct locations on disk which share that name.
# .# ├── one# │ └── foo# │ └── bar.mojo# └── two# └── foo# └── baz.mojo## Compiles with -Ione -Itwoimport foo.barimport foo.baz -
Importing functions with the same name from different modules, combining them into one overload set, is now an error, following a period of deprecation.
-
Intra-package accesses without explicit
imports are now an error, following a period of deprecation.
-
-
Use of the
readargument convention is now a hard error, following a period of deprecation; useimminstead.
Library stabilizations
- String
def __init__(out self):def __init__(out self, *, capacity_bytes: Int):def reserve_bytes(mut self, new_capacity_bytes: Int, /):
Library performance improvements
- Files with many t-string (
t"...") literals compile faster: the compile-time step that encodes each literal's format string (part of elaboration, not the whole compile) is about 7x faster. The effect on total build time scales with how many t-string literals a file has.
Library changes
-
Coordhas a newreplace[at](value)method that returns aCoordwith the element atatswapped forvalue, keeping the other elements' types. A statically known element (ComptimeInt) has no runtime storage to assign into, so overwriting one with a runtime value yields aCoordof a different type rather than mutating in place. Unlikemake_dynamic(), which converts every element to aScalar, the untouched dimensions keep their compile-time values:var c = Coord(ComptimeInt[3](), ComptimeInt[4]())var moved = c.replace[1](Int64(7)) # Coord(ComptimeInt[3](), Int64(7)) -
Python functions exposed through
PythonModuleBuilder.def_function(),PythonTypeBuilder.def_method(), andPythonTypeBuilder.def_staticmethod()no longer have a library-imposed limit on positional arguments. -
List.extendandList.resizenow grow geometrically, so repeatedly extending or resizing by a small increment is no longer quadratic. As a resultcapacity()can report more than was asked for.reserveis unchanged and still allocates exactly what you request. -
CompilationTargethas a newis_arm()predicate, andis_x86()now reports the architecture rather than SSE4 availability. Both read the architecture from the target triple, so they no longer vary with--target-cpu. This changesis_x86()on x86 targets without SSE4.1 — most visibly the baselinex86-64CPU, where it used to returnFalse. Usehas_sse4(),has_avx2(), and friends to gate code on a specific instruction set. -
CompilationTargetcan now describe RISC-V targets:is_riscv(),is_rv32(), andis_rv64()report the architecture, andhas_riscv_extension["m"]()reports a single ISA extension by its lowercase LLVM name. An extension implied by another counts as present, so a target built withdalso reportsf. It is alwaysFalseon a non-RISC-V target, and rejects an uppercase name at compile time.Selecting a RISC-V CPU or ISA string now resolves the extensions it implies, so
--target-cpu=sifive-e31and--march=rv32imacboth reportm,a, andc. Previously either one reported only the base integer ISA. -
Bencher.bench_function()now takes a raising closure. -
The zero-argument
Bench.bench_function()overload now takes a raising closure as a runtime argument. The compile-time parameter formbench_function[fn]()for a raising zero-argument body has been removed. -
The remaining compile-time parameter forms of
Bench.bench_function()andBencher.iter()have been removed. Pass the closure as a runtime argument. -
Bencher.iter_preproc()now takes its closures as runtime arguments instead of compile-time parameters, along with an explicit state value that is passed mutably to both: the preprocessing function prepares the state before each timed call of the benchmarked function, so state no longer has to be shuttled through mutable captures. -
Bencher.bench_with_input()now takes its benchmark closure as a runtime argument. Its register-passable overload accepts both non-raising and raising closures. -
Bencher.iter_custom()now only takes its closure as a runtime argument. The compile-time parameter form has been removed. -
std.python.numpynow handles multi-dimensional NumPy arrays, not just 1-D:-
copy_to_numpy_tensor()copies aSpaninto a new NumPy array of a given shape. The shape is aCoord, so extents may be compile-time (Idx[N]) or runtime (Int) in any mix. -
from_numpy_tensor()borrows an N-D C-contiguous array as aNumPyView, which holds the buffer and its shape together and indexes asview[i, j].
from std.python.numpy import copy_to_numpy_tensor, from_numpy_tensorfrom std.utils.coord import Coord, Idxvar values: List[Float64] = [0, 1, 2, 3, 4, 5]var arr = copy_to_numpy_tensor(values, Coord(Idx[2], Idx[3]))var view = from_numpy_tensor[DType.float64, 2](arr)var value = view[1, 2]The existing 1-D
copy_to_numpy_array()andfrom_numpy_array()are unchanged. -
-
Arraynow conforms toComparablewhen its element type does, adding<,<=,>, and>=. The ordering is lexicographic: the first differing element decides, so[1, 5] < [2, 3]isTrue. -
StringDictnow conforms toWritablewhen its value type isWritable, matching the existing behavior ofDict. This lets youprint()aStringDictor convert it to aString. -
The
charsargument ofstrip(),lstrip()andrstrip()onStringSpan,StringandStringLiteralis now anImmStringSpan, so a mutable string is accepted aschars, including the string being stripped (s.strip(s)). -
StringDict.__getitem__()now accepts aStringSpan, so you can index aStringDictwith a borrowed string view without first allocating aStringjust to perform the lookup. -
Renamed the variadic type-list parameter on
TupleandVariadicPacktoTs, standardizing the naming convention used across the standard library. The old name,element_types, remains as a deprecated alias. -
Added experimental
DType.float6_e2m3fnandDType.float6_e3m2fn, the two 6-bit encodings from the Open Compute microscaling specification. Both are finite-only, so neither has an inf nor a NaN encoding.These are experimental storage formats for packed weights rather than general-purpose numeric types, and standard library support is deliberately partial. As with the existing
DType.float4_e2m1fn, they are excluded fromis_numeric(), arithmetic is not implemented, and converting to or from another floating-point type is unsupported on every target, so values cannot be printed either. -
Arraynow conforms toDefaultablewhen its typeTis alsoDefaultable. -
Arraynow supports concatenation with theconcatmethod when its typeTisMovable. Both operands are consumed and their elements are moved into the new array, whose length is the sum of the operands' lengths. -
Arraynow supports repetition with therepeatmethod when its typeTisCopyable. The array is consumed: its elements are copied into all but the last repetition and moved into the last one. -
Deprecated
is_trivially_movable(),is_trivially_copyable(), andis_trivially_deletable()instd.memoryin favor ofIsTriviallyMovable[T],IsTriviallyCopyable[T], andIsTriviallyDeinitable[T]instd.traits. The replacements arecomptimepredicates rather than functions, so drop the call parens at use sites, for exampleIsTriviallyCopyable[T]instead ofis_trivially_copyable[T](). -
Renamed
UnsafeMaybeUninittoMaybeUninit. It conforms toMovable,Copyable/ImplicitlyCopyable, andDeinitableonly when the contained type's own move, copy, or implicit deinitializer is trivial, since moving, copying, or destroying aMaybeUninitonly touches its raw bits, never the contained value's own lifecycle methods. Gating conformance this way turns what would otherwise be silent memory-safety bugs into compile-time errors. -
Added
deinit(), for anyDeinitabletype, to explicitly extend a value's lifetime up to a specific point and run its deinitializer there. -
Atomicis now parameterized on a value typeTinstead of aDType. Update call sites fromAtomic[DType.float32]toAtomic[Float32]. The atomic operations (load(),store(),fetch_add(),compare_exchange(), and so on) still only supportScalartypes. -
Added
Pointer[T].unsafe_write(def() -> T), which initializes the pointee with the value returned by a closure, constructing it directly in place rather than moving an already-constructed value there. Unlikeunsafe_write(var T), this does not require the pointee type to beMovable. -
Array[T, N]has a newfill_with=constructor that calls a function with each index in[0, N)and writes its result into that position, replacing theArray(uninitialized=True)plus manual fill-loop idiom. -
List's element type is now bounded byAnyTypeinstead ofMovable. -
Listhas a newfill_with=constructor that calls a function with each index in[0, length)and writes its result into that position, without requiring the element type to beMovable. -
Added
write()toMaybeUninitandPointer, as a safe counterpart tounsafe_write()for types that are trivially deinitializable (for exampleInt). Since a trivial deinitializer is a no-op, overwriting a live value throughwrite()can't leak a resource, so it's callable without first destroying the previous value. Prefer it overunsafe_write()whenever the pointee type is trivially deinitializable. -
Pointer.mut_castis now deprecated. Developers should prefer using explicit mutabilites at the callsite viaMutPointerorImmPointer. If mut casting is needed (it should try to be avoided) - you can useunsafe_mut_cast. -
Added
ptr()toStringLiteral,CStringSlice,ArcPointer, andOwnedPointer, deprecating theirunsafe_ptr()methods. These types always hold a valid, live value, so a pointer to it is never unsafe. -
The following APIs have been migrated to unified closures:
sort,debug_assert,Span.apply. -
Uncaught exceptions now print to
stderr, notstdout.
GPU programming
-
The
max.gpupackage now mirrors everything reachable fromstd.gpu, making it a complete entry point for accelerator programming. Prefermax.gpu, which is becoming the only public source for these utilities. -
The
std.gpupackage is now private, asstd._gpu.max.gpuis the only public source for the GPU primitives, and its API reference is the only published one;/docs/std/gpu/...pages redirect to/api/mojo/max/gpu/.... Replacefrom std.gpu import ...withfrom max.gpu import ...; a failedstd.gpuimport carries a note pointing at the new home.
Tooling changes
mojo docnow reports the condition of a conditional trait conformance, and the generated API docs show it alongside the trait. Previously the condition was dropped, making a conditional conformance indistinguishable from an unconditional one. Also fixed rendering of somewhereclauses.
Removed
This release completes the removal of APIs deprecated during the v1.0 cycle.
-
Implicit variable declaration now produces an error instead of a warning. The walrus operator also only overwrite existing values, not implicitly declare new ones.
-
Removed the temporary
InlineArrayalias forArray, including its re-exports fromstd.collectionsand the prelude. UseArraydirectly. -
Removed redundant
Intoverloads across the standard library:count_leading_zeros(),count_trailing_zeros(),bit_reverse(),byte_swap(),pop_count(),log2_ceil(),next_power_of_two(), andprev_power_of_two()instd.bit;broadcast()instd.gpu.primitives(including theUIntoverload);readfirstlane()instd.sys; andumod()instd.math.uutils.Intis an alias forScalar[DType.int], so the genericSIMDoverloads already acceptIntarguments and returnInt; call sites need no changes. As a side effect,broadcast()onInt/UIntvalues now shuffles the full 64-bit value instead of silently truncating it to 32 bits. -
Removed the
Intoverloads ofrotate_bits_left()androtate_bits_right()instd.bit. TheSIMDoverloads now accept any integral element type instead of only unsigned ones — rotation is a pure bit-pattern operation, so signed and unsigned rotate identically — and therefore handleIntarguments directly. Call sites need no changes. -
Removed the
std.gpu.profilermodule and itsProfileBlockcontext manager. It timed host wall-clock, not GPU work, and reported the elapsed time with the operands reversed. Time a block of host code withperf_counter_ns()directly, and use a GPU profiler such as Nsight Systems orrocproffor device timings. -
Removed
memcmpand itsstd.memoryre-export. Useunsafe_memcmpinstead. -
Removed
String.set_byte_length(), an internal helper that set the length field without reserving capacity. -
Removed the
validateparameter fromb64decode(), which now always validates. Passingvalidate=Falsedid not skip any work on valid input; it only turned characters outside the base64 alphabet into silently corrupt output bytes. Drop[validate=True]from existing calls; calls that relied on the default now raise instead of returning garbage. -
Removed the origin aliases left over from the
ImmuttoImmandExternaltoUntrackedrenames. Use the surviving spelling in each case:ImmOriginforImmutOrigin,ImmUnsafeAnyOriginforImmutUnsafeAnyOrigin,ImmStaticOriginforStaticConstantOrigin,UntrackedOriginforExternalOrigin,MutUntrackedOriginforMutExternalOrigin, andImmUntrackedOriginfor bothImmutUntrackedOriginandImmutExternalOrigin. -
Removed the redundant
Intoverloads ofsqrt(),fma(),align_down(),align_up(),clamp(), andiota()fromstd.math.Intis an alias forScalar[DType.int], so the genericSIMDoverloads already acceptIntarguments and returnInt; call sites need no changes. -
Removed the pre-unification pointer aliases
MutUnsafePointer,ImmUnsafePointer,ImmutUnsafePointer,ImmutOpaquePointer,ImmutPointer, andOptionalUnsafePointer. UseMutPointer,ImmPointer,ImmOpaquePointer, andOptionalPointerinstead.UnsafePointeritself remains available, but is deprecated in favor ofPointer. -
Removed the raw memory functions superseded by their
unsafe_-prefixed spellings:memcpy,memset,memset_zero,uninit_move_n,uninit_copy_n, anddestroy_n. Useunsafe_memcpy,unsafe_memset,unsafe_memset_zero,unsafe_uninit_move_n,unsafe_uninit_copy_n, andunsafe_destroy_ninstead. -
Removed the
sizealiases left from thesizetolengthrename:SIMD.size,Array.size,TypeList.size, and theSIMDSizealias forSIMDLength. UselengthandSIMDLength. -
Removed the
as_immutable()andget_immutable()methods onPointer,Span, andStringSpan. Useas_imm(). -
Removed the
ImmutSpanalias. UseImmSpan. -
Removed
String.as_string_slice(). Construct aStringSpanfrom the string instead:StringSpan(my_string). -
Removed the
ImplicitlyDestructibleandImplicitlyDeletablealiases. UseDeinitable. -
Removed the deprecated ownership-transfer methods:
List.steal_data()andOwnedPointer.steal_data()are nowunsafe_take_allocation(),OwnedPointer.take()isinto_inner(), andVariant.take()andVariant.unsafe_take()areunwrap()andunsafe_unwrap(). -
Removed the
Pointermethods superseded by theirunsafe_-prefixed spellings:as_noalias_ptr(),destroy_pointee(),destroy_pointee_with(),init_pointee_move(),init_pointee_copy(), andinit_pointee_move_from(). Useunsafe_as_noalias(),unsafe_deinit_pointee(),unsafe_deinit_pointee_with(),unsafe_write(), andunsafe_write_move_from(). ThePointer.typealias forPointer.Tis gone as well. -
Removed the
ConditionalTypetype function and thestd.utils.type_functionsmodule. Use the ternary expressionT if cond else U. -
Removed
trait_downcast(). Constrain on the trait instead, withconforms_to(type_of(src), Trait)in awhereclause or acomptime assert. -
Removed the parametric
benchmark.run[func]()overloads. Pass the function as an argument torun(f)instead, which accepts a unified closure. -
Removed
AnyCoroutine,CoroutineandRaisingCoroutinefrom the prelude, and made the module that defines them private. Mojo's async support is unfinished, and these types being globally visible led people to build on an API that carries no stability guarantees.async defis unaffected: the compiler still synthesizes these types for you, so they continue to appear in inferred types and diagnostics. There is no supported way to name them directly. -
Removed the async task API from the public
std.runtime.asyncrtmodule, which is now private.initialize_runtime()andparallelism_level()are unaffected and have moved up to thestd.runtimepackage, so import them fromstd.runtimeinstead ofstd.runtime.asyncrt. -
Removed support for
.mojopkgfiles after a period of deprecation. Use.mojocfiles instead.
Fixed
-
unsafe_uninit_move_n()andunsafe_uninit_copy_n()withoverlapping=Truenow handle an overlap in either direction whenTis not trivially movable or copyable. They always walked front-to-back, so adestabovesrcoverwrote elements that had not been moved or read yet. -
SIMD.__init__(py=...)now reads unsigned dtypes through the unsigned CPython entry point (PyLong_AsSize_t). Constructing an unsignedSIMDfrom a Python int in[2**63, 2**64)no longer overflows, and a negative Python int now raises instead of silently wrapping to the maximum value. -
A union whose widest member is a
SIMD[DType.bool, N]withN > 1, such asOptional[SIMD[DType.bool, 2]], now compiles. -
A
whereclause naming a type that an enclosingwhereclause constrained to a tighter trait can now be proven. Calling a method declaredwhere Ts.contains[T]()with such aTfailed withlacking evidence to prove correctness, even thoughTwas plainly inTs. -
hash()on a floating-pointSIMDvalue now normalizes the sign of zero, sohash(-0.0) == hash(0.0). Hashing the raw bit pattern broke theHashablecontract that equal values hash equally: aDictorSetcould hold both-0.0and0.0as separate keys even though they compare equal, and a lookup could then return a value stored under the other key. -
mojo buildcan cross-compile to RISC-V again. Emitting LLVM IR, assembly, or an object for ariscv32orriscv64triple failed withtarget '...' is not supported by this build. -
mojo build --print-supported-targetsno longer lists targets that the compiler cannot generate code for. -
mojo build --emit asmand--emit llvmnow always write the offload kernel files next to the host output file. Building a kernel that an earlier build had already compiled could write them into the earlier build's output directory, or skip them with no diagnostic. -
Parametric
raisesnow accepts any primary expression as the thrown type in a function signature, matching the syntax positions where types otherwise appear. This most notably fixesraises Self.SomeAssocTypeon trait and struct methods, which would previously fail with an error. The parenthesized workaround (raises (Self.DriveErrorType)) is no longer required. -
An integer
range()with a step of zero is now always empty. It previously used to be an infinite loop - iterating forever at runtime, and hanging the compiler at comptime. -
A strided
range()no longer iterates forever when the element after the last one falls outside the element type, as inrange(UInt8(250), UInt8(255), UInt8(2)). The cursor used to wrap past the type's limit and land back inside the range, so iteration restarted near the opposite limit and never agreed withlen(). This affected signed and unsigned ranges in both step directions. -
reversed()on a scalarrange()no longer yields an empty iterator when the range starts within one step of the element type's limit, as inreversed(range(Int8.MIN, Int8.MIN + 8, Int8(1))). Unsigned ranges, and ranges whose span overflows their element type, are fixed by the same change.Reversing an already-reversed range, as in
reversed(reversed(range(10))), is now a compile-time error. -
Fixed
ceildiv()returning0for unsigned operands near the type's maximum value. The unsigned code path computednumerator + denominator - 1, which overflows and wraps for large operands; it now derives the ceiling from the floor division and remainder instead. -
Counter.most_common(n)now returns all elements whennexceeds the number of unique elements, matching Python, instead of aborting. -
os.path.join()now inserts separators based on the accumulated path rather than the first argument, sojoin("/", "a", "b")returns/a/b(previously/ab) andjoin("a", "b/", "c")returnsa/b/c(previouslya/b//c). -
base64.b64decode()now raises an error when the input length is not divisible by 4 instead of reading past the end of the input (or aborting when asserts are enabled). -
On macOS,
os.stat()andos.lstat()no longer return a negativest_modefor regular files. The underlyingmode_tandnlink_tC type aliases were declared as signed 16-bit integers, but macOS defines them as unsigned, so any mode with theS_IFREGbit set (every regular file) sign-extended into a negativeInt. -
On macOS,
os.stat()andos.lstat()now report file timestamps with the correct nanosecond values._CTimeSpec.as_nanoseconds()previously treated thetimespec.tv_nsecfield as microseconds, inflating the subsecond component by a factor of up to 1,000. -
PythonObjectno longer leaks a CPython reference per positional argument when calling a Python object, nor when setting an item, attribute, or set literal element. -
atol()(and thereforeInt(String)) now raises for every value outside theIntrange. Values just pastInt.MAX(such asInt.MAX + 1) no longer wrap silently, andInt.MINparses correctly by design rather than by wraparound.atol()will also now raise instead of aborting on a string that holds only whitespace, or only whitespace and a sign. -
Every value of a struct type whose
@align(N)exceeds its natural alignment is now aligned toN, including every element of an array or aListof that type. -
b64decode()now ignores ASCII whitespace in its input, so base64 text wrapped across lines by a MIME encoder or thebase64command line tool decodes without the caller stripping it first. Only the six ASCII whitespace bytes are ignored; unlike Python'sbase64.b64decode(), any other byte outside the base64 alphabet still raises. The "length must be divisible by 4" error now counts only the significant characters.