> 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).

# Parameterization

Many programming languages offer systems for writing generic or polymorphic
code, which let you write code once, and generate efficient, specialized
code at compile time.

Mojo's compile-time parameter system lets you define reusable code. A parameter
is a compile-time input to a struct or function. Parameters appear in square
brackets after the struct or function name. Parameters can take ordinary
values, like `Int` or `String`:

```mojo
def multiplier[factor: Int](https://mojolang.org/docs/manual/parameters/x: Int.md) -> Int:
    return x * factor

def main():
    comptime times_ten = multiplier[10]
    x10 = times_ten(3)
```

Parameters accept both types and values at compile time. When a
parameter accepts a type, the result is type-generic code. When it
accepts a value, the result is value-generic code.

```mojo no-test
struct MyList[T: AnyType]:
    # ... type-generic

struct FixedBuffer[size: Int]:
    # ... value-generic
```

Mojo's parameters are similar to C++ template parameters or Rust generic
parameters.

In Mojo, "parameter" always means a compile-time value, and
"argument" always means a run-time value.

In most other languages, a parameter is part of a declaration and an
argument is the value you pass at the call site. Mojo changes the
meaning of "parameter" to refer specifically to compile-time values.

Mojo makes this distinction visible in syntax: use `[]` for
parameters and `()` for arguments.

In addition to parameterizing structs and functions, you can also define
parameterized `comptime` values.

## Parameterized functions

To define a *parameterized function*, add parameters in square brackets ahead
of the argument list. Each parameter is formatted just like an argument: a
parameter name, followed by a colon and a type. In the
following example, the function has a single parameter, `count` of type `Int`.

```mojo
def repeat[count: Int](https://mojolang.org/docs/manual/parameters/msg: String.md):
    comptime for i in range(count):
        print(msg)
```

The [`comptime`](/docs/manual/metaprogramming/comptime-evaluation/#comptime-for)
keyword shown here
causes the `for` loop to be fully unrolled at compile time. The `comptime for`
requires the loop limits to be known at compile time. Since `count` is a
parameter, `range(count)` can be calculated at compile time.

Calling a parameterized function, you provide values for the parameters, just
like function arguments:

```mojo
repeat[3](https://mojolang.org/docs/manual/parameters/"Hello".md)
```

```output
Hello
Hello
Hello
```

The compiler resolves the parameter values during compilation, and creates a
concrete version of the `repeat[]()` function for each unique parameter value.
After resolving the parameter values and unrolling the loop, the `repeat[3]()`
function would be roughly equivalent to this:

```mojo no-test
def repeat_3(msg: String):
    print(msg)
    print(msg)
    print(msg)
```

:::note

This doesn't represent actual code generated by the compiler. By the
time parameters are resolved, Mojo code has already been transformed to an
intermediate representation in [MLIR](https://mlir.llvm.org/).

:::

If the compiler can't resolve all parameter values to constant values,
compilation fails.

### Overloading on parameters

Functions and methods can be overloaded on their parameter signatures. For
information on overload resolution, see
[Overloaded functions](/docs/manual/functions/#overloaded-functions).

## Parameters at a glance

Parameters to a function or struct appear in square brackets after a function
or struct name. Parameters always require type annotations.

When you're looking at a function or struct signature, you may
see some special characters such as `/` and `*` in the parameter list.
Here's an example:

```mojo
def my_sort[
    # infer-only parameters
    dtype: DType,
    width: Int,
    //,
    # positional-only parameter
    values: SIMD[dtype, width],
    /,
    # positional-or-keyword parameter
    compare: def(Scalar[dtype], Scalar[dtype]) thin -> Int,
    *,
    # keyword-only parameter
    reverse: Bool = False,
]() -> SIMD[dtype, width]:
```

Here, `compare` is a function-typed parameter. Because the comparator is a
noncapturing function value, the function type explicitly uses `thin`.

Here's a quick overview of the special characters in the parameter list:

- Double slash (`//`): parameters declared before the double slash are
  [infer-only parameters](#infer-only-parameters).
- Slash (`/`): parameters declared before a slash are positional-only
  parameters. Positional-only and keyword-only parameters follow the same rules
  as [positional-only and keyword-only
  arguments](/docs/manual/functions#positional-only-and-keyword-only-arguments).
- A parameter name prefixed with a star, like `*Types` identifies a
  [variadic parameter](#variadic-parameters) (not shown in the example above).
  Any parameters following the variadic parameter are keyword-only.
- Star (`*`): in a parameter list with no variadic parameter, a star by itself
  indicates that the following parameters are keyword-only parameters.
- An equals sign (`=`) introduces a default value for an
  [optional parameter](#optional-parameters-and-keyword-parameters).

## Parameters and generics

Generics let functions work across multiple types, and let containers
store values of many types. For example,
[`List`](/docs/std/collections/list/List/) takes a type parameter, so
`List[Int]` holds integers and `List[String]` holds strings.

In Mojo, generics use compile-time parameters. A function parameterized
on a type is type-generic. A function parameterized on a value is
value-generic. Both use `[]`.

This function uses both a type parameter and a value parameter:

```mojo
def repeat[
    MsgType: Writable, // infer-only
    count: Int
](https://mojolang.org/docs/manual/parameters/msg: MsgType.md):
    comptime for _ in range(count):
        print(msg)

def main():
    repeat[2](https://mojolang.org/docs/manual/parameters/42.md)  # prints 42 on two lines
```

`MsgType` is type-generic. It accepts any `Writable` type. `count` is
value-generic. It accepts a compile-time integer. Together, they let
you write one function that works across types and specializes for
different repeat counts.

`MsgType` uses `//` to mark it as an
[infer-only parameter](#infer-only-parameters). The compiler infers
the type from `msg`, so you only pass `count` explicitly.

For more on generics, including trait conformance, conditional conformance,
and value generics, see [generics](/docs/manual/generics/).

## Parameterized structs

You can also add parameters to structs. You can use parameterized structs to
build generic collections. For example, a generic array type might include code
like this:

```mojo
struct GenericArray[ElementType: Copyable & ImplicitlyDestructible]:
    var data: UnsafePointer[Self.ElementType, MutExternalOrigin]
    var size: Int

    def __init__(out self, var *elements: Self.ElementType):
        self.size = len(elements)
        self.data = alloc[Self.ElementType](https://mojolang.org/docs/manual/parameters/self.size)
        for i in range(self.size):
            (self.data + i).init_pointee_move(elements[i].copy())

    def __del__(deinit self):
        for i in range(self.size):
            (self.data + i).destroy_pointee()
        self.data.free()

    def __getitem__(self, i: Int) raises -> ref[self] Self.ElementType:
        if i < self.size:
            return self.data[i]
        else:
            raise Error("Out of bounds")
```

This struct has a single parameter, `ElementType`, which is a placeholder for
the data type you want to store in the array, sometimes called a *type
parameter*. `ElementType` conforms to the
[`Copyable`](/docs/std/builtin/value/Copyable/) trait and therefore to the
[`Movable`](/docs/std/builtin/value/Movable/) trait.

As with parameterized functions, you need to pass in parameter values when you
use a parameterized struct. In this case, when you create an instance of
`GenericArray`, you need to specify the type you want to store, like `Int`, or
`Float64`. (This is a little confusing, because the *parameter value* you're
passing in this case is a *type*. That's OK: a Mojo type is a valid compile-time
value.)

You'll see that `Self.ElementType` is used throughout the struct where you'd
usually see a type name. For example, as the formal type for the `elements` in
the constructor, and the return type of the `__getitem__()` method.

Here's an example of using `GenericArray`:

```mojo
var array = GenericArray(1, 2, 3)
for i in range(array.size):
    end = ", " if i < array.size - 1 else "\n"
    print(array[i], end=end)
```

```output
1, 2, 3
```

A parameterized struct can use the `Self` type to represent a concrete instance
of the struct (that is, with all its parameters specified). For example, you
could add a static factory method to `GenericArray` with the following
signature:

```mojo no-test
struct GenericArray[ElementType: Copyable & ImplicitlyDestructible]:
    ...

    @staticmethod
    def splat(count: Int, value: Self.ElementType) -> Self:
        # Create a new array with count instances of the given value
```

Here, `Self` is equivalent to writing `GenericArray[Self.ElementType]`. That is,
you can call the `splat()` method like this:

```mojo
var array = GenericArray[Float64].splat(8, 0)
```

The method returns an instance of `GenericArray[Float64]`.

### Referencing struct parameters

As shown in the previous section, you reference a
struct parameter using dot syntax, just like a struct method or field (for
example, `Self.ElementType`).

This struct parameter access works anywhere, not just inside a struct's methods.
You can access parameters as attributes on the type itself:

```mojo
def on_type():
    print(SIMD[DType.float32, 2].size)  # prints 2
```

Or as attributes on an *instance* of the type:

```mojo
def on_instance():
    var x = SIMD[DType.int32, 2](https://mojolang.org/docs/manual/parameters/4, 8.md)
    print(x.dtype)  # prints int32
```

### `comptime` members

You can also define `comptime` values as members of a `struct` or `trait`
declaration:

```mojo
struct Circle[radius: Float64]:
    comptime pi = 3.14159265359
    comptime circumference = 2 * Self.pi * Self.radius
```

These `comptime` members have a number of uses:

- Constant values specific to the type.
- Constant values calculated based on the struct's parameters.
- Associated types based on the struct's parameters.

The difference between parameters and `comptime` members is that parameter
values are specified by the user, but `comptime` members represent either
constant values or values derived from the input parameters.

A required value is a `comptime` member without an initializer. Conforming
types must provide a value for it. This is useful when the trait needs a
compile-time constant that varies across conforming types. For example, a
Measurable trait might require a `unit` string and an `always_positive`
boolean to validate measurements.

Common trait-provided values include constants (like seeds), and trait
compositions for refinements.

Referencing `comptime` members works just like referencing struct
parameters. You can reference a member using dot syntax (such as
`Self.IteratorType`).

#### `comptime` members as enumerations

Some Mojo types use `comptime` members to express enumerations. For example, the
following code defines a `Sentiment` type that defines `comptime` constants
for different sentiment values:

```mojo
@fieldwise_init
struct Sentiment(Equatable, ImplicitlyCopyable):
    var _value: Int

    comptime NEGATIVE = Sentiment(0)
    comptime NEUTRAL = Sentiment(1)
    comptime POSITIVE = Sentiment(2)

    def __eq__(self, other: Self) -> Bool:
        return self._value == other._value

    def __ne__(self, other: Self) -> Bool:
        return not (self == other)

def is_happy(s: Sentiment):
    if s == Sentiment.POSITIVE:
        print("Yes. 😀")
    else:
        print("No. ☹️")
```

This pattern provides a type-safe enumeration.

The [`DType`](/docs/std/builtin/dtype/DType/) struct implements a simple enum
using `comptime` members like this. This allows clients to use values like
`DType.float32` in parameter expressions or run-time expressions.

#### `comptime` members as associated types

Associated types are a common use for `comptime` members. For example, a
`List[T]` struct holds values of type `T`. The list's `__iter__()` method
returns a list iterator that returns values of type `T`. `List` uses a
`comptime` member, `IteratorType`, to define the type of the returned iterator.

The following code excerpt shows a simplified version of some of the `List`
code, showing the `List` and its associated `IteratorType`:

```mojo no-test
@fieldwise_init
struct _ListIter[
    mut: Bool,
    //,
    T: Copyable,
    origin: Origin[mut],
](ImplicitlyCopyable, Iterable, Iterator):

    comptime Element = Self.T  # Required by the Iterator trait

    var index: Int
    var src: Pointer[List[Self.Element], Self.origin]

    # ... implementation omitted

struct List[T: Copyable](https://mojolang.org/docs/manual/parameters/Boolable, Copyable, Defaultable, Iterable, Sized.md):
    comptime IteratorType[
        iterable_mut: Bool, //, iterable_origin: Origin[iterable_mut]
    ]: Iterator = _ListIter[Self.T, iterable_origin]

    # ... code omitted

    def __iter__(ref self) -> Self.IteratorType[origin_of(self)]:
        return {0, Pointer(to=self)}

    # ... code omitted
```

The `IteratorType` member is parameterized on an origin, so it can
represent both mutable and immutable iterators.

### Struct methods

A struct's method can take its own parameters. For example, the `SIMD.slice()`
method takes a `size` parameter:

```mojo
var m = SIMD[DType.int32, 4](https://mojolang.org/docs/manual/parameters/1, 3, 5, 7.md)
var n = m.slice[2]()
print(n)  # prints [1, 3]
```

A struct's lifecycle methods (`__init__()` and `__del__()`) are an exception to
this rule—they can't take parameters.

### Case study: the SIMD type

For a real-world example of a parameterized type, let's look at the
[`SIMD`](/docs/std/builtin/simd/SIMD/) type from Mojo's standard library.

[Single instruction, multiple data (SIMD)](https://en.wikipedia.org/wiki/Single_instruction,_multiple_data)
is a parallel processing technology built into many modern CPUs, GPUs, and
custom accelerators. SIMD allows you to perform a single operation on multiple
pieces of data at once. For example, if you want to take the square root of each
element in an array, you can use SIMD to parallelize the work.

Processors implement SIMD using low-level vector registers in hardware that hold
multiple instances of a scalar data type. To use the SIMD instructions
on these processors, the data must be shaped into the proper SIMD width
(data type) and length (vector size). Processors may support 512-bit or
longer SIMD vectors, and support many data types from 8-bit integers to 64-bit
floating point numbers, so it's not practical to define all of the possible SIMD
variations.

Mojo's [`SIMD`](/docs/std/builtin/simd/SIMD/) type (defined as a struct)
exposes the common SIMD operations through its methods, and takes the SIMD data
type and size values as parameters. This allows you to directly map your data to
the SIMD vectors on any hardware.

Here's a cut-down (non-functional) version of Mojo's `SIMD` type definition:

```mojo no-test
struct SIMD[dtype: DType, size: Int]:
    var value: … # Some low-level MLIR stuff here

    # Create a new SIMD from a number of scalars
    def __init__(out self, *elems: SIMD[Self.dtype, 1]):  ...

    # Fill a SIMD with a duplicated scalar value.
    @staticmethod
    def splat(x: SIMD[Self.dtype, 1]) -> SIMD[Self.dtype, Self.size]: ...

    # Cast the elements of the SIMD to a different elt type.
    def cast[target: DType](https://mojolang.org/docs/manual/parameters/self.md) -> SIMD[target, Self.size]: ...

    # Many standard operators are supported.
    def __add__(self, rhs: Self) -> Self: ...
```

So you can create and use a SIMD vector like this:

```mojo
var vector = SIMD[DType.int16, 4](https://mojolang.org/docs/manual/parameters/1, 2, 3, 4.md)
vector = vector * vector
for i in range(4):
    print(vector[i], end=" ")
```

```output
1 4 9 16
```

As you can see, a simple arithmetic operator like `*` applied to a pair of
`SIMD` vector operates on the corresponding elements in each vector.

Defining each SIMD variant with parameters is great for code reuse because the
`SIMD` type can express all the different vector variants statically, instead of
requiring the language to pre-define every variant.

Because `SIMD` is a parameterized type, the `self` argument in its functions
carries those parameters—the full type name is `SIMD[type, size]`. Although
it's valid to write this out (as shown in the return type of `splat()`), this
can be verbose, so we recommend using the `Self` type (from
[PEP673](https://peps.python.org/pep-0673/)) like the `__add__()` example does.

## Using parameterized types and functions

You can use parameterized types and functions by passing values to the
parameters in square brackets. For example, for the `SIMD` type above, `dtype`
specifies the data type and `size` specifies the length of the SIMD vector
(which must be a power of 2):

```mojo
# Make a vector of 4 floats.
var small_vec = SIMD[DType.float32, 4](https://mojolang.org/docs/manual/parameters/1.0, 2.0, 3.0, 4.0)

# Make a big vector containing 1.0 in float16 format.
var big_vec = SIMD[DType.float16, 32](https://mojolang.org/docs/manual/parameters/1.0)

# Do some math and convert the elements to float32.
var bigger_vec = (big_vec + big_vec).cast[DType.float32]()
```

Note that the `cast()` method also needs a parameter to specify the type you
want from the cast (the method definition above expects a `target` parameter
value). Thus, just as the `SIMD` struct is a generic type definition, the
`cast()` method is a generic method definition. At compile time, the compiler
creates a concrete version of the `cast()` method with the target parameter
bound to `DType.float32`.

The code above shows the use of concrete types (that is, the parameters are all
bound to known values). But the major power of parameters comes from the ability
to define parameterized algorithms and types (code that uses the parameter
values). For example, here's how to define a parameterized algorithm with
`Scalar` that is datatype agnostic:

```mojo
from std.math import sqrt

def rsqrt[dt: DType](https://mojolang.org/docs/manual/parameters/x: Scalar[dt].md) -> Scalar[dt]:
    return 1 / sqrt(x)

def main():
    var v = Scalar[DType.float16](https://mojolang.org/docs/manual/parameters/42.md)
    print(rsqrt(v))
```

```output
0.154296875
```

When you write a type expression with square brackets, like `List[Int]`, you
must bind (specify a value for) all of the type's parameters. There are two
exceptions to this rule:

- You can explicitly unbind one or more parameters to create a
  [partially-bound or unbound type](#partially-bound-and-unbound-types).

- You can omit parameters if Mojo can infer them from context.

### Parameter inference

The Mojo compiler can often *infer* parameter values, so you don't always have
to specify them. For example, in the previous section, this is how we called
the parameterized `rsqrt()` function:

```mojo
var v = Scalar[DType.float16](https://mojolang.org/docs/manual/parameters/42.md)
print(rsqrt(v))
```

The compiler infers the `dt` parameter based on the type of the `v`
value passed into it, as if you wrote `rsqrt[DType.float16](https://mojolang.org/docs/manual/parameters/v.md)` explicitly.
Figure 1 shows a mental model for how parameter inference works.

<!--  rumdl-disable MD033 -->

<figure>

![](../images/parameters/parameter-inference.png#light)
![](../images/parameters/parameter-inference-dark.png#dark)

<figcaption>**Figure 1.** Parameter inference</figcaption>
</figure>

<!--  rumdl-enable MD033 -->

Parameter inference can seem a little confusing: it might seem like the compiler
is inferring compile-time parameter values from run-time argument values. But in
fact it's inferring parameters from the statically-known *types* of the
arguments.

:::note Inference failures

If parameter inference fails, the compiler reports an error, usually "failed
to infer parameter 'param_name'". Unfortunately, the compiler also sometimes
reports this error incorrectly, for example, when the actual error is a type
mismatch. In these cases, specifying the missing parameters explicitly often
allows Mojo to report the correct error.

:::

Mojo can also infer the values of struct parameters from the arguments passed to
a constructor or static method.

For example, consider the following struct:

```mojo
struct One[Type: Writable & Copyable & ImplicitlyDestructible]:
    var value: Self.Type

    def __init__(out self, value: Self.Type):
        self.value = value.copy()

def use_one():
    s1 = One(123)  # equivalent to One[Int](https://mojolang.org/docs/manual/parameters/123.md)
    s2 = One("Hello")  # equivalent to One[String](https://mojolang.org/docs/manual/parameters/"Hello".md)
```

Note that you can create an instance of `One` without specifying the `Type`
parameter—Mojo can infer it from the `value` argument.

You can also infer parameters from a parameterized type passed to a constructor
or static method:

```mojo
struct Two[Type: Writable & Copyable & ImplicitlyDestructible]:
    var val1: Self.Type
    var val2: Self.Type

    def __init__(out self, one: One[Self.Type], another: One[Self.Type]):
        self.val1 = one.value.copy()
        self.val2 = another.value.copy()
        print(String(self.val1), String(self.val2))

    @staticmethod
    def fire(thing1: One[Self.Type], thing2: One[Self.Type]):
        print("🔥", String(thing1.value), String(thing2.value))

def use_two() raises:
    s3 = Two(One("infer"), One("me"))  # prints: infer me
    Two.fire(One(1), One(2))  # prints: 🔥 1 2
    # Two.fire(One("mixed"), One(0))  # Error: parameter inferred to two different values
```

`Two` takes a `Type` parameter, and its constructor takes values of type
`One[Type]`. When constructing an instance of `Two`, you don't need to specify
the `Type` parameter, since it can be inferred from the arguments.

Similarly, the static `fire()` method takes values of type `One[Type]`, so Mojo
can infer the `Type` value at compile time. Note that passing two instances of
`One` with different types doesn't work.

:::note

If you're familiar with C++, you may recognize this as similar to Class Template
Argument Deduction (CTAD).

:::

## Parameter declarations

When you declare parameters on a struct or function, you have many of the same
options as you have with arguments—you can define optional parameters with
default values; keyword-only parameters; and variadic parameters.

In addition, you can define *infer-only parameters*, which provide a flexible
way of defining dependencies between parameterized types.

### Optional parameters and keyword parameters

Just as you can specify [optional
arguments](/docs/manual/functions#optional-arguments) in function signatures,
you can also define an optional *parameter* by giving it a default value.

You can also pass parameters by keyword, just like you can use
[keyword arguments](/docs/manual/functions/#keyword-arguments).
For a function or struct with multiple optional parameters, using keywords
allows you to pass only the parameters you want to specify, regardless of
their position in the function signature.

For example, here's a function with two parameters, each with a default value:

```mojo
def speak[a: Int = 3, msg: String = "woof"]():
    print(msg, a)

def use_defaults():
    speak()  # prints 'woof 3'
    speak[5]()  # prints 'woof 5'
    speak[7, "meow"]()  # prints 'meow 7'
    speak[msg="baaa"]()  # prints 'baaa 3'
```

Recall that when a parameterized function is called, Mojo can
[infer the parameter values](#parameter-inference). That is, it can determine
its parameter values from the parameters attached to an argument. If the
parameterized function also has a default value defined, then the inferred
parameter value takes precedence.

For example, in the following code, we update the parameterized `speak[]()`
function to take an argument with a parameterized type. Although the function
has a default parameter value for `a`, Mojo instead uses the inferred `a`
parameter value from the `bar` argument (as written, the default `a` value can
never be used, but this is just for demonstration purposes):

```mojo
@fieldwise_init
struct Bar[v: Int]:
    pass

def speak[a: Int = 3, msg: String = "woof"](https://mojolang.org/docs/manual/parameters/bar: Bar[a].md):
    print(msg, a)

def use_inferred():
    speak(Bar[9]())  # prints 'woof 9'
```

As mentioned above, you can also use optional parameters and keyword
parameters in a struct:

```mojo
struct KwParamStruct[greeting: String = "Hello", name: String = "🔥mojo🔥"]:
    def __init__(out self):
        print(Self.greeting, Self.name)

def use_kw_params():
    var a = KwParamStruct[]()  # prints 'Hello 🔥mojo🔥'
    var b = KwParamStruct[name="World"]()  # prints 'Hello World'
    var c = KwParamStruct[greeting="Hola"]()  # prints 'Hola 🔥mojo🔥'
```

:::note

Mojo supports positional-only and keyword-only parameters, following the same
rules as [positional-only and keyword-only
arguments](/docs/manual/functions#positional-only-and-keyword-only-arguments).

:::

### Variadic parameters

Mojo also supports variadic parameters, similar to
[Variadic arguments](/docs/manual/functions/#variadic-arguments):

```mojo
struct MyTensor[*dimensions: Int]:
    pass
```

Variadic parameters currently have some limitations that variadic arguments
don't have:

- Variadic parameters must be homogeneous—that is, all the values must be the
  same type.

- The parameter type must be register-passable.

Variadic keyword parameters (for example, `**kwparams`) are
not supported yet.

### Infer-only parameters

Sometimes you need to declare functions where parameters depend on other
parameters. Because the signature is processed left to right, a parameter can
only *depend* on a parameter earlier in the parameter list. For example:

```mojo no-test
def dependent_type[dtype: DType, value: Scalar[dtype]]():
    print("Value: ", value)
    print("Value is floating-point: ", dtype.is_floating_point())

dependent_type[DType.float64, Float64(2.2)]()
```

```output
Value:  2.2000000000000002
Value is floating-point:  True
```

You can't reverse the position of the `dtype` and `value` parameters, because
`value` depends on `dtype`. However, because `dtype` is a required parameter,
you can't leave it out of the parameter list and let Mojo infer it from `value`:

```mojo no-test
dependent_type[Float64(2.2)]() # Error!
```

Infer-only parameters are a special class of parameters that are **always**
either inferred from context or specified by keyword. Infer-only parameters are
placed at the **beginning** of the parameter list, set off from other parameters
by the `//` sigil:

```mojo no-test
def example[T: Copyable, //, list: List[T]]()
```

Transforming `dtype` into an infer-only parameter solves this problem:

```mojo
def dependent_type[dtype: DType, //, value: Scalar[dtype]]():
    print("Value: ", value)
    print("Value is floating-point: ", dtype.is_floating_point())
```

```mojo
dependent_type[Float64(2.2)]()
```

```output
Value:  2.2000000000000002
Value is floating-point:  True
```

Because infer-only parameters are declared at the beginning of the parameter
list, other parameters can depend on them, and the compiler always attempts
to infer the infer-only values from bound parameters or arguments.

There are sometimes cases where it's useful to specify an infer-only parameter
by keyword. For example, the
[`Span`](/docs/std/memory/span/Span/) type
is parameterized on [origin](/docs/manual/values/lifetimes/):

```mojo no-test
struct Span[mut: Bool, //, T: Copyable, origin: Origin[mut]]:
    # ... implementation omitted
```

Here, the `mut` parameter is infer-only. The value is usually inferred when you
create an instance of `Span`. Binding the `mut` parameter by keyword lets you
define a `Span` that requires a mutable origin.

```mojo
def mutate_span(span: Span[mut=True, Byte, ...]):
    for i in range(0, len(span), 2):
        if i + 1 < len(span):
            span.swap_elements(i, i + 1)
```

If the compiler can't infer the value of an infer-only parameter, and it's not
specified by keyword, compilation fails.

## Parameter expressions are just Mojo code

A parameter expression is any code expression (such as `a+b`) that occurs where
a parameter is expected. Parameter expressions support operators and function
calls, just like run-time code, and all parameter types use the same type
system as the run-time program (such as `Int` and `DType`).

Because parameter expressions use the same grammar and types as run-time
Mojo code, you can use many
["dependent type"](https://en.wikipedia.org/wiki/Dependent_type) features. For
example, you might want to define a helper function to concatenate two SIMD
vectors:

```mojo
def concat[
    dtype: DType, ls_size: Int, rh_size: Int, //
](https://mojolang.org/docs/manual/parameters/lhs: SIMD[dtype, ls_size], rhs: SIMD[dtype, rh_size].md) -> SIMD[
    dtype, ls_size + rh_size
]:
    var result = SIMD[dtype, ls_size + rh_size]()

    comptime for i in range(ls_size):
        result[i] = lhs[i]

    comptime for j in range(rh_size):
        result[ls_size + j] = rhs[j]
    return result
```

Note that the resulting length is the sum of the input vector lengths, and a
simple `+` operation expresses this.

### Powerful compile-time programming

While simple expressions are useful, sometimes you want to write imperative
compile-time logic with control flow. You can even do compile-time recursion.
For instance, here is an example "tree reduction" algorithm that sums all
elements of a vector recursively into a scalar:

```mojo
def slice[
    dtype: DType, size: Int, //
](https://mojolang.org/docs/manual/parameters/x: SIMD[dtype, size], offset: Int.md) -> SIMD[dtype, size // 2]:
    comptime new_size = size // 2
    var result = SIMD[dtype, new_size]()
    for i in range(new_size):
        result[i] = Scalar[dtype](https://mojolang.org/docs/manual/parameters/x[i + offset].md)
    return result

def reduce_add(x: SIMD) -> Int:
    comptime if x.size == 1:
        return Int(x[0])
    elif x.size == 2:
        return Int(x[0]) + Int(x[1])

    # Extract the top/bottom halves, add them, sum the elements.
    comptime half_size = x.size // 2
    var lhs = slice(x, 0)
    var rhs = slice(x, half_size)
    return reduce_add(lhs + rhs)

def main():
    var x = SIMD[DType.int, 4](https://mojolang.org/docs/manual/parameters/1, 2, 3, 4.md)
    print(x)
    print("Elements sum:", reduce_add(x))
```

```output
[1, 2, 3, 4]
Elements sum: 10
```

This makes use of the
[`comptime if`](/docs/manual/metaprogramming/comptime-evaluation/#comptime-if)
statement, which is an `if` statement that runs at compile-time. It requires
that its condition be a valid parameter expression, and ensures that only the
live branch of the `if` statement is compiled into the program. This is similar
to use of the `comptime for` loop shown earlier.

## Parameterized `comptime` values

A *parameterized `comptime` value* is a compile-time expression that takes a
list of parameters and returns a compile-time constant value:

```mojo
comptime AddOne[a: Int] : Int = a + 1

comptime nine = AddOne[8]
```

As you can see in the previous example, a parameterized `comptime` value is a
little like a *compile-time-only function*. A regular function or method can
also be invoked at compile time:

```mojo
def add_one(a: Int) -> Int:
    return a + 1

comptime ten = add_one(9)
```

A major difference between a function and a parameterized `comptime` value is
that the value of a `comptime` expression can be a type, while a function can't
return a type as a value.

```mojo no-test
# Does not work—-dynamic type values not permitted
def int_type() -> AnyType:
    return Int

# Works
comptime IntType = Int
```

Because a `comptime` value can be a type, you can use parameterized `comptime`
values to express new types:

```mojo
comptime TwoOfAKind[dt: DType] = SIMD[dt, 2]
twoFloats = TwoOfAKind[DType.float32](https://mojolang.org/docs/manual/parameters/1.0, 2.0)

comptime StringKeyDict[ValueType: Copyable & ImplicitlyDestructible] = Dict[
    String, ValueType
]
var b: StringKeyDict[UInt8] = {"answer": 42}
```

Parameterized `comptime` declarations support the same features as parameterized
structs or functions: infer-only parameters, keyword-only and optional
parameters, [automatic parameterization](#automatic-parameterization), and so
on.

```mojo
comptime Floats[size: Int, half_width: Bool = False] = SIMD[
    (DType.float16 if half_width else DType.float32), size
]
var floats = Floats[2](https://mojolang.org/docs/manual/parameters/6.0, 8.0)
var half_floats = Floats[2, True](https://mojolang.org/docs/manual/parameters/10.0, 12.0)
```

## Partially-bound and unbound types

A parameterized type with its parameters specified is said to be *fully-bound*.
That is, all of its parameters are bound to values. As mentioned before, you can
only instantiate a fully-bound type (sometimes called a *concrete type*).

However, parameterized types can be *unbound* or *partially bound* in some
contexts. For example, you can use `comptime` to create a type alias to a
partially-bound type to create a new type that requires fewer parameters:

```mojo
comptime StringKeyDict = Dict[String, _]
var b: StringKeyDict[UInt8] = {"answer": 42}
```

Here, `StringKeyDict` is a type alias for a `Dict` that takes `String` keys. The
underscore `_` in the parameter list indicates that the second parameter,
`V` (the value type), is unbound.
You specify the `V` parameter later, when you use `StringKeyDict`.

When used as a `comptime` value, any default values on unbound parameters are
retained until a concrete type is formed (for example, by calling a struct's
constructor):

```mojo
@fieldwise_init
struct HasDefault[x: Int, y: Int = 0]:
    pass

comptime UseDefault = HasDefault[10]
```

```mojo
var instance1 = UseDefault()  # instance of HasDefault[10, 0]
```

When defining parameterized APIs, you can use partially-bound and unbound types
to express type constraints with less boilerplate, a feature called
[automatic parameterization](#automatic-parameterization):

```mojo no-test
# standard declaration--explicit parameter declarations
def take_simd[dtype: DType, size: Int](https://mojolang.org/docs/manual/parameters/value: SIMD[dtype, size].md): pass

# automatically parameterized declaration
def take_floats(value: SIMD[_, _]): pass
```

You can specify a partially-bound or unbound type several ways:

- Explicitly unbind one or more parameters using an underscore (`_`) in place of
  a parameter value:

  ```mojo
  comptime StringKeyDict = Dict[String, _]

  def take_floats(floats: SIMD[DType.float32, _]): pass
  ```

  When writing a type expression like this, you must bind or explicitly unbind
  every parameter, unless Mojo can infer the parameter from context. For
  example, this produces an error:

  ```mojo
  comptime Bad = Dict[String]  # error: 'Dict' failed to infer parameter 'V'
  ```

- Explicitly unbind an arbitrary number of parameters at the end
  of a parameter list using an ellipsis (`...`):

  ```mojo
  comptime PartiallyBound = SomeComplicatedType[String, ...]
  comptime Unbound = SomeComplicatedType[...]

  def take_simd(v: SIMD[...]): pass
  ```

  Using an ellipsis unbinds any remaining parameters in the list,
  including keyword parameters.

- Use the bare identifier with no square brackets to specify an
  unbound type:

  ```mojo
  comptime SomeAlias = SomeComplicatedType

  def take_simd2(v: SIMD): pass
  ```

  As a matter of style, `SIMD[...]` or `SIMD[_, _]` is usually preferable to the
  bare `SIMD`. The former versions are more explicit, and provide a visual cue
  to readers that they're looking at a parameterized type.

### Partially-bound types versus parameterized comptime values

You may notice that the `comptime` examples in this section look similar
to the examples in the section on
[parameterized `comptime` values](#parameterized-comptime-values). For
example, you could define the `StringKeyDict` alias using either syntax:

```mojo no-test
# partially-bound type
comptime StringKeyDict = Dict[String, _]
# parameterized comptime value
comptime StringKeyDict[V] = Dict[String, V]
```

For simple type aliases, you can use either a partially-bound type or a
parameterized `comptime` value. For more complex aliases, parameterized
`comptime` values give you a great deal more flexibility.

## Automatic parameterization

Writing heavily-parameterized APIs often produces long, repetitive signatures.
For example, to define a function that takes any kind of `SIMD` value, you could
write this:

```mojo no-test
def take_simd[dtype: DType, size: Int, //](https://mojolang.org/docs/manual/parameters/vec: SIMD[dtype, size].md): 
    pass
```

This signature represents a function that takes any `SIMD` value,
inferring its `dtype` and `size` parameters. But it's a lot of code
to do something pretty simple.

To make it easier to write signatures like this, Mojo supports "automatic"
parameterization. Instead of explicitly naming each parameter in the argument
type, you specify a
[partially-bound or unbound type](#partially-bound-and-unbound-types):

```mojo
def take_simd(vec: SIMD[...]):
    print(vec.dtype)
    print(vec.size)
```

```mojo
var v = SIMD[DType.float64, 4](https://mojolang.org/docs/manual/parameters/1.0, 2.0, 3.0, 4.0)
take_simd(v)
```

```output
float64
4
```

In the above example, the `take_simd()` function is automatically parameterized.
The `vec` argument takes a value of type `SIMD[...]`—an unbound parameterized
type. Mojo treats the unbound parameters on `vec` as infer-only parameters on
the function. This is roughly equivalent to the following code:

```mojo no-test
def take_simd[t: DType, s: Int, //](https://mojolang.org/docs/manual/parameters/vec: SIMD[t, s].md):
    print(t)
    print(s)
```

When you call `take_simd()` you must pass it a concrete instance of the
`SIMD` type—that is, one with all of its parameters specified, like
`SIMD[DType.float64, 4]`. The Mojo compiler *infers* the parameter
values from the input argument.

You can also use automatic parameterization with a partially bound type:

```mojo no-test
def take_floats(floats: SIMD[DType.float32, _]): pass
```

There are two important differences between a manually-parameterized
signature and an automatically-parameterized signature:

- With a manually-parameterized function, you can access the parameters by name
  (for example, `t` and `s` in the previous example), which is not an option in
  an automatically parameterized function.

  However, you can always access a type's parameters and `comptime` members
  using dot syntax—as in the automatic parameterization example, which used
  `vec.dtype` and `vec.size` to access parameters on the argument.

- With the manually-parameterized function, you can pass the parameter value
  directly; that's not an option with automatically-parameterized functions.
  The unbound parameters are always inferred.

In addition to using automatic parameterization in the argument list of a
function, you can also use it in the parameter lists of functions, structs,
and parameterized `comptime` values.

### Examples of automatic parameterization

This section shows more examples of using automatic parameterization.

#### Automatic parameterization of parameters

You can also take advantage of automatic parameterization in the parameter list
of a function, struct, or parameterized `comptime` value. For example:

```mojo no-test
def simd_param[value: SIMD[...]]():
    pass

# Equivalent to:
def simd_param[dtype: DType, size: Int, //, value: SIMD[dtype, size]]():
    pass
```

Here's another example using a parameterized `comptime` value:

```mojo
comptime SomeComptime[s: SIMD[...]] = SomeStruct[s]

# Equivalent to:
comptime SomeComptime2[dtype: DType, size: Int, //, S: SIMD[dtype, size]] = SomeStruct[S]
```

#### Automatic parameterization and type expressions

As previous examples showed, you can access the parameters of an argument
or parameter value using dot syntax (`arg.param`). You can also use this
syntax inside a signature.

For example, if you want your function to take two SIMD vectors with the same
type and size, you can write code like this:

```mojo
def interleave(v1: SIMD[...], v2: type_of(v1)) -> SIMD[v1.dtype, v1.size * 2]:
    var result = SIMD[v1.dtype, v1.size * 2]()

    comptime for i in range(v1.size):
        result[i * 2] = v1[i]
        result[i * 2 + 1] = v2[i]
    return result
```

```mojo
var a = SIMD[DType.int16, 4](https://mojolang.org/docs/manual/parameters/1, 2, 3, 4.md)
var b = SIMD[DType.int16, 4](https://mojolang.org/docs/manual/parameters/0, 0, 0, 0.md)
var c = interleave(a, b)
print(c)
```

```output
[1, 0, 2, 0, 3, 0, 4, 0]
```

As shown in the example, you can use the magic `type_of(x)` expression if you
just want to match the type of an argument. In this case, it's more convenient
and compact than writing the equivalent `SIMD[v1.dtype, v1.size]`.

#### Automatic parameterization with partially-bound types

Mojo also supports automatic parameterization: with [partially-bound
parameterized types](#partially-bound-and-unbound-types) (that is,
types with some but not all of the parameters specified).

For example, suppose you have a `Fudge` struct with three parameters:

```mojo
@fieldwise_init
struct Fudge[sugar: Int, cream: Int, chocolate: Int = 7](https://mojolang.org/docs/manual/parameters/Writable.md):
    pass
```

You can write a function that takes a `Fudge` argument with just one bound
parameter (it's *partially bound*):

```mojo
def eat(f: Fudge[5, ...]):
    print("Ate " + String(f))
```

The `eat()` function takes a `Fudge` struct with the first parameter (`sugar`)
bound to the value 5. The second and third parameters, `cream` and `chocolate`
are unbound.

The unbound `cream` and `chocolate` parameters become implicit parameters
on the `eat` function. In practice, this is roughly equivalent to writing:

```mojo no-test
def eat[cr: Int, ch: Int, //](https://mojolang.org/docs/manual/parameters/f: Fudge[5, cr, ch].md):
    print("Ate", String(f))
```

In both cases, you can call the function by passing in an instance with the
`cream` and `chocolate` parameters bound:

```mojo
eat(Fudge[5, 5, 7]())
eat(Fudge[5, 8, 9]())
```

```output
Ate Fudge (5,5,7)
Ate Fudge (5,8,9)
```

If you try to pass in an argument with a `sugar` value other than 5,
compilation fails, because it doesn't match the argument type:

```mojo no-test
eat(Fudge[12, 5, 7]())
# ERROR: invalid call to 'eat': argument #0 cannot be converted from 'Fudge[12, 5, 7]' to 'Fudge[5, 5, 7]'
```

You can also explicitly unbind individual parameters. This gives you
more freedom in specifying unbound parameters.

For example, you might want to let the user specify values for `sugar` and
`chocolate`, and leave `cream` constant. To do this, replace each unbound
parameter value with a single underscore (`_`):

```mojo
def devour(f: Fudge[_, 6, _]):
    print("Devoured", String(f))
```

Again, the unbound parameters (`sugar` and `chocolate`) are added as implicit
parameters on the function.

You can also unbind parameters by keyword, or mix positional and keyword
parameters, so the following function is roughly equivalent to the previous one:
the first parameter, `sugar` is explicitly unbound with the underscore
character. The `chocolate` parameter is unbound using the keyword syntax,
`chocolate=_`. And `cream` is explicitly bound to the value 6:

```mojo no-test
def devour(f: Fudge[_, chocolate=_, cream=6]):
    print("Devoured", String(f))
```

Both versions of the `devour()` function work with the following calls:

```mojo
devour(Fudge[3, 6, 9]())
devour(Fudge[4, 6, 8]())
```

```output
Devoured Fudge (3,6,9)
Devoured Fudge (4,6,8)
```

## Assert parameterized type equality with `rebind()`

One of the consequences of Mojo not performing function instantiation in the
parser like C++ is that Mojo cannot always figure out whether some parameterized
types are equal and complain about an invalid conversion. This typically occurs
in static dispatch patterns. For example, the following code won't compile:

```mojo no-test
def take_simd8(x: SIMD[DType.float32, 8]):
    pass

def generic_simd[nelts: Int](https://mojolang.org/docs/manual/parameters/x: SIMD[DType.float32, nelts]):
    comptime if nelts == 8:
        take_simd8(x)
```

The parser will complain:

```plaintext
error: invalid call to 'take_simd8': argument #0 cannot be converted from
'SIMD[f32, nelts]' to 'SIMD[f32, 8]'
        take_simd8(x)
        ~~~~~~~~~~^~~
```

This is because the parser fully type-checks the function without instantiation,
and the type of `x` is still `SIMD[f32, nelts]`, and not `SIMD[f32, 8]`, despite
the static conditional. The remedy is to manually assert the type of `x`,
using the [`rebind()`](/docs/std/builtin/rebind/rebind/) builtin, which inserts
a compile-time assertion that the input and result types resolve to the same
type after elaboration:

```mojo
def take_simd8(x: SIMD[DType.float32, 8]):
    pass

def generic_simd[nelts: Int](https://mojolang.org/docs/manual/parameters/x: SIMD[DType.float32, nelts]):
    comptime if nelts == 8:
        take_simd8(rebind[SIMD[DType.float32, 8]](x))
```

The compiler still checks that the types match, but does so later, during
elaboration. If the types don't match, compilation fails. There are fairly
simple rules for when to use `rebind()`:

- **Do** use `rebind()` when you know that two parametric types will be
  identical after elaboration.
- **Don't** use `rebind()` to cast between arbitrary data types.

`rebind()` returns a reference to the rebound value. If you need to transfer the
rebound value or assign it to a variable, use the
[`rebind_var()`](/docs/std/builtin/rebind/rebind_var/) function.
