{"slug": "first-look-mojo-1-0-mixes-python-and-rust", "title": "First look: Mojo 1.0 mixes Python and Rust", "summary": "Modular released the first beta of Mojo 1.0, a systems programming language that combines Python-like syntax with Rust-style memory safety and ownership. The language provides precise control over memory, strong typing, GPU programming support, and pointer types, but is not a drop-in replacement for Python. Mojo aims to capture developers in math, statistics, and machine learning by offering high performance with familiar syntax.", "body_md": "## Milestone Mojo release reveals a systems programming language with precise control over memory, strong types, GPU programming support, and intuitive Python-like syntax.\n\nBack in 2023, Chris Lattner, creator of [LLVM](https://www.infoworld.com/article/2261861/what-is-llvm-the-power-behind-swift-rust-clang-and-more.html), and [his team at Modular](https://www.modular.com/company/about) unveiled [a new language called Mojo](https://www.infoworld.com/article/2338548/a-first-look-at-the-mojo-language.html). Its syntax resembled Python, but it compiled to machine-native code and offered memory-safety features akin to Rust. It also offered cross-compatibility with existing Python programs, one of many hints that Mojo aimed to capture the math, stats, and machine learning segment of Python developers.\n\nNow in 2026, the first [beta version of Mojo 1.0](https://mojolang.org/releases/v1.0.0b1/) is out, and with that the shape of the language is far clearer than before. Most crucially: Mojo is not a drop-in replacement for Python. It still features Python-esque syntax and uses many of Python’s concepts, but is unmistakably headed in its own direction. As of 1.0 and beyond, Mojo aims to be a systems language with precise control over memory and strong types, while sporting convenience features inspired by higher-level languages.\n\n## Mojo basics\n\nMojo syntax resembles Python at first glance. The use of indents instead of braces to delineate blocks, common keywords (`def`\n\nfor functions, etc.), how control flow is handled (`if/else/while/for`\n\n), exceptions, and type annotations will all be familiar to Python developers.\n\nWhere Mojo breaks with Python, and stakes out its own territory, starts with how values are handled in variables. Variables have strong types, either assigned through annotations or inferred automatically from their first assignment. If you set `a`\n\nto equal `1`\n\n, you cannot set it to `\"Greetings earthlings\"`\n\nlater. (In Python, the objects themselves are strongly typed but the names used to refer to them do not have types.)\n\nMojo further breaks from Python by adding a concept found in Rust: *ownership* of values. Instead of runtime garbage collection, Mojo uses ownership to track the lifetimes of objects at compile time.\n\nTo indicate you want to transfer ownership of a value, you use the “transfer sigil” syntax:\n\n```\na = [1,2,3]\nb = a^\n```\n\nThe `^`\n\nindicates we’re moving ownership of the contents of `a`\n\ninto `b`\n\n. For data types that aren’t implicitly copyable, like containers, we can use transfer of ownership. Or we can make a copy explicitly:\n\n```\na = [1,2,3]\nb = a.copy()\n```\n\nVariables that reference other values, like an element in a list, are copied if they are implicitly copyable. But you can use the `ref`\n\nkeyword to take a reference rather than make a copy:\n\n```\na = [1,2,3]\nb = a[1] # copy; integers are implicitly copyable\nb+=1 # changes only value of b\nref c = a[1] # reference\nc+=1 # changes value stored in a[1]\n```\n\nMojo also offers pointer types, whereas Python has no such thing in the language definition. You can create four kinds of pointers in Mojo, depending on how much control you need:\n\n- A regular\n`Pointer`\n\npoints to any value it doesn’t own. `OwnedPointer`\n\npoints to a single value, which it owns.`ArcPointer`\n\nis like an`OwnedPointer`\n\nbut it’s reference-counted, so it can point to objects that potentially have other`ArcPointers`\n\npointing to them.`UnsafePointer`\n\ncan point to*anything*, including uninitialized memory or multiple values (like an array in C). The idea is to use other pointer types whenever you can, and avoid`UnsafePointer`\n\n[unless you absolutely need it](https://mojolang.org/docs/manual/pointers/unsafe-pointers/#).\n\nAs with Rust, any Mojo code that doesn’t follow the rules for type descriptions, ownership, and borrowing doesn’t compile.\n\n## Mojo types and values\n\nLike Python, Mojo offers several built-in common data types. Unlike Python, they more directly correspond to high-performance, machine-level types. Mojo offers signed and unsigned integers in various bit widths, up to 64 bits, and floating-point numbers in the same range of sizes. All these types can be used in SIMD-accelerated vectors.\n\nBy contrast, Python integers can theoretically be of any size, but they don’t map directly to hardware integers, so they operate more slowly. And while Python floating-point numbers are machine-level 64-bit floats, they’re wrapped as Python objects, so they too incur performance overhead.\n\nMojo also offers Python-like boolean values and the list, dictionary, and set container types. Plus it adds an `Optional`\n\ntype, which is a value that can hold a particular type of value or `None`\n\n, along with a Rust-like `.or_else()`\n\nmethod to obtain a default value instead of raising an error.\n\nFor working with linear algebra and multidimensional arrays, Mojo offers a `layout`\n\npackage as part of its standard library. This includes two tensor types, the older [ LayoutTensor](https://mojolang.org/docs/manual/layout/tensors/) and the newer\n\n[type. The data type is declared separately from the layout, separating the concerns of data storage and data access. Layouts cover not only the dimensional shape of the data, but also things like strided access or whether the layout is row-based or column-based.](https://mojolang.org/docs/manual/tile-tensor/)\n\n`TileTensor`\n\n## Mojo structs vs. Python classes\n\nWhereas Python has classes, Mojo has structs. Mojo structs are defined in much the same way as Python classes, and they have many of the same behaviors:\n\n``` python\nstruct Point:\n    var x: Int\n    var y: Int\n    def __init__(out self, x: Int, y: Int):\n        self.x = x\n        self.y = y\n```\n\nThe same struct can be more succinctly defined as shown below, in much the same way as Python’s dataclasses:\n\n``` js\n@fieldwise_init\nstruct Point:\n    var x: Int\n    var y: Int\n```\n\nBy default, Mojo structs don’t support copy or move operations. Those have to be defined by adding “traits” to the struct (another nod to Rust concepts):\n\n```\nstruct Point(Copyable):\n```\n\nTraits are also used to grant common behaviors across structs, since Mojo’s structs don’t have inheritance behaviors the way Python classes do. Mojo structs also lack Python’s other dynamic qualities: fields in a struct all have to be laid out ahead of time and type-defined.\n\nBecause Mojo more directly exposes machine-level types and behaviors than Python, structs can take advantage of those things. The `RegisterPassable`\n\ntrait for a struct, for instance, allows the created type to be passed in machine registers for speed, provided it [conforms to some key behaviors](https://mojolang.org/docs/manual/traits/#register-passable).\n\n## Mojo error types and exceptions\n\nIn Python, errors are propagated up the program stack as exceptions, instead of being returned as values. This means error handling works along a different path than normal program flow.\n\nMojo has what looks like a similar mechanism. You `raise`\n\nerrors, and you intercept them with `try/except/else/finally`\n\nblocks. However, Mojo handles errors differently under the hood. In Mojo, errors are essentially values, and raising them doesn’t involve unwinding the program stack. This keeps the runtime overhead for error-checking to a minimum.\n\nThe default error type is a simple string, but you can use any struct type as an error value if you want to propagate additional information with the error. However, the Mojo compiler does not permit you to catch more than one kind of error type in a single `try`\n\nblock. The common Python pattern of `try:/except ThisError:/except ThatError:/except Exception:`\n\ndoesn’t exist in Mojo. This ensures that each type of error that can be raised is given distinct logical treatment.\n\n## Metaprogramming in Mojo\n\nPython’s dynamism and runtime flexibility mean there’s little need for the metaprogramming features, like macros, that show up in other languages. The trade-off is that such flexibility comes at the cost of performance.\n\nMojo is more akin to Rust or C++ in that it offers compile-time metaprogramming — ways to define behaviors that are checked at compile time instead of runtime. The `comptime`\n\nkeyword lets you define values (essentially compile-time constants), unroll loops (for faster loop execution), or invoke blocks of code to be generated based on compile-time conditions (as per `#ifdef`\n\nin C):\n\n```\ncomptime if enable_tpu():\n    use_tpu()\nelse:\n    use_cpu()\n```\n\nMojo also allows functions to be given their own compile-time conditions by way of parameters:\n\n``` php\ndef advance_by[amount:Int](x: Int) -> Int:\n    return x+amount\n\ndef main():\n    comptime by_five = advance_by[5]\n    n = by_five(5) \n    # n will be 10\n    m = advance_by[10](2)\n    # m will be 12\n```\n\nThe parameter (in square brackets) is provided to the function at compile time. We use a `comptime`\n\nstatement to create a new function object based on the parameters supplied, and we call that. Or, as in the line `m = advance_by[10](2)`\n\n, we just call the function directly and provide a value known at compile time. This syntax also can be used to generate functions that are “datatype-agnostic”:\n\n``` php\ndef advance_by[dt:DType](x:Scalar[dt], y:Scalar[dt]) -> Scalar[dt]:\n    return x+y\n```\n\n`DType`\n\nis Mojo’s built-in namespace for data types, so this function accepts two scalar variables (`float16, int32`\n\n, etc.) as long as they are the same type.\n\nParameters also can be given default values, same as regular arguments for a function, or work with a variable number of parameters (as long as they’re all the same register-passable type).\n\nAnother compile-time feature, “constraints,” lets you define conditions for calling functions or creating structs at runtime:\n\n``` php\ndef add_to_nonzero[x: Int]() -> where x >=0:\n    ...\n\nstruct Box[size: Int where size>0]:\n    ...\n```\n\nConstraints are verified at compile time, so any violation of them throws a compiler error (rather than a runtime error).\n\nThe same syntax for constraints and parameters can be used to generate generics:\n\n``` php\ndef analyze[T: Comparable & Copyable](values:List[T]) -> List[T]:\n    ...\n```\n\nA function with this signature would take in a list of values that are of a certain type T declared at compile time, and return a list of values of the same type. However, that type would have to support the `Comparable`\n\nand `Copyable`\n\ntraits.\n\nMojo’s [reflection](https://mojolang.org/docs/manual/metaprogramming/reflection/) features allow you to write code that performs compile-time actions on its own structure. As of this writing Mojo’s reflection support is limited, but can be [used with traits](https://mojolang.org/docs/manual/metaprogramming/reflection/#write-once-reuse-everywhere-with-traits) to provide behaviors that work across struct types without needing to account directly for their design.\n\n## GPU support in Mojo\n\nIn most programming languages, Python included, GPU support isn’t part of the language as such. Rather, it’s part of whatever library you might use that supports GPU computation (for instance, CuPy).\n\nBy contrast, Mojo’s standard library has a `gpu`\n\npackage that exposes programming APIs specifically for GPUs. Mojo’s [programming model for GPUs](https://mojolang.org/docs/manual/gpu/fundamentals/#gpu-programming-model) lets you write functions that work with values that support the [DevicePassable trait](https://mojolang.org/docs/std/builtin/device_passable/DevicePassable/) — integers and floats, typically — and return the results by storing them in a memory buffer passed as an argument.\n\nUnlike Python toolkits such as Numba, Mojo doesn’t provide a way to do this automatically for a given function, for instance by way of a decorator. The Mojo function has to be GPU-friendly in its design, and additional boilerplate is needed to set up the GPU connection, compile the function on the GPU, run it, and retrieve the results. But the documentation provides detailed guidance for using GPU support properly, including how to [avoid race conditions](https://mojolang.org/docs/manual/gpu/block-and-warp/) between GPU operations.\n\n## Python interop in Mojo\n\nA major feature of Mojo’s earlier versions was the ability to call Python from Mojo and vice versa, as a way to allow Mojo to make use of the Python package ecosystem. Mojo 1.0 preserves this feature, along with the original mechanisms for it:\n\n[When Mojo calls Python](https://mojolang.org/docs/manual/python/python-from-mojo/), it invokes the CPython runtime to do so. In essence Mojo is just spinning up a CPython instance and using it as a dynamically linked library.[When Python calls Mojo](https://mojolang.org/docs/manual/python/mojo-from-python/), it loads the Mojo code as a Python module, similar to how Python uses C/C++ or any code that exposes a C-compatible FFI. A Mojo module can declare external bindings that Python can recognize and use.\n\nThe interop between Mojo and Python has the same limitations as interop between Python and C. [Mojo and Python types](https://mojolang.org/docs/manual/python/types/) must be converted in both directions, and the cost of making function calls in either direction isn’t trivial. That means the best uses of Mojo and Python together would be for operations where most of the work can be done in Mojo, with minimal calls across the language divide.\n\n## Mojo’s mojo\n\nAny new programming language faces barriers. The biggest is finding an audience as a driver for growth and further development. Mojo’s target audience appears to be current Python and Rust users who have issues with their respective languages — Python’s performance, Rust’s complexity — and want a better alternative.\n\nAnother obstacle: Right now there’s no automatic migration path from Rust or Python to a pure-Mojo codebase. And if Rust and Python can make progress on their respective issues (although it seems more likely that Python will get faster than Rust will get simpler), Mojo will have even more work cut out for it.\n\nObstacles aside, Mojo’s direct syntax, machine-native speed, and future-looking features, like GPU-based programming, are appealing. It’s entirely possible that those features will bring Mojo a following all its own.", "url": "https://wpnews.pro/news/first-look-mojo-1-0-mixes-python-and-rust", "canonical_source": "https://www.infoworld.com/article/4173158/first-look-mojo-1-0-mixes-python-and-rust.html", "published_at": "2026-05-27 06:14:50+00:00", "updated_at": "2026-05-27 06:26:37.624708+00:00", "lang": "en", "topics": ["machine-learning", "artificial-intelligence", "ai-infrastructure", "ai-tools", "ai-products"], "entities": ["Chris Lattner", "LLVM", "Modular", "Mojo", "Python", "Rust"], "alternates": {"html": "https://wpnews.pro/news/first-look-mojo-1-0-mixes-python-and-rust", "markdown": "https://wpnews.pro/news/first-look-mojo-1-0-mixes-python-and-rust.md", "text": "https://wpnews.pro/news/first-look-mojo-1-0-mixes-python-and-rust.txt", "jsonld": "https://wpnews.pro/news/first-look-mojo-1-0-mixes-python-and-rust.jsonld"}}