Erlang/OTP Forums

Author Message

<  Erlang questions mailing list  ~  Best practice for defining functions with edoc,erlc,eunit a

Guest
Posted: Wed Dec 02, 2009 11:10 am Reply with quote
Guest
> Best practice for writing documenting and testing code
>
> I'd like to try and define "best practice" for writing documenting and
> testing Erlang code. I want to use:
>
> - only the tools supplied in the OTP release
>
> So I use:
>
> - eunit for unit testing
> - the dialyzer for checking my code
> - edoc for documenting things
> - type specifications for specifying types

> Now for questions.
>
> 1) Does this represent best practice? Is this the best way to
> write code? - can anybody improve on this?

It almost fits for me. I'm only separating functional and test code into different modules (I've
allways done so in other languages before, so just called it a habit.). And I use the module
documentation more. Take a look at
http://code.google.com/p/tideland-cel/source/browse/trunk/src/celjob.erl and
http://code.google.com/p/tideland-cel/source/browse/trunk/src/celjobtst.erl.

I'll change all my function comments to use the -spec notation.

> 3) Does anything else have to be fixed?

I'm not happy with the mixed notation in comments or using -spec. So it should be @spec in a
comment or -doc handled like -spec.

> 4) Improvements..
>
> I can think of one. I have some code to convert .erl to
> .html with correctly colored code and hyperlinks etc.
> So I can "surf" the code. It would be nice to have hooks
> into edoc so I can call this code

Sounds great, yes.

Warm regards

mue

--
**
** Frank Mueller / Oldenburg / Germany
**


________________________________________________________________
erlang-questions mailing list. See http://www.erlang.org/faq.html
erlang-questions (at) erlang.org

Post received from mailinglist
Guest
Posted: Thu Dec 03, 2009 9:59 am Reply with quote
Guest
>
> On Dec 2, 2009, at 11:31 PM, Zoltan Lajos Kis wrote:
>>>
>> One more thing that can be addressed is the order of exporting (and
>> defining) functions. My preference is to:
>> - 1, export API functions
>> - 2, export Behavior callback functions (a separate export line for
>> each behavior)
>> - 3, export internal functions. The functions that you _don't want
>> to export_, but Erlang makes you to do so in order to use them in
>> spawns, applys, etc.
>>
>
> Could I make a plea for
> - a SINGLE export list for all "API" (horrible term) functions
> - in alphabetic order

Sorry. Borrowed the term from the Erlang/OTP source code Smile

>
>> Something like:
>>
>> %% API
>> -export([start_link/0, update/0, get/1, put/2, ...]).
>
> Something like
>
> -export([
> get/1,
> put/2,
> start_link/0,
> update/0
> ]).
>
> It's just that much easier to see what the module is all about.
> Someone using emacs can easily keep such a list in order using
> sort-lines.

I prefer to group the "API" functions based on their functionality and
order them by the order they will most probably be used.
In my config server example start_link / update will be used by the
supervisor/management hierarchy, while get and put will be used by whoever
needs something.

>
>>
>>
>> %% Behavior callbacks
>> -behaviour(gen_server).
>> -export([init/1, handle_call/3, handle_cast/2, ...]).
>
> Years ago I recommended that the syntax should be extended
> to
> -behaviour(Behaviour, [Callback...]).
> so that a cross-checking tool could tell that these functions
> were *intended* to be used as callbacks by that behaviour and
> weren't just accidentally adjacent.

A simple -behavior(Behavior). could be interpreted by the compiler as
exporting all of the behavior's callback functions. That would trigger a
compiler error if you forgot to implement one.

>
>>
>>
>> %% Internal functions
>> -export([spawnee/0, applyee/2, ...]).
>
> Now that we have spawn(fun () -> ... end) and F(...),
> we shouldn't need this group at all.
>

In general you can argue that all of these internal functions can be
handled as callbacks, and thus put into behaviors, and exported as such.
Nevertheless grep for "internal exports" in the Erlang/OTP source. There
is quite a lot of them.

Regards,
Zoltan.


________________________________________________________________
erlang-questions mailing list. See http://www.erlang.org/faq.html
erlang-questions (at) erlang.org

Post received from mailinglist
axel
Posted: Thu Dec 03, 2009 11:11 am Reply with quote
User Joined: 03 Mar 2005 Posts: 271
Greetings,

If the Erlang/OTP source that has "internal exports" is old, it could
pre-date the existence of erlang:spawn/1. In that case it would not be a
good example.

Regarding exports I always have them in a single, sorted, list since it
makes it easier for humans to find out which functions that are
exported.


bengt

On Thu, 2009-12-03 at 10:55 +0100, Zoltan Lajos Kis wrote:
> >
> > On Dec 2, 2009, at 11:31 PM, Zoltan Lajos Kis wrote:
> >>>
> >> One more thing that can be addressed is the order of exporting (and
> >> defining) functions. My preference is to:
> >> - 1, export API functions
> >> - 2, export Behavior callback functions (a separate export line for
> >> each behavior)
> >> - 3, export internal functions. The functions that you _don't want
> >> to export_, but Erlang makes you to do so in order to use them in
> >> spawns, applys, etc.
> >>
> >
> > Could I make a plea for
> > - a SINGLE export list for all "API" (horrible term) functions
> > - in alphabetic order
>
> Sorry. Borrowed the term from the Erlang/OTP source code Smile
>
> >
> >> Something like:
> >>
> >> %% API
> >> -export([start_link/0, update/0, get/1, put/2, ...]).
> >
> > Something like
> >
> > -export([
> > get/1,
> > put/2,
> > start_link/0,
> > update/0
> > ]).
> >
> > It's just that much easier to see what the module is all about.
> > Someone using emacs can easily keep such a list in order using
> > sort-lines.
>
> I prefer to group the "API" functions based on their functionality and
> order them by the order they will most probably be used.
> In my config server example start_link / update will be used by the
> supervisor/management hierarchy, while get and put will be used by whoever
> needs something.
>
> >
> >>
> >>
> >> %% Behavior callbacks
> >> -behaviour(gen_server).
> >> -export([init/1, handle_call/3, handle_cast/2, ...]).
> >
> > Years ago I recommended that the syntax should be extended
> > to
> > -behaviour(Behaviour, [Callback...]).
> > so that a cross-checking tool could tell that these functions
> > were *intended* to be used as callbacks by that behaviour and
> > weren't just accidentally adjacent.
>
> A simple -behavior(Behavior). could be interpreted by the compiler as
> exporting all of the behavior's callback functions. That would trigger a
> compiler error if you forgot to implement one.
>
> >
> >>
> >>
> >> %% Internal functions
> >> -export([spawnee/0, applyee/2, ...]).
> >
> > Now that we have spawn(fun () -> ... end) and F(...),
> > we shouldn't need this group at all.
> >
>
> In general you can argue that all of these internal functions can be
> handled as callbacks, and thus put into behaviors, and exported as such.
> Nevertheless grep for "internal exports" in the Erlang/OTP source. There
> is quite a lot of them.
>
> Regards,
> Zoltan.
>
>
> ________________________________________________________________
> erlang-questions mailing list. See http://www.erlang.org/faq.html
> erlang-questions (at) erlang.org
>


________________________________________________________________
erlang-questions mailing list. See http://www.erlang.org/faq.html
erlang-questions (at) erlang.org

Post received from mailinglist
View user's profile Send private message
Guest
Posted: Thu Dec 03, 2009 11:50 pm Reply with quote
Guest
On Dec 3, 2009, at 10:55 PM, Zoltan Lajos Kis wrote:
> I prefer to group the "API" functions based on their functionality

If their functionality isn't too close to make this easy,
why are they in the same module?

OK, let's take Smalltalk as a model, and consider a Set data type

-export([
% @category Instance creation
empty/0, % empty() is empty
from_list/1, % from_list([X1,...,Xn]) has the listed members
singleton/1, % singleton(X) has X as only member
% @category Size
is_empty/1, % is_empty(S) iff S is empty()
not_empty/1, % not_empty(S) iff not is_empty(S)
size/1, % size(S) is number of elements
% @category Single element operations
arb/1, % arb(S) when not_empty(S) is some element
excludes/2, % excludes(S, X) iff X is not in S
includes/2, % includes(S, X) iff X is in S
sans/2, % sans(S, X) is S \ {X}
with/2, % with(S, X) is S U {X}
% @category Whole container comparisons
are_equal/2, % are_equal(S1, S2) iff S1\S2 and S2\S1 empty
not_equal/2, % not_equal(S1, S2) iff S1 S2 different as sets
excludes_all/2, % excludes_all(S1, S2) iff no overlap
excludes_any/2, % excludes_any(S1, S2) iff not_empty(S2\S1)
includes_all/2, % includes_all(S1, S2) iff is_empty(S2\S1)
includes_any/2, % includes_any(S1, S2) iff some overlap
% @category Whole container operations
difference/2, % difference(S1, S2) = S1 \ S2
intersection/2, % intersection(S1, S2)
union/2, % union(S1, S2) = S1 U S2
% @category Iteration
all_satisfy/2, % all_satisfy(S, P) when P(X) for all X in S
any_satisfy/2, % any_satisfy(S, P) when P(X) for some X in S
fold/3, % fold(F, A, S)
map/2, % map(F, S) = {F(X) | X <- S}
none_satisfy/2, % non_satisfy(S, P) = not any_satisfy(S, P)
% @category Conversion
to_list/1 % to_list(S) lists elements in unspecified order
]).

Is this _really_ more useful than a single alphabetic list?
(It helps when there is a consistently applied vocabulary of
categories.)

Take a look at
http://hackage.haskell.org/packages/archive/logfloat/0.12.0.1/doc/html/Data-Number-LogFloat.html
for functions in groups.

It can be a useful indexing tool WHEN YOU ARE SEARCHING THE
DOCUMENTATION.
But the order in which something is documented and the order in which it
is presented in the code need not be the same.

At least let the functions in each group be presented alphabetically.

> and
> order them by the order they will most probably be used.

Why do you think that is a good order?

If someone is reading for the first time, the order they need is
some sort of logical dependency order, and your "my guess about
your frequency of use" order gets in the way.

If someone is re-reading, chances are they're looking for a
particular topic, in which case the frequency-guess order at
best doesn't help. (The thing you most need to read about
is probably the thing you use least often, because it's the
thing you reinforce your memory of least.)
>>
>> Years ago I recommended that the syntax should be extended
>> to
>> -behaviour(Behaviour, [Callback...]).
>> so that a cross-checking tool could tell that these functions
>> were *intended* to be used as callbacks by that behaviour and
>> weren't just accidentally adjacent.
>
> A simple -behavior(Behavior). could be interpreted by the compiler as
> exporting all of the behavior's callback functions. That would
> trigger a
> compiler error if you forgot to implement one.

Yes, but it wouldn't be as helpful for the human reader.
>>>
>>> %% Internal functions
>>> -export([spawnee/0, applyee/2, ...]).
>>
>> Now that we have spawn(fun () -> ... end) and F(...),
>> we shouldn't need this group at all.
>>
>
> In general you can argue that all of these internal functions can be
> handled as callbacks, and thus put into behaviors, and exported as
> such.

Possibly true, but NOT the point I was making here.
>
> Nevertheless grep for "internal exports" in the Erlang/OTP source.
> There
> is quite a lot of them.

Let's take pool.erl as an example.
-export([statistic_collector/0,
do_spawn/4,
init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
terminate/2]).

Let's take the first function in that list. It is exported
because of these two calls:

spawn_link(pool, statistic_collector, []),
spawn_link(Node, pool, statistic_collector, []),

This is the old way of doing things. These days, those calls
can be written as

spawn_link(fun () -> pool:statistic_collector() end),
spawn_link(Node, fun () -> pool:statistic_collector() end),

with no need for an export.

Now let's look at do_spawn/4. This time there's one call.

Pid = spawn(N, pool, do_spawn, [Gl, M, F, A]),

which could now be

Pid = spawn(N, fun () -> pool:do_spawn(Gl, M, F, A) end),

and then we could eliminate do_spawn/4,

Pid = spawn(N, fun () ->
group_leader(Gl, self()),
apply(M, F, A)
end),

The remaining "Internal exports", init/1, handle_call/3, handle_cast/2,
handle_info/2, and terminate/2 are precisely callbacks for gen_server,
so they fall into the class of "behaviour callbacks" for which we
agreed that a second export list was appropriate. As behaviour
call-backs, they should not be described as "Internal exports".

Let's try another file with "Internal exports".
proc_lib.erl has one, wake_up/3. That's used here:

hibernate(M, F,A) when is_atom(M), is_atom(F), is_list(A) ->
erlang:hibernate(proc_lib, wake_up, [M,F,A]).

This one currently has to survive because there is no
erlang:hibernate/1, though it's not clear why. If there were,
it could be

hibernate(Fun) ->
erlang:hibernate(fun () -> wake_up(Fun) end).


Just because there _are_ lots of "Internal exports" doesn't
mean that there NOW _should be_.

I've written up an EEP for this, but on reflection, I believe that
library changes are supposed to be posted to this list, so my next
message will be exactly that.


________________________________________________________________
erlang-questions mailing list. See http://www.erlang.org/faq.html
erlang-questions (at) erlang.org

Post received from mailinglist
wuji
Posted: Wed Sep 12, 2012 6:35 am Reply with quote
User Joined: 10 Aug 2012 Posts: 654
affiliate KABC reported.Thomas, 26, and Young, 29, likely will be charged with with [h2]replica designer *beep*[/h2] with murder on Friday, Villanueva said.Their arrests at 9 p.m. PT Wednesday
related to the arrest at 8 p.m. Wednesday of Richard Anderson, 33, 33, [h4]cheap replica *beep*[/h4] 33, in connection with a string of shotgun robberies, Villanueva added, though
would not reveal the nature of the relationship between the two cases.Ben-Meir's cases.Ben-Meir's jordan 11 cases.Ben-Meir's wallet was missing, raising the possibility he was killed during a
KABC reported. Police would not confirm the missing wallet to ABCNews.com.Ben-Meir, who who jordan concord who coordinated music for MTV shows including Ashton Kutcher's "Punk'd," was found
down, shot at least once in the back of the head, on on cheap jordan shoes on the sidewalk outside his home early Sunday morning by a neighbor.He
View user's profile Send private message

Display posts from previous:  

All times are GMT
Page 1 of 1
This forum is locked: you cannot post, reply to, or edit topics.

Jump to:  

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum