v24.1 (2024-02-29)
🔥 Legendary
-
Mojo is now bundled with the MAX platform!
As such, the Mojo package version now matches the MAX version, which follows a
YY.MAJOR.MINORversion scheme. Because this is our first release in 2024, that makes this version24.1. -
Mojo debugging support is here! The Mojo VS Code extension includes debugger support. For details, see Debugging in the Mojo Manual.
⭐️ New
-
We now have a
Settype in our collections!Setis backed by aDict, so it has fast add, remove, andinchecks, and requires member elements to conform to theKeyElementtrait.from collections import Set
var set = Set[Int](1, 2, 3)
print(len(set)) # 3
set.add(4)
for element in set:
print(element[])
set -= Set[Int](3, 4, 5)
print(set == Set[Int](1, 2)) # True
print(set | Set[Int](0, 1) == Set[Int](0, 1, 2)) # True
let element = set.pop()
print(len(set)) # 1 -
Mojo now supports the
x in yexpression as syntax sugar fory.__contains__(x)as well asx not in y. -
Mojo now has support for keyword-only arguments and parameters. For example:
fn my_product(a: Int, b: Int = 1, *, c: Int, d: Int = 2):
print(a * b * c * d)
my_product(3, c=5) # prints '30'
my_product(3, 5, d=7) # error: missing 1 required keyword-only argument: 'c'This includes support for declaring signatures that use both variadic and keyword-only arguments/parameters. For example, the following is now possible:
fn prod_with_offset(*args: Int, offset: Int = 0) -> Int:
var res = 1
for i in range(len(args)):
res *= args[i]
return res + offset
print(prod_with_offset(2, 3, 4, 10)) # prints 240
print(prod_with_offset(2, 3, 4, offset=10)) # prints 34Note that variadic keyword-only arguments/parameters (for example,
**kwargs) are not supported yet. That is, the following is not allowed:fn variadic_kw_only(a: Int, **kwargs): ...For more information, see Positional-only and keyword-only arguments in the Mojo Manual.
-
The
print()function now accepts a keyword-only argument for theendwhich is useful for controlling whether a newline is printed or not after printing the elements. By default,enddefaults to "\n" as before. -
The Mojo SDK can now be installed on AWS Graviton instances.
-
A new version of the Mojo Playground is available. The new playground is a simple interactive editor for Mojo code, similar to the Rust Playground or Go Playground. The old JupyterLab based playground will remain online until March 20th.
-
The Mojo LSP server will now generate fixits for populating empty documentation strings:
fn foo(arg: Int):
"""""" # Unexpected empty documentation stringApplying the fixit from above will generate:
fn foo(arg: Int):
"""[summary].
Args:
arg: [description].
""" -
Added new
*_syntax that allows users to explicitly unbind any number of positional parameters. For example:struct StructWithDefault[a: Int, b: Int, c: Int = 8, d: Int = 9]: pass
alias all_unbound = StructWithDefault[*_]
# equivalent to
alias all_unbound = StructWithDefault[_, _, _, _]
alias first_bound = StructWithDefault[5, *_]
# equivalent to
alias first_bound = StructWithDefault[5, _, _, _]
alias last_bound = StructWithDefault[*_, 6]
# equivalent to
alias last_bound = StructWithDefault[_, _, _, 6]
alias mid_unbound = StructWithDefault[3, *_, 4]
# equivalent to
alias mid_unbound = StructWithDefault[3, _, _, 4]As demonstrated above, this syntax can be used to explicitly unbind an arbitrary number of parameters, at the beginning, at the end, or in the middle of the operand list. Since these unbound parameters must be explicitly specified at some point, default values for these parameters are not applied. For example:
alias last_bound = StructWithDefault[*_, 6]
# When using last_bound, you must specify a, b, and c. last_bound
# doesn't have a default value for `c`.
var s = last_bound[1, 2, 3]()For more information see the Mojo Manual sections on partially-bound types and automatic parameterization of functions.
-
DynamicVectornow supports iteration. Iteration values are instances ofReferenceand require dereferencing:var v: DynamicVector[String]()
v.append("Alice")
v.append("Bob")
v.append("Charlie")
for x in v:
x[] = str("Hello, ") + x[]
for x in v:
print(x[]) -
The
mojo packagecommand now produces compilation agnostic packages. Compilation options such as O0, or --debug-level, are no longer needed or accepted. As a result, packages are now smaller, and extremely portable. -
Initializers for
@register_passablevalues can (and should!) now be specified withinout selfarguments just like memory-only types:@register_passable
struct YourPair:
var a: Int
var b: Int
fn __init__(inout self):
self.a = 42
self.b = 17
fn __copyinit__(inout self, existing: Self):
self.a = existing.a
self.b = existing.bThis form makes the language more consistent, more similar to Python, and easier to implement advanced features for. There is also no performance impact of using this new form: the compiler arranges to automatically return the value in a register without requiring you to worry about it.
The older
-> Selfsyntax is still supported in this release, but will be removed in a subsequent one, so please migrate your code. One thing to watch out for: a given struct should use one style or the other, mixing some of each won't work well. -
The
inout selfinitializer form is required for initializers of@register_passabletypes that may raise errors:@register_passable
struct RaisingCtor:
fn __init__(inout self) raises:
raise -
asyncfunctions that may raise errors have been temporarily disabled in this build. The implementation of Mojo async is undergoing a rework 🚧. -
The standard library
slicetype has been renamed toSlice, and aslicefunction has been introduced. This makes Mojo closer to Python and makes theSlicetype follow the naming conventions of other types likeInt. -
"Slice" syntax in subscripts is no longer hard coded to the builtin
slicetype: it now works with any type accepted by a container's__getitem__()method. For example:@value
struct UnusualSlice:
var a: Int
var b: Float64
var c: String
struct YourContainer:
fn __getitem__(self, slice: UnusualSlice) -> T: ...Given this implementation, you can subscript into an instance of
YourContainerlikeyc[42:3.14:"🔥"]and the three values are passed to theUnusualSliceconstructor. -
The
__refitem__()accessor method may now return aReferenceinstead of having to return an MLIR internal reference type. -
Added
AnyPointer.move_into()method, for moving a value from one pointer memory location to another. -
Added built-in
hex()function, which can be used to format any value whose type implements theIntabletrait as a hexadecimal string. -
PythonObjectnow implements__is__and__isnot__so that you can use expressions of the formx is yandx is not ywithPythonObject. -
PythonObjectnow conforms to theSizedRaisingtrait. This means the built-inlen()function now works onPythonObject. -
The
ospackage now contains thestat()andlstat()functions. -
A new
os.pathpackage now allows you to query properties on paths. -
The
ospackage now has aPathLiketrait. A struct conforms to thePathLiketrait by implementing the__fspath__()function. -
The
pathlib.Pathnow has functions to query properties of the path. -
The
listdir()method now exists onpathlib.Pathand also exists in theosmodule to work onPathLikestructs. For example, the following sample lists all the directories in the/tmpdirectory:from pathlib import Path
fn walktree(top: Path, inout files: DynamicVector[Path]):
try:
var ls = top.listdir()
for i in range(len(ls)):
var child = top / ls[i]
if child.is_dir():
walktree(child, files)
elif child.is_file():
files.append(child)
else:
print("Skipping '" + str(child) + "'")
except:
return
fn main():
var files = DynamicVector[Path]()
walktree(Path("/tmp"), files)
for i in range(len(files)):
print(files[i]) -
The
find(),rfind(),count(), and__contains__()methods now work on string literals. This means that you can write:if "Mojo" in "Hello Mojo":
... -
Breakpoints can now be inserted programmatically within the code using the builtin
breakpoint()function.Note: on Graviton instances, the debugger might not be able to resume after hitting this kind of breakpoint.
-
Added a builtin
Boolabletrait that describes a type that can be represented as a boolean value. To conform to the trait, a type must implement the__bool__()method. -
Modules within packages can now use purely relative
fromimports:from . import another_module -
Trivial types, like MLIR types and function types, can now be bound implicitly to traits that require copy constructors or move constructors, such as
Movable,Copyable, andCollectionElement. -
A new magic
__origin_of(expr)call will yield the lifetime of a memory value. We hope and expect that this will eventually be replaced byReference(expr).lifetimeas the parameter system evolves, but this is important in the meantime for use in function signatures. -
A new magic
__type_of(expr)call will yield the type of a value. This allows one to refer to types of other variables. For example:fn my_function(x: Int, y: __type_of(x)) -> Int:
let z: __type_of(x) = y
return z
🦋 Changed
-
As another step towards removing let declarations we have removed support for let declarations inside the compiler. To ease migration, we parse
letdeclarations as avardeclaration so your code won't break. We emit a warning about this, but please switch your code to usingvarexplicitly, because this migration support will be removed in a subsequent update.fn test():
# treated as a var, but please update your code!
let x = 42 # warning: 'let' is being removed, please use 'var' instead
x = 9 -
It is no longer possible to explicitly specify implicit argument parameters in automatically parameterized functions. This ability was an oversight and this is now an error:
fn autoparameterized(x: SIMD):
pass
autoparameterized[DType.int32, 1](3) # error: too many parameters -
vectorize_unrollhas been removed, andvectorizenow has a parameter namedunroll_factorwith a default value of 1. Increasingunroll_factormay improve performance at the cost of binary size. See the loop unrolling blog here for more details. -
The
vectorizesignatures have changed with the closurefuncmoved to the first parameter:vectorize[func, width, unroll_factor = 1](size)
vectorize[func, width, size, unroll_factor = 1]()The doc string has been updated with examples demonstrating the difference between the two signatures.
-
The
unrollsignatures have changed with the closurefuncmoved to the first parameter:unroll[func, unroll_count]() -
The signature of the
NDBufferandBuffertypes have changed. Now, both take the type as the first parameter and no longer require the shape parameter. This allows you to use these types and have sensible defaults. For example:NDBuffer[DType.float32, 3]is equivalent to
NDBuffer[DType.float32, 3, DimList.create_unknown[3]()]Users can still specify the static shape (if known) to the type:
NDBuffer[DType.float32, 3, DimList(128, 128, 3)] -
The error message for missing function arguments is improved: instead of describing the number of arguments (e.g.
callee expects at least 3 arguments, but 1 was specified) the missing arguments are now described by name (e.g.missing 2 required positional arguments: 'b', 'c'). -
The
CollectionElementtrait is now a built-in trait and has been removed fromcollections.vector. -
The
DynamicVector(capacity: Int)constructor has been changed to takecapacityas a keyword-only argument to prevent implicit conversion fromInt. -
Variant.get[T]()now returns aReferenceto the value rather than a copy. -
The
Stringmethodstolower()andtoupper()have been renamed tostr.lower()andstr.upper(). -
The
refandmutrefidentifiers are no longer reserved as Mojo keywords. We originally thought about using those as language sugar for references, but we believe that generic language features combined with theReferencetype will provide a good experience without dedicated sugar.
🛠️ Fixed
- #435 Structs with Self type don't always work.
- #1540 Crash in register_passable self referencing struct.
- #1664 - Improve error
message when
StaticTupleis constructed with a negative size for the number of elements. - #1679 - crash on SIMD of zero elements.
- Various crashes on invalid code: #1230, #1699, #1708
- #1223 - Crash when parametric function is passed as (runtime) argument. The parser now errors out instead.
- #1530 - Crash during diagnostic emission for parameter deduction failure.
- #1538 and #1607 - Crash when returning type value instead of instance of expected type. This is a common mistake and the error now includes a hint to point users to the problem.
- #1613 - Wrong type name in
error for incorrect
selfargument type in trait method declaration. - #1670 - Crash on implicit conversion in a global variable declaration.
- #1741 - Mojo documentation
generation doesn't show
inout/ownedon variadic arguments. - #1621 - VS Code does not
highlight
raisesandcapturingin functional type expressions. - #1617 - VS Code does not
highlight
fnin specific contexts. - #1740 - LSP shows unrelated info when hovering over a struct.
- #1238 - File shadows Mojo package path.
- #1429 - Crash when using nested import statement.
- #1322 - Crash when missing types in variadic argument.
- #1314 - Typecheck error when binding alias to parametric function with default argument.
- #1248 - Crash when importing from file the same name as another file in the search path.
- #1354 - Crash when importing from local package.
- #1488 - Crash when setting generic element field.
- #1476 - Crash in interpreter when calling functions in parameter context.
- #1537 - Crash when copying parameter value.
- #1546 - Modify nested vector element crashes parser.
- #1558 - Invalid import causes parser to crash.
- #1562 - Crash when calling parametric type member function.
- #1577 - Crash when using unresolved package as a variable.
- #1579 - Member access into type instances causes a crash.
- #1602 - Interpreter failure when constructing strings at compile time.
- #1696 - Fixed an issue that caused syntax highlighting to occasionally fail.
- #1549 - Fixed an issue when
the shift amount is out of range in
SIMD.shift_leftandSIMD.shift_right.