🔥 Mojo Tutorial 1

Install, setup, basics

Mojo is a programming language developed for the MLIR compiler framework that provides a unified programming framework for software development, especially in the field of artificial intelligence. (from Wiki)

Mojo is a new programming language that bridges the gap between research and production by combining Python syntax and ecosystem with systems programming and metaprogramming features. Mojo is still young, but it is designed to become a superset of Python over time. (from github)

Introduction

This will be a series of tutorials and most of the examples are from official Mojo tutorials.
https://docs.modular.com/mojo/

Install

  1. It is easy to install on your PC and supports Mac, Linux and Windows. Simply follow the instruction on the offical website to install it. https://www.modular.com/mojo

  2. I highly recommend to use VSCODE for development. Mojo extension is available on VSCODE.

Hello World

1
2
3
4
5
6
7
8
9
10
let hello = "hello world"

fn main():
print("hello world")

# to run it
# in command line:
# mojo main.mojo

# output: hello world

You can also type mojo in your terminal to enter REPL session.

Build an executable binary

  • create executable

    1
    mojo build main.mojo
  • run executable

    1
    2
    3
    ./main

    outout: hello world

Basics

Mojo is a complied language and Mojo code can be ahead-of-time (AOT) or just-in-time (JIT) compiled.

fn keyword is the function definition in Mojo. var defines a mutable variable. let creates an immutable value.

1
2
3
4
5
6
fn main():
var x: Int = 1
let y: Int = 2
x += 1
print(x)
print(y)

Int is declared as the type for function arguments and return type.

1
2
3
4
5
fn add(x: Int, y: Int) -> Int:
return x + y

z = add(1, 2)
print(z) # 3

Functions also takes default values.

1
2
3
4
5
6
7
8
9
10
fn pow(base: Int, exp: Int = 2) -> Int:
return base ** exp

# Uses default value for `exp`
z = pow(3)
print(z) #9

# Uses keyword argument names (with order reversed)
z = pow(exp=3, base=2)
print(z) #8

Function Argument mutability and ownership
Function arguments are immutable references by defualt. This ensures memory safe and avoiding a copy.
This default behavior is called borrowing and can be explicitly defined using keyword borrowed.

1
2
fn add(borrowed x: Int, borrowed y: Int) -> Int:
return x + y

If you want the arguments to be modified within the function. Use keyword inout for arguments declaration.
Changes made in the function are also visible outside the function.

1
2
3
4
5
6
7
8
9
10
11
12
fn add_inout(inout x: Int, inout y: Int) -> Int:
x += 1
y += 1
return x + y

fn main():
var a = 1
var b = 2
let c = add_inout(a, b)
print(a) # 2
print(b) # 3
print(c) # 5

owned keyword provides the function with full ownership of the value. ‵text‵ is a copy of original a and can be modified without affecting a.

1
2
3
4
5
6
7
8
9
fn set_fire(owned text: String) -> String:
text += "🔥"
return text

fn main():
let a: String = "mojo"
let b = set_fire(a)
print(a) # mojo
print(b) # mojo🔥

If you want to give the function ownership of a value and do not want to make a copy (memory efficient). Use ^ transfer operator.
The transfer operator will destroy local variable, in this case a. Any later operations that use a will cause compiler errors.

1
2
3
4
5
6
7
8
9
fn set_fire(owned text: String) -> String:
text += "🔥"
return text

fn main():
let a: String = "mojo"
let b = set_fire(a^)
print(a) # error, a no longer exists
print(b) # mojo🔥

Struct in Mojo
A struct is similar to class. It supports method, filed, overloading, etc.
Mojo structs are completely static—they are bound at compile-time.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct Base:
var a: Int
var b: Int

fn __init__(inout self, a: Int, b: Int):
self.a = a
self.b = b

fn print(self):
print(self.a, self.b)

fn main():
let obj = Base(1, 2)
obj.print() # 1 2

Python integration
Use Python Numpy modules in Mojo. If you encounter errors, this may help. https://github.com/modularml/mojo/issues/551

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from python import Python

var np: PythonObject = None

fn main():
try:
np = Python.import_module("numpy")
let ar = np.arange(15).reshape(3, 5)
print(ar)
print(ar.shape)
except:
pass

# [[ 0 1 2 3 4]
# [ 5 6 7 8 9]
# [10 11 12 13 14]]
# (3, 5)

References

Author

Joe Chu

Posted on

2023-11-14

Updated on

2024-03-24

Licensed under

Comments