What’s the difference between the fn and def keywords in Mojo?
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.
The def() keyword in Mojo
When 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
deffunctions 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
deffunctions, 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
deffunctions 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 withdeffunctions.
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.
The fn() keyword in Mojo
When 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
fnfunctions are designed with a higher degree of rigidity. This means they are not as dynamically flexible asdeffunctions, 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
fnkeyword enforces the immutability of argument values within the function’s body. Unlike thedefkeyword, where arguments are mutable, this design choice minimizes accidental mutations and encourages using non-copyable types as arguments.Explicit local variable declarations: Unlike the
defkeywords, thefnkeyword 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 theletandvarkeywords.
# 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.
Function arguments and returns
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
returnvalues, 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
Conclusion
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.
Unlock your potential: Mojo fundamentals series, all in one place!
To deepen your understanding of Mojo, explore our series of Answers below:
What are the fundamentals of Mojo?
Understand the basics of Mojo, its design principles, and how it enhances performance for AI and system-level programming.What’s the difference between
intandIntin Mojo?
Learn how Mojo differentiates between built-in primitive types and custom types with enhanced functionality.What’s the difference between
fnanddefin Mojo?
Discover when to usefnfor performance-oriented functions anddeffor flexible, dynamic programming.What’s the difference between
letandvarin Mojo?
Explore the distinction betweenlet(immutable) andvar(mutable) variables and their impact on memory safety.MLIR in Mojo
Understand how Mojo leverages Multi-Level Intermediate Representation (MLIR) for optimizing AI workloads and low-level computations.What is argument mutability in Mojo?
Learn how Mojo handles mutable and immutable function arguments to enhance performance and safety.What is a struct in Mojo?
Explore how structs in Mojo provide efficient, memory-safe data structures for performance-critical applications.Mojo vs. Python
Compare Mojo and Python in terms of speed, memory efficiency, and usability for AI and system-level programming.
Free Resources