Elixir - Typespecs


Elixir is a dynamically typed language, so all types in Elixir are inferred by the runtime. Nonetheless, Elixir comes with typespecs, which are a notation used for declaring custom data types and declaring typed function signatures (specifications).

Function Specifications(specs)

By default, Elixir provides some basic types, such as integer or pid, and also complex types: for example, the round function, which rounds a float to its nearest integer, takes a number as an argument (an integer or a float) and returns an integer. In the related documentation, the round typed signature is written as −

round(number) :: integer

The above description implies that the function on the left takes as argument what is specified in parenthesis and returns what is on the right of ::, i.e., Integer. Function specs are written with the @spec directive, placed right before the function definition. The round function can be written as −

@spec round(number) :: integer
def round(number), do: # Function implementation

Typespecs support complex types as well, for example, if you want to return a list of integers, then you can use [Integer]

Custom Types

While Elixir provides a lot of useful inbuilt types, it is convenient to define custom types when appropriate. This can be done when defining modules through the @type directive. Let us consider an example to understand the same −

defmodule FunnyCalculator do
  @type number_with_joke :: {number, String.t}

  @spec add(number, number) :: number_with_joke
  def add(x, y), do: {x + y, "You need a calculator to do that?"}

  @spec multiply(number, number) :: number_with_joke
  def multiply(x, y), do: {x * y, "It is like addition on steroids."}

{result, comment} = FunnyCalculator.add(10, 20)

When the above program is run, it produces the following result −

You need a calculator to do that?

NOTE − Custom types defined through @type are exported and available outside the module they are defined in. If you want to keep a custom type private, you can use the @typep directive instead of @type.