Erlang exclude type from supertype

Viewed 81

In Erlang, is it possible to define a type by excluding a subtype from a supertype? As an example, how would I define a type that is "anything but pid()":

-type anything_but_pid() :: ...?

Reading the docs on supervisor data types, I came across this type spec for child_id(), which defines the type as term(), and then says Not a pid() in a comment below:

child_id() = term()

Not a pid().

Is that the best I can do if I don't want to explicitly list all possible types?

3 Answers

No, as of OTP 23 (and even 24) this is not supported.

Moreover, expecting Dialyzer to help is such cases is ill-advised, as Dialyzer is often over-approximating, for several reasons, and although I don't think that it would turn such a type to term() immediately, it might very well do so at the first given opportunity (e.g. wherever you call such a function).

As a possible workaround for this you may define a specification for your function like this:

    -spec foo(pid()) -> ...;
             (any()) -> ...
    foo(data) when is_pid(data) -> error;
    foo(data) -> ....

Specifically for anything_but_pid(), you could "simply" enumerate all other options:

-type anything_but_pid() :: port()
                          | reference()
                          | atom()
                          | bitstring()
                          | number()
                          | fun()
                          | maybe_improper_list()
                          | map()
                          | tuple()

Of course, this doesn't generalize...

Related