Typed list typespec never breaks the contract

625 views Asked by At

If you define a typespec and use a different type of parameter it will display an error similar to:

binary() ... breaks the contract ... boolean()

For example this typespec:

@spec check?(binary) :: boolean

But it doesnt seem to work for a typed List, or at least, it will never display the warning, if I have a method which receives a list of strings I would define this typespec:

@spec check?([String.t]) :: boolean

I can then define any spec for the list and it will never complain when running a dialyzer, i.e:

@spec check?(list(boolean)) :: boolean
@spec check?(list(Conn)) :: boolean
@spec check?(list(number)) :: boolean
@spec check?(list(integer)) :: boolean

Is that intended? it looks like if I defined a list with any type [any()]

Is there other way to achieve this?

1

There are 1 answers

0
legoscia On BEST ANSWER

The reason this happens is that all the list types include the empty list as a valid value.

For example, in the following case:

  • you call the function with a possibly empty list of booleans
  • the function accepts a possibly empty list of strings

Dialyzer will conclude that there is a possible solution, namely if the list is empty. Since Dialyzer only prints warnings if it can conclude that a certain piece of code will always crash, it doesn't print one in this case.

I'm not aware of any good solution to this. If you want to explicitly require non-empty lists, you can use e.g. nonempty_list(boolean) instead of list(boolean).