Andriy Drozdyuk
Andriy Drozdyuk

Reputation: 61121

How to document a type as just a name?

Looking at Erlang docs, sometimes I come across type specs, that document a function type without really specifying the type...

Hard to explain, so let me give you an example. In the gen_server the handle_call function shows up as the following in the docs:

Request = term()
From = {pid(),Tag}
State = term()
Result = {reply,Reply,NewState} | {reply,Reply,NewState,Timeout}
  | {reply,Reply,NewState,hibernate}
  | {noreply,NewState} | {noreply,NewState,Timeout}
  | {noreply,NewState,hibernate}
  | {stop,Reason,Reply,NewState} | {stop,Reason,NewState}
 Reply = term()
 NewState = term()
 Timeout = int()>=0 | infinity
 Reason = term()

Here the type Tag is never shown (i.e. it's just a variable name).

Is the same possible to do with edoc? The closest I found was opaque type spec, but that documents it as abstract - is that the same?

Upvotes: 2

Views: 125

Answers (2)

Vinod
Vinod

Reputation: 2243

It is possible as long as the argument variable name in the function (in all clauses) and that name used in the @spec are same. For example.

%% @spec start_link(Args) -> {ok, pid()}
start_link(Args) ->
    gen_server:start_link(?MODULE, Args, []).

will generate the following doc

start_link(Args) -> {ok, pid()}

If you have a different name for example

%% @spec start_link(Args) -> {ok, pid()}
start_link(Num) when is_integer(Num) ->
    gen_server:start_link(?MODULE, [], []);
start_link(Args) ->
    gen_server:start_link(?MODULE, Args, []).

It would generate as

start_link(Num::Args) -> {ok, pid()}

assuming Args as a type.

I would personally not recommend to use edoc @spec and instead use -spec as they are used by dialyzer and hence can be validated.

edoc can generate the doc from -spec too. Given both -spec and @spec, edoc overrides to @spec directive.

%% @spec start_link(Args) -> {ok, Pid}
-spec start_link(term()) -> {ok, pid()}.
start_link(Args) ->
    gen_server:start_link(?MODULE, Args, []).

Above will result in

start_link(Args) -> {ok, Pid}

And removing @spec from above will result in

start_link(Args::term()) -> {ok, pid()}

Upvotes: 2

legoscia
legoscia

Reputation: 41618

As far as I can see, this is not possible with Edoc.

I tried using a spec like this:

-spec foo(Something) -> term().
foo(X) ->
    X.

And while Edoc is actually happy about it, and gives the type spec as foo(Something) in the docs without specifying what Something is, the compiler complains about it, and says:

type variable 'Something' is only used once (is unbound)

So you'd have to write:

-spec foo(Something::_) -> term().
foo(X) ->
    X.

which shows up as foo(Something::term()), thereby giving a type specification for Something.

Using an Edoc-only type specification:

%% @spec foo(Something) -> term()
foo(X) ->
    X.

Edoc treats Something as a type name that applies to the variable X and puts foo(X::Something) in the documentation.

So neither way would do exactly what you want to achieve.

Upvotes: 0

Related Questions