# Deviations: Functions

## Top-arity Functions

### Rationale

Top-arity functions represent the "top type" for function of a given arity. In the Mavis typesystem, the parameters to the function signature signify "which types may be passed and are guaranteed to not crash the function. Accordingly, the type-signature `any() -> any()` represents a smaller population of functions than the type-signature `integer() -> any()`, as the former type signature represents that all values are guaranteed to succeed, whereas the later represents that only integers are guaranteed to succeed, a less stringent criterion.

Erlang does have a "top type" for functions, namely the any function, which is denoted in Elixir as`... -> any()`. However, it is important to note that there are cases when it is reasonable to be able to select on an arity-specific top type. See the example below.

### Nomenclature

in Mavis, this type is represented as `_, _ -> result_type()`, where the number of underscores corresponds to the arity of this function type.

internally, these functions are represented by placing a positive integer in the `:params` field of the `Type.Function.t` struct.

### Example

``````def my_function(f) when is_function(f, 1) do
:some_result
end``````

should have signature `(_ -> any()) :: :some_result`.

note that Dialyzer gives this function the signature `(any() -> any()) :: :some_result`, which suggests that a lambda passed to `my_function` must be able to tolerate any input. In reality, this function will not crash if passed, for example `:erlang.byte_size/1` which has a more restrictive signature.

A truly `any() -> any()` lambda would be for example `IO.inspect/1`.

### Notes

At this point, it doesn't seem to qualify the `any() -> any()` as a fully qualified "subtype" of the `integer() -> any()`, though that may be implemented later.

There is no zero-arity top-arity function.

### Normalization to erlang function types

the `:params` field is replaced by a list of `any()` types of the appropriate arity. Namely the following happens:

`_ -> any()` to `any() -> any()` `_, _ -> any()` to `any(), any() -> any()`

when performing type inference, any function which is specced to take lambdas with all `any()` parameters should be viewed with suspicion and subjected to inference.