Monday, January 30, 2017

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, as well as more 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. As you can see in its documentation, round’s 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 ::, ie, Integer. Function specs are written with the @spec directive, placed right before the function definition. The round function could 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 could use [Integer].

Custom Types

While Elixir provides a lot of useful built-in types, it’s convenient to define custom types when appropriate. This can be done when defining modules through the @type directive. Let us have a look at an example:
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."}
end

{result, comment} = FunnyCalculator.add(10, 20)
IO.puts(result)
IO.puts(comment)
When running above program, it produces following result:
30
"You need a calculator to do that?"
NOTE: Custom types defined through @type are exported and available outside the module they’re defined in. If you want to keep a custom type private, you can use the @typep directive instead of @type.

No comments:

Post a Comment