Types and specs in Elixir are not even used at compiletime, except that they get integrated into the compiled modules.
Then the can get evaluated using a tool called dialyzer, which is from the erlang/beam toolchain and not related to elixir (directly).
elixirc does not resolve types, but only stores the information of them into the module, it would telling some false story when they are inlined. As it is now, it is more or less obvious that they are an optional extra.
Also elixirs (and erlangs) type annotations are in a way powerfull that I can’t relly think a way of to express it inline while maintaining readability.
Consider this one (this is a single type and not 4!):
@spec foo(:error) :: 1
@spec foo(:two) :: "two"
@spec foo(integer) :: String.t
@spec foo(list(integer)) :: integer
Or the more classical ones;
@spec map(list(a), fun((a) -> b)) :: list(b) where a: var, b: var
@spec fold(list(a), b, fun((a, b) -> b) :: b where a: var, b: var
These specs are from the deepest areas of my mind, maybe I confused a bit syntax of them with erlang, but roughly they should show what I mean.
There are even specs much more complex you have to think about, just take a look at the contracts for all the
GenServer like behaviours…