Mojo is a new programming language, a superset of Python, and is intended for artificial intelligence programming. It uses the newly introduced features to optimize its code to run on custom hardware and also provides low level access to MLIR. This enables the user to create custom data types and abstractions for their hardware allowing them utilize their hardware to the full potential.
When a variable from one function is passed into another, its scope changes. When this happens, there are some restrictions that the function receiving the variable, must have in terms of the variable's modification. This is referred to as argument mutability whether functions and operations outside a variable's scope are allowed to modify its value or not. Most programming languages do not offer security measures for argument mutability. This can result in some serious memory management issues if some things are overlooked.
Some programming languages have ways to deal with this situation by using an "ownership/borrowing" system. For example, Rust is known for its secure memory management which implements this exact system. Let's have a look at how we roll in Mojo.
When an argument is passed to a function in Mojo, the compiler follows different semantics based on the keyword used to pass the argument. We have three options for argument ownership:
The
The callee function can get temporary access to the argument and alter it's value.
The callee function can get transferred the ownership of the argument.
borrowed
keywordA borrowed
argument is an immutable reference of the actual argument being passed to the callee function. This means that the function is only able to read and use the value of the argument but not actually alter it.
fn ChangeValue(borrowed a: Int):a += 1fn main():var a: Int = 1ChangeValue(a)print (a)
When we try to execute the code above, we get an error that the function cannot alter the argument's value because it is immutable.
inout
keywordIf we want a certain function to modify an argument's value then it should be passed using the inout
keyword. This is demonstrated below using the same example as above:
fn ChangeValue(inout a: Int):a += 1fn main():var a: Int = 1ChangeValue(a)print (a)
As we can see, the ChangeValue
function didn't have any problems updating the argument's value.
Note: When we use the
inout
keyword, any changes made to the argument inside the function are also reflected outside the function.
owned
keywordThis keyword is used to transfer ownership of a variable to the callee function. The variable is no longer owned by the caller function to lend to other functions. We can use the following example to demonstrate the use of this keyword:
fn take_var(owned x: Int):print("take ownership")print(x)fn use_var(borrowed x: Int):print("use variable")print(x)fn main():let x: Int = 2use_var(x)take_var(x^)# uncomment to see error# use_var(x)
As seen in the code above, when we want to transfer the ownership of a variable to another function, we use the ^
post the name of the variable when passing it to the function. After the ownership of the variable is passed to the callee function, it can no longer be used in the caller function and an error will be thrown.
In this Answer, we saw how we can pass arguments with different permissions to other functions. We also saw how we can pass the ownership of the arguments being passed to the callee function. These features give Mojo the security it needs to prevent memory leaks and use a proper memory management infrastructure.
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 int
and Int
in Mojo?
Learn how Mojo differentiates between built-in primitive types and custom types with enhanced functionality.
What’s the difference between fn
and def
in Mojo?
Discover when to use fn
for performance-oriented functions and def
for flexible, dynamic programming.
What’s the difference between let
and var
in Mojo?
Explore the distinction between let
(immutable) and var
(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