Mojo: the point of view of a researcher using Python

I took a bit of time to discover the new programming language Mojo .

What is Mojo? from its official website:

“Mojo is a new programming language that bridges the gap between research and production by combining the best of Python syntax with systems programming and metaprogramming. With Mojo, you can write portable code that’s faster than C and seamlessly inter-op with the Python ecosystem.”

The Why Mojo page explains that the language has been created for Artificial Intelligence (AI). Mojo is presented as a “programming language with powerful compile-time metaprogramming, integration of adaptive compilation techniques, caching throughout the compilation flow, and other features that are not supported by existing languages.” It is also about “support modern chip architectures” with the “MLIR open-source compiler infrastructure”.

“Further, we decided that the right long-term goal for Mojo is to provide a superset of Python (that is, to make Mojo compatible with existing Python programs) and to embrace the CPython implementation for long-tail ecosystem support. If you’re a Python programmer, we hope that Mojo is immediately familiar, while also providing new tools to develop safe and performant systems-level code that would otherwise require C and C++ below Python.”

Wow, impressive! But what does this really mean? As a researcher (working in fluid mechanics) who predominantly uses Python for scientific computing, I wrote this long note on Mojo to investigate few questions:

  • What is really Mojo? And what will it become?

  • Can Mojo be useful for generalist scientific computing (i.e. not only AI)?

  • When will it be really usable? And what is currently missing?

The creators of Mojo have generated a wealth of informative materials to introduce their innovative programming language, notably the documentation and a compelling technical presentation at the LLVM conference . Despite these valuable resources, I didn’t found on the web in-depth descriptions or analyses from sources outside its creators. This motivates me to propose this independent perspective on Mojo.

About the author of this note

I study turbulence and instabilities in fluids influenced by density differences (like the oceans and the atmosphere, but also air in heated rooms). In our group, we use mostly experiments (in the Coriolis platform ) and numerical simulations.

I have some experience with using Python and other languages (C++, Fortran, a bit of Julia, …) for scientific computing.

I am the creator of a project (called Fluiddyn) using Python for my field of study. I wrote and maintain few Python packages used for my research, like Fluidlab, Fluidimage, Fluidfft, Fluidsim, Snek5000, Fluidsimfoam, Formattex, Formatbibtex, etc. I also created Transonic , a package to ease the use of Pythran and other Python compilers.

I teach a bit, mostly about turbulence, instabilities, geophysical flows, Python and scientific computing (but only at a level for which Python is sufficient).

The development of Mojo started in September 2022. A first very early stage version was released on May 2023 only for online tries. Mojo became accessible for local use on individual computers only in September 2023. As of the current date, the lastest version is Mojo 0.6.0, which was released on December 2023. While still in its early stages, Mojo was used to build few impressive programs (for example very fast and portable matrix multiplications or Llama.mojo faster than llama.cpp ). Furthermore, both the language and its website have entered a phase that enables individuals to better understand what Mojo is going to become in the coming months and years. Note that this wasn’t the case just a few months ago, and articulating the essence of the project behind Mojo is clearly challenging.

Recall on programming languages categories

Before studying what Mojo is and will be, it’s beneficial to revisit some common categories of programming languages.

  • Interpreted versus compiled : Traditionally, languages were categorized as either interpreted (capable of direct execution with an interpreter, bypassing compilation) or compiled (requiring the code to be processed by a compiler to generate an executable program, “ahead-of-time” compilation - ATO). The distinction between interpreted and compiled languages often hinges on usage rather than inherent language characteristics. For instance, there are Python “compilers” and tools like Jupyter enable C++ interpretation. Additionally, many modern interpreters incorporate a compiler that generates machine code dynamically through Just-In-Time (JIT) compilation during execution. Notably, CPython, the reference Python implementation, historically lacked JIT compilation, but there are plans to introduce it in CPython 3.13 next year. Other Python implementations, like PyPy and GraalPy, use JIT compilation.

  • Static versus dynamic : Alternatively, languages can be characterized by their degree of dynamism. Dynamical features are about the ability to modify aspects of a program during its execution. Static typing implies associating variables with a specific type at compile-time, while dynamic typing means that variables (or ‘names’) can point towards objects of any type. Additional dynamical features may include the capacity to add or change methods for types/objects and even modify built-in functions. Python is renowned for its dynamism, yet it also supports static coding practices, featuring type stability where variables consistently point to objects of the same type, along with the option for type annotations. Examples of dynamic languages include Julia and R, whereas C, C++, Rust, and Swift are representative of static languages.

For completeness, we should also mention the notion of strong or weak type system. Python is strongly typed so that 1 + "2" raises an error.

We will see that Mojo cannot easily be classified with these categories. Mojo can be interpreted (with JIT compilation) or compiled to machine code. Moreover, Mojo is a static language but with dynamical capacities.

Warnings: still closed-source and very young

Before delving into discussions about programming languages and Mojo, two crucial aspects merit attention.

Firstly, it’s essential to note that Mojo is currently a closed-source project under the guidance of the Modular company. Their goal is to monetize artificial intelligence (AI) by significantly enhancing the technological framework in this domain. The building blocks of this strategy are (i) a new AI Engine called MAX (something like TensorFlow and PyTorch, but somehow compatible with these solutions) and (ii) a new programming language — Mojo. While Modular asserts that Mojo is not intended to be a commercial “product” and write that they “expect to open-source Mojo progressively over time as it continues to mature” [ 1 ] , the project remains closed-source at present. This critical aspect will be revisited in more detail later.

Secondly, it’s important to acknowledge that Mojo is still in its early stages and, in my opinion, not yet ready for being used outside of Modular. The creators of Mojo focussed on the core of the language and on performance.

Building a new programming language

While old programming languages like Python, C, C++, Java or Javascript, continue to dominate the landscape [ 2 ] [ 3 ] , the field of applied research in programming languages has witnessed remarkable activity in recent years. A wave of innovation has given rise to the introduction of new programming languages (to name a few, Zig, Vlang, etc.). Besides these veterans and newcomers, there are also few grown up languages (as Go, Rust, Julia and Swift) which gathered active communities around them.

In this note, the focus will predominantly be on Rust, Julia, and Swift. Rust, backed by the Mozilla Foundation, originated in 2006 and was publicly introduced in 2010, bringing noteworthy innovations compared to C++, particularly about safety with its borrow checker. This systems language has garnered success and found numerous applications, such as being employed in the development of Firefox. Despite its nice qualities, Rust is known for its steep learning curve, potentially making it less suitable for rapid prototyping in the scientific field. Julia’s development commenced in 2009, with the language officially launched in 2012 — over a decade ago. Over the years, Julia has matured and found its niche in intensive numerical computing applications, where it excels. Swift, Apple’s latest language, began development in 2010, with the first version released in 2014. Swift transitioned to an open-source model in 2015.

Starting a new programming language in 2023 is kind of a bold idea. In a landscape dominated by robust and mature choices, the competition among programming languages is formidable. A new language not only needs to introduce novel features and advantages over its direct competitors but also must be sufficiently good in various other aspects. The benefits of adopting the new language should outweigh the costs associated with using less the established language. Moreover, in this field, practicality often beats purity. The case of Julia versus Python is very interesting. Julia has clear advantages compared to Python for the field of scientific computing, in particular better performance and foundation, avoiding the “two languages problem”. However, Python is good enough, has other advantages and is evolving fast enough so that there is no significant shift towards Julia [ 4 ] .

Creating and establishing a new programming language is a monumental task. While considerable resources are naturally allocated to designing the language and developing its interpreter/compiler, one also need to consider other aspects including community building, tools for developers, packaging, libraries, documentation, etc.

Let us also note that language creation, building and evolutions are slow processes. These human constructs are so complex that the typical time scale is more years than months. In the cases of Rust, Julia, or Swift, several years elapsed between the initiation of the projects and their first public releases. The Mojo team, however, opted for an early release strategy, initiating their project’s public presence swiftly. Despite this, they are still in a fast and closed-source development mode with a small and coherent team. The impressive progress achieved in just over a year sparks curiosity about the future trajectory of the project.

Why Mojo can be successful

Why should we care about this just born fancy programming language? In my humble opinion, compelling reasons suggest Mojo could emerge as one of the prominent languages in the coming years:

  • Mojo is an answer to a real suboptimal state for computing (scientific and AI) dominated by languages with clear weaknesses (of course Python and C++, but also Julia and Rust). It would be a net improvement to have a new language with a better equilibrium between usability/performance/safety, with JIT/OAT compilation capacities and a nice learning curve, especially for individuals familiar with Python.

  • Mojo is grounded in a great intuition: a static, safe language with strong dynamic capacities and seamless integration with Python.

  • Mojo is led by very smart and renowned people, in particular Christ Lattner , the “co-founder of LLVM, Clang compiler, MLIR compiler infrastructure and the Swift programming language” (taken from his Wikipedia page). His impressive track record in successful and significant open-source projects adds a substantial layer of credibility. While other accomplished individuals contribute to Mojo’s creation, Chris Lattner’s remarkable CV stands out.

  • Mojo has very solid technical underpinnings, LLVM and MLIR, as later discussed. “Mojo is the first major language designed expressly for MLIR” [ 5 ] .

  • Mojo seems to have a solid and long term founding, backed by a serious company, with partnerships with Amazon Web Services (AWS) and NVidia .

The motivations driving the creation of Mojo are described in particular in the Why Mojo page . It is a lot about fixing the technological stack used in AI, dominated in particular by Python and C++. This positions Mojo as a fresh attempt to resolve the longstanding “two languages problem”, a challenge that has also been a primary focus for Julia. However, the approaches taken by Julia and Mojo to tackle this issue differ significantly, both in terms of technological essence (to be discussed later) and in their relationship with Python. In a somewhat provocative manner, Julia and its community are perceived as being “against Python”, while Mojo aims to become a new member of the Python family.

When Julia was conceived in 2009, Python’s footprint in scientific computing was relatively modest. Numpy was only introduced in 2006, and Python 2.7 wasn’t released until 2010. During this period, Matlab held a more dominant position. Consequently, the design of Julia leaned towards Matlab rather than aligning closely with Python-Numpy. Moreover, it is not convenient to use Julia to build packages usable from Python (or R by the way). The “one language for everything” approach is not very cooperative by nature. In contrast, the pragmatic strategy of employing distinct languages for different tasks has proven highly effective in constructing a robust scientific Python ecosystem. This ecosystem leverages languages such as C, Fortran, C++, and now Rust [ 6 ] in the background.

While Julia is great and has a great ecosystem in its niche — intensive numerical computing — it tends to be somewhat isolated. For the vast community of Python users and developers of Python packages, it is not so appealing to invest time on Julia.

Mojo’s alternative strategy about its relationship with Python appears quite reasonable. Introducing a companion and complementary language could find a warm reception within the Python community. Given the current dominance and momentum of Python (see the next section), as well as the inherent inertia in language dynamics, it is a very serious advantage for Mojo for the next decade.

Projects about extending what is possible with Python

To better understand Mojo, it’s beneficial to clarify what it is not, by exploring a few projects aimed at enhancing Python and addressing its weaknesses.

  • PyPy and GraalPy : These projects are faster alternative implementations of Python. However, their adoption is limited because they face challenges in accelerating packages that rely on the CPython C API, such as Numpy, Matplotlib, Pandas, scikit-learn, and others.

  • Fixing the Python C API : Efforts are underway to resolve this limitation and enhance the usability of alternative Python implementations. These include the introduction of the new HPy C API and a more ambitious, long-term initiative aimed at improving the CPython C API .

  • CPython Core Developments : The CPython core developers are actively engaged in initiatives to enhance the performance of CPython through projects such as no-gil, subinterpreters , and Faster CPython. CPython 3.13, which will be usable at the end of 2024, should have the GIL removed and a JIT compiler based on the Copy & Patch approach .

  • Python compilers : Various Python compilers, such as Pythran, Numba, and Mypyc, have been developed to accelerate specific (static) subsets of Python, with some extending support to Numpy.

  • GPU and parallel computing : Innovative projects like Codon and Taichi introduce Domain-Specific Languages (DSLs) within the Python environment, tailored for GPU and parallel computing.

Mojo distinguishes itself from these projects by being a truly independent language, rather than falling into the category of Python enhancements or alternative implementations.

Mojo==Python++? Actually something completely different

Mojo website states that a long term goal of Mojo is to become a superset of Python , meaning that most Python programs should run without modifications. I’m not so optimistic about this but for me it is not so important. To run Python code, we anyway have other good Python interpreters. I consider that some Python features are not so useful for a project like Mojo, for example supporting the inspect module (for introspection), monkey patching of whatever (even the language builtins) or the CPython C API.

Anyway, it is important to realize that current Mojo is completely different from Python. There are few common builtin functions ( print , len , range , slice , …) and the syntax is largely compatible (imports, indexing, slicing, loops, function def, contexts, try/except, async/await, even struct definition with dunder methods, …). As already written, Mojo can also be “interpreted” and has a REPL (which can be started with the command mojo ). But some very important Python builtin types are missing (like str , int , float , list , tuple and dict ) and nearly no Python standard library is available. Moreover, more deeply and importantly, the semantic of the language is very different. For example, Mojo variables are much more like C variables than like Python variables: a name in Mojo is attached to an object. For example

from memory.unsafe import Pointer

def print_pointer(ptr: Pointer):
    print(ptr.__as_index())

def main():
    a = 1
    p1 = Pointer.address_of(a)
    print_pointer(p1)

    a = 2
    p2 = Pointer.address_of(a)
    print_pointer(p2)

    # a = "mojo"  # error: cannot implicitly convert 'StringLiteral' value to 'Int' in assignment

prints

140728977102328
140728977102328

meaning that there is only one integer variable which has been modified inplace with the statement a = 2 . In contrast, the equivalent Python code, something like,

a = 1
print(id(a))
a = 2
print(id(a))
a = "python"  # valid

prints

140163769254128
140163769254160

such that id(2) - id(1) is 32. The name (the reference) a first points towards the int object 1 . The statement a = 2 modifies the reference (the name a ) and not the integer object.

In Python, references are everywhere (the names are references, elements in a list/tuple are references, function arguments are passed as references). It does not work like that with Mojo, which has strong consequences. For example, in Python a = "py"; b = a creates two references pointing towards one object ( "py" ). In contrast, a = "mojo"; b = a creates two different objects at two different locations in the memory so that

b = "mojo"
p = Pointer.address_of(b)
print_pointer(p)

c = b  # <- this really copies the String object "mojo"
p = Pointer.address_of(c)
print_pointer(p)

prints something like

140720822767840
140720822767856

The contrast becomes evident in these examples as Mojo provides developers with a more direct engagement with objects in memory. Unlike Python and Julia, Mojo does not use reference counting and a garbage collector. Instead, memory management, defining the “lifetime” of objects, is automatically handled by a borrow checker, like in Rust. Nevertheless, Mojo also offers the flexibility to write code reminiscent of C, employing pointers and explicit allocation and deallocation of memory. In conclusion, it becomes apparent that Mojo is primarily a novel static language drawing inspiration from C++, Rust and Swift. This language is crafted for safe system programming.

References and dynamism in Mojo?

It is very surprizing to read that such language with so different basic semantics (for example the meaning of the equal operator) will become a superset of Python. However, one can implement in Mojo objects acting like the Python references. There is actually already an important type in Mojo called object (the default type for arguments without type annotation) and this code acts like in Python:

def modify(a):
    # argument given by copy in Mojo `def` but one can modify the referenced list
    a[0] = 1

def main():
    a = object([0])
    b = a  # <- the reference is copied but not the pointed list

    print(a)  # prints [0]
    modify(a)
    print(a)  # prints [1]
    print(b)  # prints [1]

Note that this is pure Mojo code that does not use the Python interpreter. Finally, it is also possible to implement a reference object (using reference counting) in Mojo. I don’t know if reference counting is used internally for object (remember that Mojo is still close source) or if the borrow checker is enough to mimic Python behavior without reference counting and a garbage collector. Anyway, since a name is associated in Mojo with an object, mimicking Python requires reference objects. It is interesting to see that both behaviors can be obtained in the same language.

Builtin references and mutable references

A Mojo proposal indicates that it will be possible to create references with two new keywords, ref and mutref .

More complexity for more control and strict static code

As mentioned earlier, Mojo draws significant influence from static languages such as C++, Rust, and Swift. This influence introduces a level of complexity that is entirely absent from Python.

Three different kinds of variables, immutability at the level of the variable

In Python, the distinction between immutable and mutable objects is based on their types. In Mojo, similar to other static languages, variables can be explicitly marked as either immutable ( let ) or mutable ( var ). For instance, one can declare an immutable String in Mojo, even though Mojo’s Strings are inherently mutable, with syntax like let s = String("Mojo") .

Additionally, Mojo introduces the alias keyword to define compile-time variables. Note that one can run whatever valid Mojo code at compile-time for example:

alias PI = 3.141592653589793
alias TAU = 2 * PI
alias my_alias = my_function_executed_at_compile_time()

Two keywords for function definition ( def and fn )

Unlike Python, Mojo utilizes two keywords ( def and fn ) for defining functions. It’s crucial to grasp that both keywords define the same function objects. It is not at all “ def for Python-like functions and fn for static functions”. The difference in keywords is only about default argument passing mechanics and strictness in terms of variable declaration. By default, arguments are copied for def and borrowed (immutable reference) for fn . With fn , explicit specification of argument types, parameters, and the return value is mandatory. For def , the default argument type is object , representing a particular Mojo type designed for dynamic code.

Better control of argument passing mechanism

Beside the difference of default mechanism between def and fn , there are three keywords to modify how arguments are passed to functions:

  • borrowed : immutable reference,

  • inout : mutable reference,

  • owned : object given to the function (used with a deference operator ^ at the function call).

Two times of execution and two types of arguments

It is interesting to note that alias are not like C macros (i.e. leading to simple code replacements). In Mojo, there are really two times of execution: compile-time and runtime. Functions and structures can be parametrized, meaning that they can have both standard runtime arguments and compile-time arguments (called “parameters” in Mojo). For example, here, a is a parameter and b is an argument:

fn bar[a: Int](b: Int):
    print("bar[a: Int](b: Int)")

This is quite similar to C++ or Rust features but it is interesting to note that one can run any Mojo code at compile-time. The decorator parameter can be used to define compile-time if and functions:

@parameter
if ...:
    ...

@parameter
fn my_closure[size: Int]():
    ...

Two kinds of user defined types: struct and class (not yet available)

While Python employs the class keyword for defining user-defined types, this specific kind of type has not been implemented in Mojo as of now. In Python, the __slots__ dunder class variable can be utilized to restrict the dynamism of the type. Conversely, in Mojo, one can define a struct , similar to C’s struct . The behavior of types in Mojo is controlled through “dunder” special methods, mirroring the approach used in Python. With no support for inheritance, composition is favored in Mojo, aligning with the approach seen in Rust. Additionally, Mojo 0.6.0 introduces basic support for Traits (a set of requirements for a type).

Ability to define lifetime behavior of struct

Developers in Mojo have precise control over the lifetime behavior of defined types by choosing to implement or omit “dunder” methods. Initialization is managed using __init__ , copying is controlled with __copyinit__ (“deep copy”), and “move” operations (“shallow copy”) are handled through __movecopy__ .

Overloading / multiple dispatch

Python leans towards duck typing and potential type checks at runtime ( isinstance ) to allow functions to handle objects with different types. In contrast, Mojo supports overloading (like C++ or Julia), with parameters and runtime arguments.

Comments on few current and future Mojo features

Compile-time metaprogramming

Metaprogramming is about code that deals with code. A language can have metaprogramming capacities which help a developer to write code to understand/modify other pieces of code. A section in Mojo documentation nicely compares and discusses different metaprogramming strategies in different languages.

For example, Python has modules in its standard library to work with Python code, in particular inspect and ast and a mechanism to potentially replace functions and classes (the decorators). In Transonic , we use these features to isolate useful code, produce new files and compile them (at compile time) and then replace functions by their compiled and optimized equivalents at runtime.

Julia has another powerful metaprogramming concept called macro . Julia macros operate similarly to functions but are executed during code parsing. This resembles Python decorators but with the distinction that Julia macros can take any expression as input, not just function or class definitions. Additionally, they act at parse time on code rather than on objects.

Interestingly, Mojo has (and will have more) compile-time metaprogramming capacities . With current Mojo version (0.6.0), it is a lot about (i) parametrized functions and structures with compile-time arguments (called “parameters” in Mojo), (ii) running arbitrary Mojo code (at compile-time) to fix parameter values and (iii) using conditions based on parameter values.

Moreover, Mojo will have “Static decorators [which] are functions executed at compile-time with the capability to inspect and modify the IR” [ 7 ] . While somewhat akin to Julia or Rust macros, this feature operates at a lower level, manipulating the MLIR intermediate representation instead of the source code.

A high level language for the MLIR compiler framework

What is MLIR? From its Wikipedia page

MLIR ( Multi-Level Intermediate Representation ) is a unifying software framework for compiler development. MLIR can make optimal use of a variety of computing platforms.

Intermediate representations (IR) are languages between the programming languages for the humans and the machine code of processing units. Compilers commonly perform optimizations at the IR level. From what I understand, MLIR seems to be a super IR framework with different “dialects” and different targets (the types of processing units, like CPU, GPU, …). As the use of diverse accelerators and exotic processing units becomes more prevalent, MLIR is anticipated to gain increasing importance. MLIR is very new and there is no high level language designed to use it. One of the goal of Mojo creators is to create such language: “Mojo is the first major language designed expressly for MLIR” [ 5 ] . A dedicated Mojo tutorial explores this feature.

Builtin Python integration

It’s very easy to run from Mojo Python code using the Python interpreter in particular in order to use any Python packages. After importing the package with something like,

from python import Python

np = Python.import_module("numpy")

(instead of import numpy as np ), one can just write Python in Mojo! Since Mojo uses CPython under the hood, executing Python in Mojo in this way is not faster than with CPython!

As expected given the current state of Mojo, there are things that do not work, for example calling a Python function with a keyword argument, which is quite annoying for some packages, for example Pandas! Also it is still quite difficult to convert Python objects into Mojo objects. I guess this will improve quickly.

C interoperability

Mojo should be able to use C libraries seamlessly just by importing a function as from "math.h" import cos . For scientific computing, we will need to have packages similar to mpi4py or h5py in Mojo, to use MPI and hdf5 respectively.

What is missing in Mojo to be really usable for scientific computing?

Open-source nature

Beyond technical considerations, the issue of Mojo’s open-source nature demands attention. While Mojo remains closed-source, building a robust community outside Modular poses a considerable challenge. To foster wider adoption, it is crucial for Modular to transition Mojo to an open-source model once it reaches a more mature state. Open-sourcing Mojo and establishing a transparent governance structure for the project are pivotal steps that, despite its significant technical merits, will be essential for Mojo to realize its full potential and achieve widespread success.

Important

After the first version of this note, some questions on Mojo Discord and an issue on Mojo issue tracker , the statement in the FAQ commented in the next paragraph has been modified! To the question Will Mojo be open-sourced? , Modular now clearly answers “We expect to open-source Mojo progressively over time as it continues to mature. Mojo is still young, so we will continue to incubate it within Modular until more of its internal architecture is fleshed out.”

It’s worth noting that the statement in the FAQ regarding open-sourcing, “Over time we expect to open-source core parts of Mojo, such as the standard library”, lacks absolute clarity. The ambiguity arises from the phrase “core parts”, leaving it uncertain whether certain essential components of Mojo will remain closed-source. While we await further details, a clearer statement like “the core parts of Mojo” would have provided more reassurance. The prospect of some “Mojo extensions” remaining closed-source is acceptable, but if any core component stays proprietary, it introduces a dependency and uncertainty for users and the community. In my perspective, the Python community may be hesitant to adopt Mojo if a closed-source element is required. While acknowledging the need for Mojo to mature as a closed-source project, there is a corresponding necessity for Modular’s plans to be clarified. I don’t see how Mojo could really compete with widely adopted open-source languages if the plan is as suggested in the FAQ (i.e. keeping in the long term core parts of Mojo proprietary).

Core of the static language

I first mention few items listed in Mojo roadmap as priorities.

These planned enhancements are expected to be substantially implemented in the coming months, leading to significant changes in the language. Therefore we will need to revisit Mojo in Spring 2024 to better evaluate its evolution and potential.

A bit more high level Python

I think that Python developers need at least Mojo types mimicking the Python str , list and dict . Note that homogeneous list and dict (and other Python stdlib API) are being implemented in a third-party repository .

Interoperability with Python

  • Ability to call Python functions with keyword arguments (very common for APIs of Python packages, see for example Pandas/Polar)

  • More Python to Mojo conversions (for example Numpy array to Mojo Tensor), without the need of writing MLIR code.

Packaging

Mojo needs a good packaging solution (maybe through compatibility with PiPY and/or Anaconda.org?), associated with a nice tool like pdm , Pixi or Cargo .

Production of Python extension from Mojo code

Enabling the compilation of Python extensions directly from Mojo code, perhaps through a @export decorator and a command like mojo build-py-ext , appears to be a feasible future prospect. Using the new HPy API would be a logical choice. Notably, this potential feature is currently absent from the Mojo website. Nevertheless, gaining insights from the Mojo team regarding their perspective on this feature would be interesting, as it is crucial for enhancing adoption within the Python community.

Conclusions

As we’ve explored, one distinctive aspect of Mojo is its capacity to allow developers to write static, safe code akin to Rust. Simultaneously, Mojo supports dynamic code with the potential absence of typing annotations, similar to Python. While both aspects are still evolving and set to improve in the coming months/years, it’s crucial to recognize that even if Mojo aims to become a superset of Python, it should not be simply regarded as “Python++”. Instead, it is more accurate to view Mojo as a new, modern static language strongly influenced by C++, Rust and Swift, emphasizing performance, portability, and the ability to write generic code for exotic hardware. Only then can one appreciate that Mojo also offers interpretability with JIT compilation, features built-in capabilities for dynamically typed code, and the potential to become a quasi superset of Python.

We observe that Mojo shares similarities with and deviates significantly from Cython, a language that acts as a superset of Python with C capabilities. Unlike Mojo, Cython code necessitates transpilation to C and cannot operate independently of a Python interpreter. Cython is widely adopted in numerous successful packages within the numerical Python stack, such as scikit-learn. However, its usage remains confined to this specialized niche application. If it becomes possible to create Python extensions from Mojo code, a distinctive application for Mojo could be as a compelling alternative to Cython.

The current trajectory of Mojo suggests it is being crafted for long-term success. Modular envisions building a powerful programming language designed to thrive over the coming decades, positioning Mojo as a formidable contender against established, mature, and fully open-source languages. However, uncertainties surrounding the future licensing of the Mojo interpreter/compiler, particularly the potential retention of core components as closed-source, raise concerns about the compatibility of these ambitions.

Important

As already written, after the first version of the note, Modular employees and the Mojo FAQ are now clear and coherent: they claim that all Mojo will progressively be made open-source . I did not amend the conclusions because the open-source question is still valid but I think it is reasonable to anticipate a fully open-source Mojo in the next few years.

The Mojo team is on track to deliver an exceptional language for high-performance computing in the next few months. Given the remarkable progress witnessed so far, it’s reasonable to anticipate that by the end of 2024, Mojo will be technically robust, featuring improved lifetime management, Rust-like Enum, Python compatibility, and more.

The pivotal decision about whether the core of Mojo becomes fully open-source holds significant consequences. If fully open-source, Mojo could have a transformative impact, especially within the Python community. This scenario would require investment from the Mojo team to enable the generation of Python extensions from Mojo code. The resulting open-source momentum could rapidly enhance the Mojo ecosystem, fostering the development of numerous new libraries. On the contrary, if the core of Mojo remains partly closed-source, adoption may be subdued, with many opting for alternative open-source solutions. It is noteworthy that when I introduced Mojo to experienced and highly qualified developers, the initial response often revolved around its closed-source status and the uncertainties regarding its future open-source status.

I tend to be optimistic about the future open-source nature of Mojo because this is in the interest of Mojo, and thereby of Modular. Mojo is still a growing baby bird in its closed-source nest. The hope is that, in the coming years, Mojo will spread its wings, soaring alongside its renowned open-source counterparts in the rising currents of collaborative development.

In conclusion, I would like to share my highly personal impression of Mojo. As a Python developer with experience in static languages and high performance computing, the experience of using and exploring Mojo has been both delightful and intellectually stimulating. It gives me a sense of being at home, on holiday, and having superpowers all at once. On the other hand, since it’s not easy to learn to drive with a space shuttle, it’s debatable whether Mojo should be put in everyone’s hands.