v24.2 (2024-03-28)
🔥 Legendary
-
The Mojo standard library is now open source! Check out the README for everything you need to get started.
-
Structs and other nominal types are now allowed to implicitly conform to traits. A struct implicitly conforms to a trait if it implements all the requirements for the trait. For example, any struct that implements the
__str__()method implicitly conforms toStringable, and is usable with thestr()built-in function.@value
struct Foo:
fn __str__(self) -> String:
return "foo!"
fn main():
print(str(Foo())) # prints 'foo!'We still strongly encourage you to explicitly list the traits a struct conforms to when possible:
@value
struct Foo(Stringable): ...Not only is this useful for documentation and for communicating intentions, but in the future, explicit conformance will be useful for features like default methods and extensions.
-
Mojo's Python interoperability now supports passing keyword arguments to Python functions:
from python import Python
def main():
plt = Python.import_module("matplotlib.pyplot")
plt.plot((5, 10), (10, 15), color="red")
plt.show()
Language changes
⭐️ New
-
Mojo now has support for variadic keyword arguments, often referred to as
**kwargs. This means you can now declare and call functions like this:fn print_nicely(**kwargs: Int) raises:
for key in kwargs.keys():
print(key[], "=", kwargs[key[]])
# prints:
# `a = 7`
# `y = 8`
print_nicely(a=7, y=8)For more details (and a list of current limitations), see Variadic keyword arguments in the Mojo manual.
🦋 Changed or removed
-
letdeclarations now produce a compile time error instead of a warning, our next step in removing let declarations. The compiler still recognizes theletkeyword for now in order to produce a good error message, but that will be removed in subsequent releases. -
Mojo now warns about unused values in both
defandfndeclarations, instead of completely disabling the warning indefs. It never warns about unusedobjectorPythonObjectvalues, tying the warning to these types instead of the kind of function they are unused in. This will help catch API usage bugs indefs and make imported Python APIs more ergonomic infns. -
For the time being, dynamic type values will be disabled in the language. For example, the following will now fail with an error:
var t = Int # dynamic type values not allowed
struct SomeType: ...
takes_type(SomeType) # dynamic type values not allowedWe want to take a step back and (re)design type valued variables, existentials, and other dynamic features. This does not affect type valued parameters, so the following works as before:
alias t = Int # still 🔥
struct SomeType: ...
takes_type[SomeType]() # already 🔥
>fn uses_trait[T: SomeTrait](value: T): ... # still 🔥 -
The
*_expression in parameter expressions is now required to occur at the end of a positional parameter list, instead of being allowed in the middle.# No longer supported
alias FirstUnbound = SomeStruct[*_, 42]
alias MidUnbound = SomeStruct[7, *_, 6]
# Still supported
alias LastUnbound = SomeStruct[42, *_]We narrowed this because we want to encourage type designers to get the order of parameters right, and want to extend
*_to support keyword parameters as well in the future.
Standard library changes
⭐️ New
-
DynamicVectorhas been renamed toList, and has moved from thecollections.vectormodule to thecollections.listmodule. In addition:-
You can now construct a
Listfrom a variadic number of values. For example:var numbers = List[Int](1, 2, 3) -
ListandInlinedFixedVectortypes now support negative indexing. This means that you can writevec[-1]which is equivalent tovec[len(vec)-1]. -
List.push_back()has been removed. Please use theappend()function instead.
-
-
The
print()function now takessepandendkeyword arguments. This means that you can write:print("Hello", "Mojo", sep=", ", end="!!!\n") # prints Hello, Mojo!!!sepdefaults to the empty string andenddefaults to "\n".Also, the
print_no_newline()function has been removed. Please useprint(end="")instead. -
The
FloatLiteraltype is now an infinite-precision nonmaterializable type. This means you can do compile-time calculations usingFloatLiteralwithout rounding errors. When materialized at runtime, aFloatLiteralvalue is converted to aFloat64.# third is an infinite-precision FloatLiteral value
alias third = 1.0 / 3.0
# t is a Float64
var t = third -
String types all conform to the
IntableRaisingtrait. This means that you can now callint("123")to get the integer123. If the integer cannot be parsed from the string, then an error is raised. -
The
Tensortype now hasargmax()andargmin()functions to compute the position of the max or min value. Note: this should return aTensor[Int]but currently the output tensor is the same type as the input tensor. This will be fixed in a future release. -
Added a new
collections.OptionalRegtype, a register-passable alternative toOptional. -
The
ulp()function has been added to themathmodule. This allows you to get the units of least precision (or units of last place) of a floating point value.
🦋 Changed
-
The
simd_load(),simd_store(),aligned_simd_load(), andaligned_simd_store()methods onDTypePointer,Buffer, andNDBufferhave been merged into a more expressive set ofload()andstore()methods with keyword-onlywidthandalignmentparameters:# Doesn't work
my_simd = my_buffer.simd_load[simd_width](index)
# Works
my_simd = my_buffer.load[width=simd_width](index)
# Doesn't work
my_buffer.aligned_simd_store[width, alignment](my_simd)
# Works
my_buffer.store[width=width, alignment=alignment](my_simd) -
The
EqualityComparabletrait now requires the__ne__()method for conformance in addition to the previously required__eq__()method. -
Many types now declare conformance to
EqualityComparabletrait. -
StaticTupleparameter order has changed toStaticTuple[type, size]for consistency withSIMDand similar collection types. -
The signature of the
elementwise()function has been changed. The new order isfunction,simd_width, and thenrank. As a result, the rank parameter can now be inferred and one can callelementwise()without it:elementwise[func, simd_width](shape) -
PythonObjectis now register-passable. -
PythonObject.__iter__()now works correctly on more types of iterable Python objects. Attempting to iterate over non-iterable objects will now raise an exception instead of behaving as if iterating over an empty sequence.__iter__()also now borrowsselfrather than requiringinout, allowing code like:for value in my_dict.values():
...
🚚 Moved
-
We took the opportunity to rehome some modules into their correct package as we were going through the process of open-sourcing the Mojo standard library. Specifically, the following are some breaking changes worth calling out. Please update your import statements accordingly.
-
Buffer,NDBuffer, and friends have moved from thememorypackage into a newbufferpackage.from buffer import Buffer, NDBuffer -
utils.list, including theDimandDimListtypes, has moved to thebufferpackage.from buffer import Dim, DimList -
The
parallel_memcpy()function has moved from thememorypackage into thebufferpackage.from buffer import parallel_memcpy -
The
rand()andrandn()functions from therandompackage that return aTensorhave moved to thetensorpackage. Note that the overloads that write to aDTypePointerremain in therandompackage.If you happen to be using both versions in the same source file, you can import them both using the
import assyntax:from tensor import rand
from random import rand as rand_dt -
The
trap()function has been renamed toabort(). It also has moved from thedebugmodule to theosmodule.from os import abort -
The
isinf()andisfinite()methods have been moved frommath.limitsto themathmodule.from math import ininf, isfinite
-
Tooling changes
⭐️ New
-
Docstring code blocks can now use
%#to hide lines of code from documentation generation.For example:
var value = 5
%# print(value)Will generate documentation of the form:
var value = 5Hidden lines are processed as if they were normal code lines during test execution. This allows for writing additional code within a docstring example that is only used to ensure the example is runnable/testable.
-
The Mojo LSP server now allow you to specify additional search paths to use when resolving imported modules in a document. You can specify search paths on the command line, using the
-Ioption, or you can add them to themojo.lsp.includeDirssetting in the VS Code extension.
Other changes
❌ Removed
-
The
__get_address_as_lvaluemagic function has been removed. You can now get an LValue from aPointerorReferenceby using the dereference operator ([]):var ptr: Pointer[MyRecord]
...
# Doesn't work
__get_address_as_lvalue(ptr.value) = MyRecord(3, 5)
# Works
ptr[] = MyRecord(3, 5) -
The type parameter for the
memcpyfunction is now automatically inferred. This means that calls tomemcpyof the formmemcpy[Dtype.xyz](...)will no longer work and the user would have to change the code tomemcpy(...). -
The
memcpy()overload that worked onBuffertypes has been removed in favor of just overloads forPointerandDTypePointer:# Doesn't work
memcpy(destBuffer, srcBuffer, count)
# Works
memcpy(destBuffer.data, srcBuffer.data, count) -
The functions
max_or_inf(),min_or_neginf()have been removed frommath.limit. These functions were only used by the SIMD type. -
As mentioned previously, the
print_no_newline()function has been removed. Please useprint(end="")instead.
🛠️ Fixed
- #1362 - Parameter inference now recursively matches function types.
- #951 - Functions that were
both
asyncand@always_inlineincorrectly errored. - #1858 - Trait with parametric methods regression.
- #1892 - Forbid unsupported decorators on traits.
- #1735 - Trait-typed values are incorrectly considered equal.
- #1909 - Crash due to nested import in unreachable block.
- #1921 - Parser crashes
binding
Referenceto lvalue with subtype lifetime. - #1945 -
Optional[T].or_else()should returnTinstead ofOptional[T]. - #1940 - Constrain
math.copysignto floating point or integral types. - #1838 - Variadic
printdoes not work when specifyingend="" - #1826 - The
SIMD.reducemethods correctly handle edge cases wheresize_out >= size.