How to understand and read "t()"?

Here’s a screenshot of part of the Range API:

Screen Shot 2019-12-13 at 10.57.28 PM

What does the Types section communicate?
To whom is it useful?
What is this syntax … Is it Elixir, Dialyzer, or both?
What meanings does t() have?
How is it related to .t often seen on modules?

I didn’t see answers to these in the docs … any pointers are appreciated.

6 Likes

That t() is the type t() in the Range module, or written otherwise Range.t()

Any member of the type %Range{first: integer(), last: integer()) is also a member of t().

The t(first, last) means, that you also can create a range from other types, you could for example spec a function to accept Range.t(float(), float()).

The syntax of the typelanguage is part of elixir as described in the Typespecs section of the elixir manual.

Types and typespecs are used in two ways:

  1. As documentation that humans know what kind of arguments a function can cope with. A reader of the spec disjoint?(Range.t(), Range.t()) :: boolean() knows that they need to pass in 2 ranges and not 2 integers or even an integer and a string. And also they know that this function will return a bool value, meaning either true or false.
  2. Dialyzer can use this information to tell us if we pass correct types into the functions we use.
14 Likes

I guess to me it looks like a function invocation. Should the reader just ignore that? Is it just syntactical noise? Or is t a function which returns the type?

You can think of it as a type constructor. Type constructors can have different arities, like functions. They take parameters which are also types–i.e. type parameters. Think of it as generics.

2 Likes

Don’t think of them as normal functions, you can’t use them as normal functions during runtime. Almost every time, your type function will have arity zero; sometimes (almost never) you might need a parametric type function, in which case it can have an arity nonzero (usually one).

1 Like