Mojo is meticulously crafted to combine the performance capabilities of systems programming with the familiarity of Python. As a testament to this objective, Mojo has become a superset of Python, ensuring that developers comfortable with Python's syntax and conventions can seamlessly transition into the Mojo ecosystem.
While Mojo directly borrows the def
keyword from Python for function definitions, it also introduces its own fn
keyword for function declarations, which comes with its own set of distinctive capabilities and use cases within the Mojo language. We will take a look at both these keywords one by one to understand the differences between them and when should we use them.
Note: You can learn more about Mojo in this Answer.
def()
keyword in MojoWhen we use the def
keyword in Mojo, we are defining a function. The syntax for it is clear and concise, resembling its Python counterpart, making it easy for Python developers to work with. Functions declared using the def
keyword can take parameters, return values, and perform a wide range of tasks, just like in Python. Here are some key characteristics of the def
keyword in Mojo:
Dynamic and flexible: The def
functions are dynamic, meaning they can be defined and redefined at runtime. This flexibility allows developers to modify and extend functions as needed, making it well-suited for dynamic programming tasks.
Mutable arguments: In def
functions, function arguments are mutable. This means that we can modify the values of arguments within the function, just like in Python. This mutability can be advantageous in certain scenarios.
Scoping flexibility: Scoping in def
functions are not enforced in a strict manner. This flexibility can be useful in various situations, but it’s important to be aware of scoping implications when working with def
functions.
Let’s take a look at a simple example of using the def
keyword in Mojo:
# Define a function using the def keyworddef main():message = "Hello from Mojo 🔥"print(message)
This code works exactly the same as it does in Python because the def
keyword is defined to be dynamic, flexible, and generally compatible with Python. While the def
keyword is well-suited for high-level programming and scripting tasks, it may not always be the ideal choice for systems programming, and that is where the fn
keyword becomes important.
fn()
keyword in MojoWhen we utilize the fn
keyword in Mojo, we are defining a function with a distinct and more controlled behavior compared to the def
keyword. The syntax, while reminiscent of Python, introduces a level of strictness and predictability that distinguishes it from the def
keyword. Functions declared using the fn
keyword are crafted with the following specific characteristics:
Strict and structured: The fn
functions are designed with a higher degree of rigidity. This means they are not as dynamically flexible as def
functions, and once defined, they maintain a level of consistency in their behavior, which can be advantageous for scenarios where predictability is crucial.
Immutable arguments: The fn
keyword enforces the immutability of argument values within the function’s body. Unlike the def
keyword, where arguments are mutable, this design choice minimizes accidental mutations and encourages using non-copyable types as arguments.
Explicit local variable declarations: Unlike the def
keywords, the fn
keyword disables the implicit declaration of local variables, making it mandatory to declare all local variables explicitly. This reduces the likelihood of name typos and aligns with the scoping provided by the let
and var
keywords.
Note: If you want to read more on the topic of using the
let
andvar
keywords for variable assignments, please take a look at this Answer.
# Define a function using the def keywordfn main():message = "Hello from Mojo 🔥"print(message)
As we can see, we get an error when we run the above code. The error message in the code arises from not explicitly declaring the message
variable on line 3. To resolve this error, we can use the var
or let
keyword before the message
variable to declare it explicitly. This correction aligns with Mojo’s requirements for fn
declarations, ensuring that all variables are defined before they are utilized.
Let’s take a look at the fixed version of the above code by using the var
keyword:
# Define a function using the def keywordfn main():var message = "Hello from Mojo 🔥"print(message)
As we can see, when we use the var
keyword in Mojo, it can trigger a warning that reminds us about the variable’s mutability. In the code, we declared the message
variable as a var
, which means it’s mutable, but because the code doesn’t actually change the value of the message
variable after its initial assignment, we do not get any error. Try replacing the var
keyword with the let
keyword to remove this warning.
An important thing to remember is that when defining a function in Mojo using the fn
keyword, data types become mandatory for both function arguments (parameters) and return values. This means that we must specify the data types of the parameters the function accepts as input and the data type of the value the function returns.
Note: In this context, we specifically address the
return
values, and the
fn add(x: Int, y: Int) -> Int:return x + yfn main():let z = add(1, 2)print (z)
The above code defines a simple add
function that adds two integers and a main
function that calls the add
function, assigns the result to a variable z
, and then prints the value of z
. When executed, it will output the sum of
Ultimately, both the fn
and def
keywords serve as valuable tools in the Mojo programmer’s toolkit, offering the flexibility to choose the most suitable option based on the specific programming context and objectives. This versatility underscores Mojo’s commitment to empowering developers with choices that cater to a wide range of application scenarios.
Free Resources