Skip to content

Things that are different

The last chapter of the Miji showed you how much Mojo is similar to Python. In most situations, you can safely rely on your Python knowledge and experience to write Mojo code. This chapter continues to show you the differences between the two languages, so that you won't be surprised when you encounter error messages or strange results.

Data types

In previous chapter, we introduced common data types in Mojo and Python, such as int, float, str, list, tuple, set, and dict. In this chapter, we will focus on the differences (nuances) between these data types in Mojo and Python.

A table is better than hundreds of words. Let's first summarize the differences in the following table:

Python typeDefault Mojo typeBe careful that
intIntIntegers in Mojo has ranges. Be careful of overflow.
floatFloat64Almost same behaviors. You can safely use it.
strStringSimilar behaviors. Note that String in Mojo is rapidly evolving.
boolBoolSame.
listListElements in List in Mojo must be of the same data type.
tupleTupleVery similar, but you cannot iterate over a Tuple in Mojo.
setcollections.SetElements in Set in Mojo must be of the same data type.
dictcollections.DictKeys and values in Dict in Mojo must be of the same data type, respectively.

Integer

In Mojo, there are multiple types for representing integers, but the most common integer type (or integral type) is Int, which is either a 32-bit or 64-bit signed integer depending on your system. It is ensured to cover the range of addresses on your system. It is similar to the numpy.intp type in Python and the isize type in Rust. Mojo also has other integer types with different sizes in bits, such as Int8, Int16, Int32, Int64, Int128, Int256 and their unsigned counterparts.

You may think that this Int type is the same as the int type in Python, but it is not true. The int type in Python is an arbitrary-precision integer type, which means it can grow as large as the memory allows ,e.g., 1 followed by 1000 zeros. In contrast, the Int type in Mojo is a fixed-size integer type, which means it has a limited range of values. On a 64-bit system, the range of Int of Mojo is from -2^63 to 2^63 - 1. If you try to conduct operations that exceed this range, you will encounter an overflow.

Thus, you need to always be careful when you are doing big integer calculations in Mojo. If you really need to work on big integers that are larger than the capacity of Int, you can consider using the BigInt type in the decimojo package, which has the similar functionality as the int type in Python.

More on integers

We will discuss integral types in more detail in Section Integer of Chapter Data Types.

Floating-point number

In Mojo, there are several types for representing floating-point numbers. They differ in the number of bits they use to store the value, such as Float16, Float32, Float64, and Float128. The most commonly used type is Float64, which is a double-precision floating-point number. It is similar to the float type in Python. In you do not specify the type of a floating-point number, Mojo will automatically use Float64 as the default type.

In short, Mojo's Float64 type is almost the same as Python's float type. You can safely use it without worrying about the differences. Mojo also provides other floating-point types with different sizes. You can wisely choose the appropriate type based on your needs (desired precision and range).

String

String is changing rapidly

The behavior of String has been changing rapidly since Mojo version 24.5. Some of the features mentioned in this section may be deprecated or removed in future versions.

More on string

We will discuss the string type in more detail in Section String of Chapter Data Types.

Mojo's String type is similar to Python's str type, representing a sequence of Unicode characters. However, there are some differences that you should be aware of:

FunctionalityPython strMojo String
Constructed from string literalsUse ofstr() constructor is optional.You have to use String() constructor.
Print string with print()Yes.Yes.
Format string with format()Yes, use {}.Yes, but you cannot specify formatting, e.g, .2f.
f-stringsYes.Not supported.
Iteration over UTF-8 code pointsYes, use for i in s: directly.Yes, but more complicated.
UTF8-assured indexing and slicingYes, use s[i] or s[i:j] directly.Not supported.

If you use only quotation marks to define a string, Mojo will treat it as a string literal type. You format them with format(). For example, the following code will raise an error:

mojo
def main():
    var a = 18
    print("The value of a is {}".format(a))  # This will raise an error

To avoid this error, you need to use String() constructor to convert the string literal to a String type:

mojo
def main():
    var a = 18
    print(String("The value of a is {}".format(a)))  # This will work

Currently, you cannot indicate formatting style for String, such as .2f for floating-point numbers or .3% for percentages.

You cannot use f-strings in Mojo at the moment.

To iterate over the UTF-8 code points in a String, you can use a for loop, but it is more complicated than in Python. You have to iterate over String.codepoints() and then wrap the items with String() constructor. See the following comparison:

python
def main():
    s: str = "Hello, world!"
    for c in s:
        print(c, end="")
main()
# Output: Hello, world! 你好,世界!
mojo
def main():
    my_string = String("Hello, world! 你好,世界!")
    for char in my_string.codepoints():
        print(String(char), end="")
# Output: Hello, world! 你好,世界!

To access a code point in a Python str, you can just use indexing or slicing, such as s[i] or s[i:j]. However, in Mojo, you cannot do this directly at the moment. This feature is still under development.

More on integers

We will discuss floating-point types in more detail in Section Floating-point number of Chapter Data Types.

List

In Python, a list is a mutable sequence type that can hold Python objects of any type. In Mojo, a List is also a mutable sequence type but can only hold objects of the same type. Here are some key differences between Python's list and Mojo's List:

FunctionalityMojo ListPython list
Type of elementsHomogeneous typeHeterogenous types
MutabilityMutableMutable
InializationList[Type]()list() or []
IndexingUse brackets []Use brackets []
SlicingUse brackets [a:b:c]Use brackets [a:b:c]
Extending by itemsUse append()Use append()
ConcatenationUse + operatorUse + operator
PrintingNot supportedUse print()
IteratingUse for loop and de-referenceUse for loop

The following things are common between List in Mojo and list in Python:

  • You can retrieve the elements of a List in Mojo using indexing.
  • You can create another List by slicing an existing List.
  • You can also append elements to a List in Mojo using the append() method.
  • You can use the + operator to concatenate two List objects.

The other functionalities of List in Mojo would be different. Your knowledge of Python's list will not help you much in Mojo. Let's look at them one by one.

To construct a List in Mojo, you have to use the list constructor. For example, to create a list of Int numbers, you can use the following code:

mojo
def main():
    my_list_of_integers = List[Int](1, 2, 3, 4, 5)
    my_list_of_floats = List[Float64](0.125, 12.0, 12.625, -2.0, -12.0)
    my_list_of_strings = List[String]("Mojo", "is", "awesome")

You cannot print the List object directly in Mojo for now. You have to write your own function to iterate over the elements of the List and print them one by one.

When you iterate over a List in Python, you get the elements directly. However, in Mojo, you get references to these elements (pointers to their address in the memory). so you have to de-reference them first before using them. The dereferencing is done via the [] operator. See the following comparison:

python
def main():
    my_list: list[int] = [1, 2, 3, 4, 5]
    for i in my_list:
        print(i, end=" ")  # Directly printing the element
# Output: 1 2 3 4 5
mojo
def main():
    my_list = List[Int](1, 2, 3, 4, 5)
    for i in my_list:
        print(i[], end=" ")  # De-referencing the element to get its value
# Output: 1 2 3 4 5

We will discuss the list type in more detail in Section List of Chapter Data Types. Chapter Memory Layout of Mojo objects provides some abstract diagrams to illustrate the memory layouts of a list in Python and Mojo.

Other difference

In addition to the differences in data types, there are some other differences (maybe nuances) between Mojo and Python that you should be aware of:

featurepythonmojo
Variable definitionNo keywordvar (in some cases optional)
Variable re-definition possible?YesNo
Function definitiondefdef (looser) or fn (stricter)
Argument behavior depends on?TypeModifiers, e.g., read, mut, owned
Argument passed by?ReferenceValue (owned) or reference (read, mut)
Default argument mutabilityMutable or a new copyImmutable (default to read modifier)
Raises in the function signatureNo needNo need for def function, need for fn function
A main function is neededNoYes
Function overloadingNoYes
Chained comparisonYesYes
a = b for listsCopy referenceCopy value
Define a typeclassstruct
Class or struct inheritable?YesNo
Define attributes in class / structNo, but can use type annotationYes, use var
Compile time parametrizationNoYes
Generic and traitsNoYes
Dunder methods to access built-in functionsYesYes, via traits
Operators overloadingYesYes, via traits
Transfer ownership of variablesNoYes, use a = b^

Mojo Miji - A Guide to Mojo Programming Language from A Pythonista's Perspective · 魔咒秘籍 - Pythonista 視角下的 Mojo 編程語言指南