The Mojo programming language is new. In fact, it’s still under development. At the end of 2023, the latest milestone release is version 0.6.0. There is no word on when the first full increment release will go GA, and the language’s final feature set is still a work in progress.
However, even at this early state of inception, the Mojo programming language has already demonstrated the ability to outperform other major languages including Python, C and Rust.
Modular’s Mojo programming language is poised to revolutionize software development in the AI space. For those who want to stay ahead of the next big machine learning trend, now is the right time to learn how to code your first Mojo program.
Learn the Mojo programming language fundamentals
In this Mojo tutorial, my plan is to help you build your first Mojo program.
I’m not talking about building a simple Hello World program in Mojo, although that is on the docket. My goal is to show you a mildly sophisticated Mojo program that will accomplish the following:
- Declare variables, both implicitly and statically.
- Use methods featuring both fn and def semantics.
- Examine how conditional statements in Mojo work.
- Introduce some semantics of exception handling on Mojo.
- Examine the syntax of Mojo looping structures.
- Invoke the Python API from Mojo code.
- Convert PythonObjects to text.
- Convert text Strings to integers in Mojo.
Mojo number guessing game
All of this will be achieved through the development of a simple, Mojo-based number guesser game.
The complete product
One of my philosophies is that it’s important to have some idea of where you’re going before beginning your coding journey. So, I’m going to put the cart before the horse a little bit and show you the full Mojo code for the example we are about to build before we actually build it. Here it is:
The rest of this tutorial will be the incremental building of this Mojo app from the ground up.
This tutorial assumes you already have installed Visual Studio, along with the Mojo runtime and the Mojo Visual Studio plugins.
Visual Studio isn’t required, as you can compile the file and run it using the utilities that come as part of the Mojo install. Still, VSCode will certainly make things easier for you.
This Mojo tutorial also assumes you have opened Visual Studio up in a clean, empty folder in which to store the code used in this Mojo example.
Create your first Mojo file 🔥
To begin, create a new file in Visual Studio named number_guesser.mojo.
If you want, you can use the flame emoji as the file extension instead of the .mojo extension. The Mojo plugins in Visual Studio recognize .🔥 (“dot-flame”) as well as .mojo.
The ability to use the flame emoji as a file extension is a fun little feature that the Mojo creators put in to reinforce the idea that Mojo is a little bit different from all of the other programming languages out there.
Hello World in Mojo
Add the following code to your new file to get the requisite Hello World Mojo application out of the way:
fn main(): print("Hello Mojo World!")
Run the program and Hello Mojo World prints to the console.
Mojo vs. Python at first glance
Python developers might notice many similarities, and a couple of big differences, between Mojo and Python’s syntax.
The similarities that will make Python developers feel at ease include the following:
- Mojo comes with a comprehensive set of built-in functions, such as print.
- Blocks of code are delineated with a combination of the colon and indentation.
- Mojo uses four spaces for indentation; tabs are verboten.
- Lines of code do not require a semi-colon at the end.
- Text can be placed in both single quotes and double quotes.
The three big differences between Mojo and Python are:
- The fn preamble before the Mojo method is new. Python developers are used to seeing def.
- Commands must go inside a method. Mojo does not allow unguarded statements that reside outside of a method to execute.
- Python’s cryptic if name == main syntax is replaced with a proper main method.
fn vs. def in Mojo
Python developers will be happy to know that they can actually change fn to def in this Hello World example and the code would work just fine.
Mojo is a superset of Python. Mojo completely supports Python code. That means yes, Mojo supports the def preamble.
The difference between these keywords is that if you use fn, you commit to the stricter coding requirements that Mojo demands. Choose def, and you can write any dynamically typed Python code you like.
No unguarded code in Mojo
Given its roots as a scripting language, Python does not require statements to be packaged within a method. Any code that is written in the top-level scope of a file will be executed from top to bottom, both when a file is executed or when it is imported.
This is a pretty significant Python security flaw that remains unsolved, even when the language’s cryptic name equals main construct is used.
In Mojo, variables can be declared in the top-level scope, but all executable statement must go within a method.
Furthermore, to be consistent with all C-based programming languages, Mojo uses a main method to represent the entry-point of an application. The name equals main construct has been eliminated.
How to declare variables in Mojo
We are building a number guessing game, so our program demands two variables:
- A variable named the_guess.
- A variable named the_magic_number.
Note: An experienced developer wouldn’t prepend a variable with the, but since this is intended as a novice developer’s first program, it is permissible as it will help enhance the code’s readability. There’s no need to send me any shade on these variable name choices.
To declare a local variable inside a Mojo method, follow these steps:
- Use the var keyword to indicate a variable declaration is happening.
- Provide a name for the variable.
- Optionally assign the variable a value.
For constants, you use the let keyword. In this iteration of our application, the magic number will be constant, so we will declare it with let.
Our updated method, after the Hello World print statement is removed, looks as follows:
fn main(): let the_magic_number = 7 var the_guess = 5
Static vs. implicit typing
You may have heard that Mojo is statically typed, which contrasts staunchly with Python.
You also may be wondering why we specified no data type when declaring these variables. After all, most statically typed languages require you to indicate if you are using a float or an integer or a String or a Boolean.
Much like Java, in Mojo variables local to a method can have their type inferred, which relieves the developer from explicitly providing a type name. However, explicit typing is allowed and would look as follows:
fn main(): let the_magic_number : Int = 7 var the_guess : Int = 5
Mojo Int vs. Python’s int
Python developers might notice that Int has a leading uppercase letter, while in Python it is all lower-case.
Python’s lower-case int does some interesting stuff that might work counter to some of the performance interests of Mojo. The different capitalization provides the Mojo language architects some wiggle-room as they figure out how to handle some of Python’s whole-number peculiarities.
Conditional logic in Mojo
We need to decide if the_guess is higher, lower or equal to the_magic_number, and that requires conditional statements.
Conditional logic doesn’t vary much from one programming language to another. After all, there are only so many ways to construct an if..else statement.
Mojo follows the familiar syntax of Python for conditional statements, including elif along with the if and else keywords.
fn main(): let the_magic_number : Int = 7 var the_guess : Int = 5 if the_guess < the_magic_number: print(the_guess + " is too low!"); elif the_guess > theMagicNumber: print(the_guess + " is too high!"); else print("You guessed correct!");
Run the application in its current state and you will get the following output:
5 is too low!
You will also get a few warning messages, as Mojo does not like the fact that the guess variable does not change throughout the course of the program.
let vs. var in Mojo
Data that is marked as constant and unchanging is handled much differently from data that is variable. The compiler can apply many low-level optimizations when it knows a given value is immutable.
In Mojo, a constant is identified through the use of let rather than var. When we run our program, the compiler tells us we should use let for the_guess since its value does change. We can dismiss this warning for now, as future iterations of our program will have the_guess live up to its variable moniker.
How to use Python in Mojo
Rather than hard coding the_guess, we should obtain it from the user.
This requires user input features that are not yet part of the Mojo API. However, they are available from the Python APIs, which is exactly what we’ll use.
To access Python functions inside our Mojo code, we must add the following import at the top of the file:
from python import Python as impy
We then must import the function we need and maintain a reference to the Python component in our code:
let py_input = impy.import_module("builtins").input
How to get user input in Python
Now we can use the Python input function in our Mojo code just as we would in a normal Python program.
However, a resource pulled from Python is returned as a PythonObject. In our code, we explicitly type the data returned from the Python input function as a PythonObject to make this fact clear:
let input : PythonObject = py_input()
Mojo gets a little nervous when you call on objects from external libraries, so we need to add the raises keyword to the main method declaration to indicate that this method might now raise an unexpected exception at runtime:
fn main() raises:
Convert a String to an Int in Mojo
The PythonObject implements the Stringable Mojo trait, so we can easily access the text-based value the PythonObject represents:
let text_input : String = input.__str__() #convert PythonObject to String
A cleaner option is to just pass the input to the str() function to get back a String:
let text_input : String = str(input) #convert PythonObject to String
We can then convert the String to an Int with the atol method:
the_guess = atol(text_input) #convert Mojo String to int
While loops in the Mojo programming language
To finish off our application, we embed the logic for garnering input and evaluating the guess inside a while loop that checks if the correct number was chosen:
while the_magic_number != the_guess:
Pepper in a few print statements to provide feedback to the user, and you’ve completed your first Mojo program!
from python import Python as impy fn main() raises: let py_input = impy.import_module("builtins").input let the_magic_number : Int = 7 var the_guess : Int = 5 print("Guess a number between 1 and 10") while the_magic_number != the_guess: let input : PythonObject = py_input() let text_input : String = str(input) #PythonObject to String the_guess = atol(text_input) #convert String to int in Mojo print("You guessed: " + str(the_guess)) if the_guess < the_magic_number: print(the_guess + " is too low!") elif the_guess > theMagicNumber: print(the_guess + " is too high!") else print("You guessed correct!");)
Output of your first Mojo program
When the code runs, the output is as follows:
scrumtuous@mojo-tutorial:~/ mojo number_guesser.mojo Guess a number between 1 and 10 2 You guessed: 2 Guess higher! 9 You guessed: 9 Guess lower! 8 You guessed: 8 Guess lower! 5 You guessed: 5 Guess higher! 7 You guessed: 7 You guessed correct!
Now your first Mojo application is complete
And that’s it! That’s how easy it is to program in Mojo!
For Python developers, there’s really nothing too difficult to wrap your head around. And developers who come to the world of artificial intelligence and machine learning from languages including Java, Rust and C octothorpe will enjoy the statically typed nature of the Mojo language, not to mention its main method.
There really is something here in this new Mojo programming language for everyone in the computer programming world to love.