Skip to main content
Version: Nightly

v0.5.0 (2023-11-2)

⭐️ New

  • The SIMD type now defaults to the architectural SIMD width of the type. This means you can write SIMD[DType.float32] which is equivalent to SIMD[DType.float32, simdwidthof[DType.float32]()].

  • The SIMD type now contains a join() function that allows you to concatenate two SIMD values together and produce a new SIMD value.

  • Mojo now supports compile-time keyword parameters, in addition to existing support for keyword arguments. For example:

    fn foo[a: Int, b: Int = 42]():
    print(a, "+", b)

    foo[a=5]() # prints '5 + 42'
    foo[a=7, b=13]() # prints '7 + 13'
    foo[b=20, a=6]() # prints '6 + 20'

    Keyword parameters are also supported in structs:

    struct KwParamStruct[a: Int, msg: String = "🔥mojo🔥"]:
    fn __init__(inout self):
    print(msg, a)

    fn use_kw_params():
    KwParamStruct[a=42]() # prints '🔥mojo🔥 42'
    KwParamStruct[5, msg="hello"]() # prints 'hello 5'
    KwParamStruct[msg="hello", a=42]() # prints 'hello 42'

    For more detail, see the Mojo Manual.

    For the time being, the following notable limitations apply:

    • Keyword-only parameters are not supported yet:

      fn baz[*args: Int, b: Int](): pass  # fails
      fn baz[a: Int, *, b: Int](): pass # fails

      (The analogous keyword-only arguments in Python are described in PEP 3102.)

    • Variadic keyword parameters are not supported yet:

      fn baz[a: Int, **kwargs: Int](): pass  # fails
  • Mojo now supports "automatic" parameterization of functions. What this means is that if a function argument type is parametric but has no bound parameters, they are automatically added as input parameters on the function. This works with existing features to allow you to write parametric functions with less boilerplate.

    @value
    struct Thing[x: Int, y: Int]:
    pass

    fn foo(v: Thing):
    print(v.x)
    print(v.y)

    fn main():
    let v = Thing[2, 3]()
    foo(v)

    However, partial autoparameterization is not supported yet:

    fn foo(v: Thing[y=7]):  # Partially bound type not allowed yet.
    ...
  • Keyword argument passing is supported when invoking __getitem__ using the bracket syntax:

    @value
    struct MyStruct:
    fn __getitem__(self, x: Int, y: Int, z: Int) -> Int:
    return x * y + z

    MyStruct()[z=7, x=3, y=5] # returns 22

    However, keyword argument passing to __setitem__ using the bracket syntax is not supported yet:

    @value
    struct OtherStruct:
    fn __setitem__(self, x: Int, y: Int): pass

    OtherStruct()[x=1] = 4 # fails
  • Function argument input parameters can now be referenced within the signature of the function:

    fn foo(x: SIMD, y: SIMD[x.type, x.size]):
    pass
  • The benchmark module has been simplified and improved so you can now run:

    import benchmark
    from time import sleep

    fn sleeper():
    sleep(.01)

    fn main():
    let report = benchmark.run[sleeper]()
    print(report.mean())

    It no longer requires a capturing fn so can benchmark functions outside the same scope.

    You can print a report with:

    report.print()
    ---------------------
    Benchmark Report (s)
    ---------------------
    Mean: 0.012314264957264957
    Total: 1.440769
    Iters: 117
    Warmup Mean: 0.0119335
    Warmup Total: 0.023866999999999999
    Warmup Iters: 2
    Fastest Mean: 0.012227958333333334
    Slowest Mean: 0.012442699999999999

    Units for all functions default to seconds, but can be changed with:

    from benchmark import Unit

    report.print[Unit.ms]()
  • Mojo now supports struct parameter deduction (a.k.a. class template argument deduction, or CTAD) for partially bound types. Struct parameter deduction is also possible from static methods. For example:

    @value
    struct Thing[v: Int]: pass

    struct CtadStructWithDefault[a: Int, b: Int, c: Int = 8]:
    fn __init__(inout self, x: Thing[a]):
    print("hello", a, b, c)

    @staticmethod
    fn foo(x: Thing[a]):
    print("🔥", a, b, c)

    fn main():
    _ = CtadStructWithDefault[b=7](Thing[6]()) # prints 'hello 6 7 8'
    CtadStructWithDefault[b=7].foo(Thing[6]()) # prints '🔥 6 7 8'
  • Tensor has new fromfile() and tofile() methods to save and load as bytes from a file.

  • The built-in print() function now works on the Tensor type.

  • TensorShape and TensorSpec now have constructors that take DynamicVector[Int] and IndexList to initialize shapes.

  • The String type now has the count() and find() methods to enable counting the number of occurrences or finding the offset index of a substring in a string.

  • The String type now has a replace() method which allows you to replace a substring with another string.

🦋 Changed

  • VariadicList and VariadicListMem moved under builtins, and no longer need to be imported.

  • Variadic arguments are now automatically projected into a VariadicList or VariadicListMem inside the function body. This allows for more flexibility in using var args. For example:

      fn print_ints(*nums: Int):
    let len = len(nums)
    for i in range(len):
    print(nums[i])
    print(len)
  • The parameters for InlinedFixedVector have been switched. The parameters are now [type, size] instead of [size, type]. The InlinedFixedVector now has a default size which means that one can just use InlinedFixedVector as InlinedFixedVector[Float32] and the default size is used.

  • write_file() method in Buffer and NDBuffer is renamed to tofile() to match the Python naming.

  • Mojo will now utilize all available cores across all NUMA sockets on the host machine by default. The prior default behavior was to use all the cores on the first socket.

❌ Removed

  • The math.numerics module is now private, because its types (FPUtils and FlushDenormals) should not be used externally.

🛠️ Fixed

  • #532 - Compiler optimizing while True loop away
  • #760 - Compilation error: 'hlcf.for.yield' op specifies 0 branch inputs but target expected 1 along control-flow edge from here
  • #849 - The Tensor type is now initialized with zeros at construction time.
  • #912 - Invalid load for __get_address_as_lvalue.
  • #916 - Parser crash when specifying default values for inout arguments.
  • #943 - Mojo hangs if you use continue in the nested loop
  • #957 - Parser crash when a function call with variadic arguments of a memory-only type is evaluated at compile time.
  • #990 - Fixes rounding issue with floor division with negative numerator.
  • #1018 - In some cases the sort function was returning invalid results. This release fixes some of these corner cases.
  • #1010 - Initializing tensor in alias declaration results in crash.
  • #1110 - The time.now() function now returns nanoseconds across all operating systems.
  • #1115 - cannot load non-register passable type into SSA register.