Do Elixir typespecs allow multiple clauses like Erlang's do?

810 views
Skip to first unread message

Myron Marston

unread,
Dec 11, 2016, 3:11:59 PM12/11/16
to elixir-lang-core

Today I was reading through http://learnyousomeerlang.com/dialyzer and stumbled across this:

-spec convert(tuple()) -> list();
  (list()) -> tuple().
convert(Tup) when is_tuple(Tup) -> tuple_to_list(Tup);
convert(L = [_|_]) -> list_to_tuple(L).

Rather than putting tuple() and list() types together into a single union, this syntax allows you to declare type signatures with alternative clauses. If you call convert/1 with a tuple, we expect a list, and the opposite in the other case.

I’ve never seen this in Elixir typespecs before and the docs make no mention of Elixir supporting multiple clauses in a type spec. Is this something Elixir supports (or could it in the future)? I can imagine a syntax like:

@spec convert(tuple) :: list
@spec convert(list) :: tuple
def convert(tup) when is_tuple(tup), do: Tuple.to_list(tup)def convert([_ | _] = list), do: List.to_tuple(list)

Basically, just allowing us to list multiple type spec clauses sequentially like we do with function clauses, with line breaks in between.

If this is already supported, I can work on updating the type spec docs to mention it.

Thanks,
Myron

Michał Muskała

unread,
Dec 11, 2016, 3:56:23 PM12/11/16
to elixir-l...@googlegroups.com
As far as I know it should "just work™".

Michał.
> --
> You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/6bf79af0-6f26-42f7-83e6-35c7f0b7c37f%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

eksperimental

unread,
Dec 11, 2016, 4:08:53 PM12/11/16
to elixir-l...@googlegroups.com
It's not common, but it is supported

lib/elixir/lib/file.ex
1006: @spec open(Path.t, [mode | :ram]) :: {:ok, io_device} | {:error, posix}
1007: @spec open(Path.t, (io_device -> res)) :: {:ok, res} | {:error, posix} when res: var

lib/elixir/lib/file.ex
1061: @spec open!(Path.t, [mode | :ram]) :: io_device | no_return
1062: @spec open!(Path.t, (io_device -> res)) :: res | no_return when res: var

Adding that to the Typespecs page would be good!

Myron Marston

unread,
Dec 11, 2016, 5:15:31 PM12/11/16
to elixir-lang-core, eksper...@autistici.org
Looks like it's already mentioned, and I somehow have missed it even though I've read the typespec docs a few times:

Reply all
Reply to author
Forward
0 new messages