> For the complete Mojo documentation index, see [llms.txt](/llms.txt).
> Markdown versions of all pages are available by appending .md to any URL (e.g. /docs/manual/basics.md).

# Functions

Mojo uses the `def` keyword to define functions.
Functions declared inside a [`struct`](/docs/manual/structs/) are called
"methods," but they have all the same qualities as "functions" described here.

:::caution

The `fn` keyword is deprecated as of Mojo v26.2. Use `def` for all
function declarations. The `fn` keyword will be removed in a future
release.

:::

## Anatomy of a function

You'll find these elements in Mojo functions:

<pre>
<strong>def</strong> <var>function_name</var><strong>[
&#8203;    </strong><var>parameters ...</var><strong>
](https://mojolang.org/docs/manual/&.md#8203;    </strong><var>arguments ...</var><strong>) -&gt;</strong> <var>return_value_type</var>:
&#8203;    <var>function_body</var>
</pre>

Functions can have:

- Parameters: A function can optionally take one or more compile-time
  _parameter_ values used for metaprogramming.
- Arguments: A function can also optionally take one or more run-time
  _arguments_.
- Return value: A function can optionally return a value.
- Function body: Statements that are executed when you call the function.
  Function definitions must include a body.

All of the optional parts of the function can be omitted, so the minimal
function is something like this:

```mojo
def do_nothing():
    pass
```

If a function takes no parameters, you can omit the square brackets, but the
parentheses are always required.

Although you can't leave out the function body, you can use the `pass` statement
to define a function that does nothing.

### Arguments and parameters

Functions take two kinds of inputs: _arguments_ and _parameters_. Arguments are
familiar from many other languages: they are run-time values passed into the
function.

```mojo
def add(a: Int, b: Int) -> Int:
    return a+b
```

On the other hand, you can think of a parameter as a compile-time variable that
becomes a run-time constant. For example, consider the following function with a
parameter:

```mojo
def add_tensors[rank: Int](https://mojolang.org/docs/manual/a: MyTensor[rank], b: MyTensor[rank].md) -> MyTensor[rank]:
    # ...
```

In this case, the `rank` value needs to be specified in a way that can be
determined at compilation time, such as a literal or expression.

When you compile a program that uses this code, the compiler produces a unique
version of the function for each unique `rank` value used in the program, with
`rank` treated as a constant within each specialized version.

This usage of "parameter"
is probably different from what you're used to from other languages, where
"parameter" and "argument" are often used interchangeably. In Mojo, "parameter"
and "parameter expression" refer to compile-time values, and "argument" and
"expression" refer to run-time values.

By default, both arguments and parameters can be specified either by position or
by keyword. These forms can also be mixed in the same function call.

```mojo
# positional
x = add(5, 7)      # Positionally, a=5 and b=7
# keyword
y = add(b=3, a=9)
# mixed
z = add(5, b=7)    # Positionally, a=5
```

For more information on arguments, see [Function arguments](#function-arguments)
on this page. For more information on parameters, see
[Parameterization: compile-time metaprogramming](/docs/manual/parameters/).

## Function requirements

A function has the following requirements:

- You must declare the type of each function parameter and argument.

- If a function doesn't return a value, you can either omit the return type or
  declare `None` as the return type.

  ```mojo
  # The following function definitions are equivalent

  def greet(name: String):
    print("Hello,", name)

  def greet(name: String) -> None:
    print("Hello,", name)
  ```

- If the function returns a value, you must either declare the return type using
  the <code><strong>-></strong> <var>type</var></code> syntax or provide a
  [named result](#named-results) in the argument list.

  ```mojo
  # The following function definitions are equivalent

  def incr(a: Int) -> Int:
    return a + 1

  def incr(a: Int, out b: Int):
    b = a + 1
  ```

  For more information, see the [Return values](#return-values) section of this
  page.

## Function arguments

:::note Functions with / and * in the argument list

You might see the following characters in
place of arguments: slash (`/`) and/or star (`*`). For example:

```mojo
def myfunc(pos_only, /, pos_or_keyword, *, keyword_only):
```

Arguments **before** the `/` can be passed only by position. Arguments **after**
the `*` can be passed only by keyword. For details, see
[Positional-only and keyword-only arguments](#positional-only-and-keyword-only-arguments)

You may also see argument names prefixed with one or two stars (`*`):

```mojo
def myfunc2(*names, **attributes):
```

An argument name prefixed by a single star character, like `*names` identifies a
[variadic argument](#variadic-arguments), while an argument name prefixed with
a double star, like `**attributes` identifies a
[variadic keyword-only argument](#variadic-keyword-arguments).

:::

### Optional arguments

An optional argument is one that includes a default value, such as the `exp`
argument here:

```mojo
def my_pow(base: Int, exp: Int = 2) -> Int:
    return base ** exp

def use_defaults():
    # Uses the default value for `exp`
    var z = my_pow(3)
    print(z)
```

However, you can't define a default value for an argument that's declared with
the [`mut`](/docs/manual/values/ownership/#mutable-arguments-mut) argument
convention.

Any optional arguments must appear after any required arguments. [Keyword-only
arguments](#positional-only-and-keyword-only-arguments), discussed later, can
also be either required or optional.

### Keyword arguments

You can also use keyword arguments when calling a function. Keyword arguments
are specified using the format
<code><var>argument_name</var> = <var>argument_value</var></code>.
You can pass keyword arguments in any order:

```mojo
def my_pow(base: Int, exp: Int = 2) -> Int:
    return base ** exp

def use_keywords():
    # Uses keyword argument names (with order reversed)
    var z = my_pow(exp=3, base=2)
    print(z)
```

### Variadic arguments

Variadic arguments let a function accept a variable number of arguments. To
define a function that takes a variadic argument, use the variadic argument
syntax <code>*<var>argument_name</var></code>:

```mojo
def sum(*values: Int) -> Int:
  var sum: Int = 0
  for value in values:
    sum = sum + value
  return sum
```

The variadic argument `values` here is a placeholder that accepts any number of
passed positional arguments.

You can define zero or more arguments before the variadic argument. When calling
the function, any remaining positional arguments are assigned to the variadic
argument, so any arguments declared **after** the variadic argument can only be
specified by keyword (see
[Positional-only and keyword-only arguments](#positional-only-and-keyword-only-arguments)).

Variadic arguments can be divided into two categories:

- Homogeneous variadic arguments, where all of the passed arguments are the same
  type—all `Int`, or all `String`, for example.
- Heterogeneous variadic arguments, which can accept a set of different argument
  types.

The following sections describe how to work with homogeneous and heterogeneous
variadic arguments.

:::note Variadic parameters

Mojo also supports variadic _parameters_, but with some limitations—for details
see [variadic parameters](/docs/manual/parameters/#variadic-parameters).

:::

#### Homogeneous variadic arguments

When defining a homogeneous variadic argument (all arguments must be the same
type), use <code>*<var>argument_name</var>: <var>argument_type</var></code>:

```mojo
def greet(*names: String):
    ...
```

Inside the function body, the variadic argument is available as an iterable list
for ease of use. Concretely, that type is named
[`VariadicList`](/docs/std/builtin/variadics/VariadicList/). Here is a
simple example:

```mojo
def sum(*values: Int) -> Int:
  var sum: Int = 0
  for value in values:
    sum = sum+value
  return sum
```

Iterating over this list directly with a `for..in` loop currently produces a
reference to the element, which can be mutable with a `mut` variadic list. Use
the `ref` binding pattern to capture a mutable reference if you
want to mutate the elements of the list:

```mojo
def make_worldly(mut *strs: String):
    for ref i in strs:
        i += " world"
```

You can also directly index the list with integers as well:

```mojo
def make_worldly(mut *strs: String):
    for i in range(len(strs)):
        strs[i] += " world"
```

#### Heterogeneous variadic arguments

Implementing heterogeneous variadic arguments (each argument type may be
different) is somewhat more complicated than homogeneous variadic arguments. To
handle multiple argument types, the function must be
[generic](/docs/manual/generics/), which requires using
[traits](/docs/manual/traits/) and [parameters](/docs/manual/parameters/). So
the syntax may look a little unfamiliar if you haven't worked with those
features.

The signature for a function with a heterogeneous variadic argument looks like
this:

```mojo
def count_many_things[*ArgTypes: Intable](https://mojolang.org/docs/manual/*args: *ArgTypes.md):
    ...
```

The parameter list, `[*ArgTypes: Intable]` specifies that the function takes an
`ArgTypes` parameter, which is a list of types, all of which conform to the
[`Intable`](/docs/std/builtin/int/Intable/) trait. The asterisk in `*ArgTypes`
indicates that `ArgTypes` is a **variadic type parameter** (a list of types).

The argument list, `(*args: *ArgTypes)` has the familiar `*args` for the
variadic argument, but instead of a single type, its type is defined as the
variadic type list `*ArgTypes`. The asterisk in `*args` indicates a
**variadic argument**, and the asterisk in `*ArgTypes` refers to the
variadic type parameter.

This means that each argument in `args` has a corresponding type in `ArgTypes`,
so <code>args[<var>n</var>]</code> is of type
<code>ArgTypes[<var>n</var>]</code>.

Inside the function, `args` becomes a
[`VariadicPack`](/docs/std/builtin/variadics/VariadicPack/) because the
syntax `*args: *ArgTypes` creates a heterogeneous variadic argument. That means
each element in `args` can be a different type that requires a different amount
of memory. To iterate through the `VariadicPack`, the compiler must know each
element's type, so you must use a [`comptime for`
loop](/docs/manual/metaprogramming/comptime-evaluation/#comptime-for):

```mojo
def count_many_things[*ArgTypes: Intable](https://mojolang.org/docs/manual/*args: *ArgTypes.md) -> Int:
    var total = 0

    comptime for i in range(args.__len__()):
        total += Int(args[i])

    return total

def main():
    print(count_many_things(5, 11.7, 12))
```

```output
28
```

Notice that when calling `count_many_things()`, you don't actually pass in
a list of argument types. You only need to pass in the arguments, and Mojo
generates the `ArgTypes` list itself.

#### Variadic keyword arguments

Mojo functions also support variadic keyword arguments (`**kwargs`). Variadic
keyword arguments allow the user to pass an arbitrary number of keyword
arguments. To define a function that takes a variadic keyword argument, use the
variadic keyword argument syntax <code>**<var>kw_argument_name</var></code>:

```mojo
def print_nicely(**kwargs: Int):
    for item in kwargs.items():
        print(item.key, "=", item.value)

# prints:
# `a = 7`
# `y = 8`
print_nicely(a=7, y=8)
```

In this example, the argument name `kwargs` is a placeholder that accepts any
number of keyword arguments. Inside the body of the function, you can access
the arguments as a dictionary of keywords and argument values (specifically,
an instance of
[`OwnedKwargsDict`](/docs/std/collections/dict/OwnedKwargsDict/)).

There are currently a few limitations:

- Variadic keyword arguments are always implicitly treated as if they
  were declared with the `var` [argument
  convention](/docs/manual/values/ownership#argument-conventions), and
  can't be declared otherwise:

  ```mojo
  # Not supported yet.
  def read_var_kwargs(read **kwargs: Int): ...
  ```

- All the variadic keyword arguments must have the same type, and this
  determines the type of the argument dictionary. For example, if the argument
  is `**kwargs: Float64` then the argument dictionary will be a
  `OwnedKwargsDict[Float64]`.

- The argument type must conform to the
  [`Copyable`](/docs/std/builtin/value/Copyable/) trait.

- Dictionary unpacking is not supported yet:

  ```mojo
  def takes_dict(d: Dict[String, Int]):
    print_nicely(**d)  # Not supported yet.
  ```

- Variadic keyword _parameters_ are not supported yet:

  ```mojo
  # Not supported yet.
  def var_kwparams[**kwparams: Int](): ...
  ```

### Positional-only and keyword-only arguments

When defining a function, you can restrict some arguments so that they can
be passed only as positional arguments, or they can be passed only as keyword
arguments.

To define positional-only arguments, add a slash character (`/`) to the
argument list. Any arguments before the `/` are positional-only: they can't be
passed as keyword arguments. For example:

```mojo
def min(a: Int, b: Int, /) -> Int:
    return a if a < b else b
```

This `min()` function can be called with `min(1, 2)` but can't be called using
keywords, like `min(a=1, b=2)`.

There are several reasons you might want to write a function with
positional-only arguments:

- The argument names aren't meaningful for the caller.
- You want the freedom to change the argument names later on without breaking
  backward compatibility.

For example, in the `min()` function, the argument names don't add any real
information, and there's no reason to specify arguments by keyword.

For more information on positional-only arguments, see [PEP 570 – Python
Positional-Only Parameters](https://peps.python.org/pep-0570/).

Keyword-only arguments are the inverse of positional-only arguments: they can
be specified only by keyword. If a function accepts variadic arguments, any
arguments defined _after_ the variadic arguments are treated as keyword-only.
For example:

```mojo
def sort(*values: Float64, ascending: Bool = True): ...
```

In this example, the user can pass any number of `Float64` values, optionally
followed by the keyword `ascending` argument:

```mojo
var a = sort(1.1, 6.5, 4.3, ascending=False)
```

If the function doesn't accept variadic arguments, you can add a single star
(`*`) to the argument list to separate the keyword-only arguments:

```mojo
def kw_only_args(a1: Int, a2: Int, *, double: Bool) -> Int:
    var product = a1 * a2
    if double:
        return product * 2
    else:
        return product
```

Keyword-only arguments often have default values, but this is not required. If a
keyword-only argument doesn't have a default value, it is a _required
keyword-only argument_. It must be specified, and it must be specified by
keyword.

Any required keyword-only arguments must appear in the signature before
any optional keyword-only arguments. That is, arguments appear in the following
sequence in a function signature:

- Required positional arguments.
- Optional positional arguments.
- Variadic arguments.
- Required keyword-only arguments.
- Optional keyword-only arguments.
- Variadic keyword arguments.

For more information on keyword-only arguments, see [PEP 3102 – Keyword-Only
Arguments](https://peps.python.org/pep-3102/).

## Overloaded functions

All function declarations must specify argument types, so if you want a
function to work with different data types, you need to implement
separate versions of the function that each specify different argument types.
This is called "overloading" a function.

For example, here's an overloaded `add()` function that can accept either
`Int` or `String` types:

```mojo
def add(x: Int, y: Int) -> Int:
    return x + y

def add(x: String, y: String) -> String:
    return x + y
```

If you pass anything other than `Int` or `String` to the `add()` function,
you'll get a compiler error. That is, unless `Int` or `String` can implicitly
cast the type into their own type. For example, `String` includes an overloaded
version of its constructor (`__init__()`) that supports
[implicit conversion](/docs/manual/lifecycle/life/#constructors-and-implicit-conversion)
from a `StringLiteral` value. Thus, you can also pass a `StringLiteral` to a
function that expects a `String`.

When resolving an overloaded function call, the Mojo compiler tries each
candidate function and uses the one that works (if only one version works), or
it picks the closest match (if it can determine a close match), or it reports
that the call is ambiguous (if it can't figure out which one to pick). For
details on how Mojo picks the best candidate, see
[Overload resolution](#overload-resolution).

If the compiler can't figure out which function to use, you can resolve the
ambiguity by explicitly casting your value to a supported argument type. For
example, the following code calls the overloaded `foo()` function,
but both implementations accept an argument that supports [implicit
conversion](/docs/manual/lifecycle/life#constructors-and-implicit-conversion)
from `String`. So, the call to `foo("Hello")` is ambiguous and creates a
compiler error. You can fix this by casting the value to the type you really
want:

```mojo
struct MyString:
    @implicit
    def __init__(out self, string: String):
        pass

struct YourString:
    @implicit
    def __init__(out self, string: String):
        pass

def foo(name: MyString):
    print("MyString")

def foo(name: YourString):
    print("YourString")

def call_foo():
    # foo("Hello") # error: ambiguous call to 'foo' ... This call is ambiguous because two `foo` functions match it
    foo(MyString("Hello"))
```

:::note Overload Sets
An "overload set" is a collection of function overloads that share
the same name but different signatures.

- Overload sets can't be extended by imports, aliases, or parameters.
- If you define a function in a Mojo module, it hides any
  overload sets you imported earlier.
:::

### Overload resolution

When resolving an overloaded function, Mojo does not consider the return type
or other contextual information at the call site—it considers only parameter and
argument types and whether the functions are instance methods or static methods.

The overload resolution logic filters for candidates according to the following
rules, in order of precedence:

1. Candidates requiring the smallest number of implicit conversions (in both
   arguments and parameters).
2. Candidates without variadic arguments.
3. Candidates without variadic parameters.
4. Candidates with the shortest parameter signature.
5. Non-`@staticmethod` candidates (over `@staticmethod` ones, if available).

If there is more than one candidate after applying these rules, the overload
resolution fails. For example:

```mojo
struct MyInt(TrivialRegisterPassable):
    """A type that is implicitly convertible to `Int`."""
    var value: Int

    @implicit
    def __init__(out self, _a: Int):
        self.value = _a

def foo[x: MyInt, a: Int]():
    print("foo[x: MyInt, a: Int]()")

def foo[x: MyInt, y: MyInt]():
    print("foo[x: MyInt, y: MyInt]()")

def bar[a: Int](https://mojolang.org/docs/manual/b: Int.md):
    print("bar[a: Int](https://mojolang.org/docs/manual/b: Int.md)")

def bar[a: Int](https://mojolang.org/docs/manual/*b: Int.md):
    print("bar[a: Int](https://mojolang.org/docs/manual/*b: Int.md)")

def bar[*a: Int](https://mojolang.org/docs/manual/b: Int.md):
    print("bar[*a: Int](https://mojolang.org/docs/manual/b: Int.md)")

def parameter_overloads[a: Int, b: Int, x: MyInt]():
    # `foo[x: MyInt, a: Int]()` is called because it requires no implicit
    # conversions, whereas `foo[x: MyInt, y: MyInt]()` requires one.
    foo[x, a]()

    # `bar[a: Int](https://mojolang.org/docs/manual/b: Int.md)` is called because it does not have variadic
    # arguments or parameters.
    bar[a](https://mojolang.org/docs/manual/b.md)

    # `bar[*a: Int](https://mojolang.org/docs/manual/b: Int.md)` is called because it has variadic parameters.
    bar[a, a, a](https://mojolang.org/docs/manual/b.md)

parameter_overloads[1, 2, MyInt(3)]()

struct MyStruct:
    def __init__(out self):
        pass

    def foo(mut self):
        print("calling instance method")

    @staticmethod
    def foo():
        print("calling static method")

def test_static_overload():
    var a = MyStruct()
    # `foo(mut self)` takes precedence over a static method.
    a.foo()
```

```output
foo[x: MyInt, a: Int]()
bar[a: Int](https://mojolang.org/docs/manual/b: Int.md)
bar[*a: Int](https://mojolang.org/docs/manual/b: Int.md)
```

## Return values

Return value types are declared in the signature using the
<code><strong>-></strong> <var>type</var></code> syntax. Values are
passed using the `return` keyword, which ends the function and returns the
identified value (if any) to the caller.

```mojo
def get_greeting() -> String:
    return "Hello"
```

By default, the value is returned to the caller as an owned value. As with
arguments, a return value may be [implicitly
converted](/docs/manual/lifecycle/life#constructors-and-implicit-conversion) to
the named return type. For example, the previous example calls `return` with a
string literal, `"Hello"`, which is implicitly converted to a `String`.

:::note Returning a reference

A function can also return a mutable or immutable reference using a `ref` return
value. For details, see
[Lifetimes, origins, and references](/docs/manual/values/lifetimes/).

:::

### Named results

Named function results allow a function to return a value that can't be moved or
copied. Named result syntax lets you specify a named, uninitialized variable to
return to the caller using the `out` argument convention:

```mojo
def get_name_tag(var name: String, out name_tag: NameTag):
    name_tag = NameTag(name^)
```

The `out` argument convention identifies an uninitialized variable that the
function must initialize. (This is the same as the `out` convention used in
[struct constructors](/docs/manual/lifecycle/life/#constructor).) The `out`
argument for a named result can appear anywhere in the argument list, but by
convention, it should be the last argument in the list.

A function can declare only one return value, whether it's declared using an
`out` argument or using the standard <code><strong>-></strong>
<var>type</var></code> syntax.

A function with a named result argument doesn't need to include an explicit
`return` statement, as shown above. If the function terminates without a
`return`, or at a `return` statement with no value, the value of the `out`
argument is returned to the caller. If it includes a `return` statement with a
value, that value is returned to the caller, as usual.

The fact that a function uses a named result is transparent to the caller. That
is, these two signatures are interchangeable to the caller:

```mojo
def get_name_tag(var name: String) -> NameTag:
    ...
def get_name_tag(var name: String, out name_tag: NameTag):
    ...
```

In both cases, the call looks like this:

```mojo
tag = get_name_tag("Judith")
```

Because the return value is assigned to this special `out` variable, it doesn't
need to be moved or copied when it's returned to the caller. This means that you
can create a function that returns a type that can't be moved or copied, and
which takes several steps to initialize:

```mojo
struct ImmovableObject:
    var name: String

    def __init__(out self, var name: String):
        self.name = name^

def create_immovable_object(var name: String, out obj: ImmovableObject):
    obj = ImmovableObject(name^)
    obj.name += "!"
    # obj is implicitly returned

def main():
    my_obj = create_immovable_object("Blob")
```

By contrast, the following function with a standard return value doesn't work:

```mojo
def create_immovable_object2(var name: String) -> ImmovableObject:
    obj = ImmovableObject(name^)
    obj.name += "!"
    return obj^ # Error: ImmovableObject is not copyable or movable
```

Because `create_immovable_object2` uses a local variable to store the object
while it's under construction, the return call requires it to be either moved
or copied to the callee. This isn't an issue if the newly-created value is
returned immediately:

```mojo
def create_immovable_object3(var name: String) -> ImmovableObject:
    return ImmovableObject(name^) # OK
```

## Raising and non-raising functions

By default, when a function raises an error, the function terminates immediately
and the error propagates to the calling function. If the calling function
doesn't handle the error, it continues to propagate up the call stack.

```mojo
def raises_error() raises:
    raise Error("There was an error.")
```

Mojo functions are _non-raising_ by default. To declare that a function can
propagate an error to its caller, add the `raises` keyword to the function
signature. A non-raising function that calls a raising function **must handle
any possible errors.**

```mojo
# This function will not compile
def unhandled_error():
    raises_error()   # Error: can't call raising function in a non-raising context

# Explicitly handle the error
def handle_error():
    try:
        raises_error()
    except e:
        print("Handled an error:", e)

# Explicitly propagate the error
def propagate_error() raises:
    raises_error()
```

All of the examples above use the built-in `Error` type. Mojo also supports
_typed errors_, where you specify a custom error type a function can raise:

```mojo
def validate(value: Int) raises ValidationError -> Int:
    ...
```

For more information, see
[Errors, error handling, and context managers](/docs/manual/errors/).
