[erlang-questions] Package Support/Use

Mats Cronqvist mats.cronqvist@REDACTED
Tue Nov 7 12:58:20 CET 2006


   in this thread i've argued that returning tagged tuples is inferior
to always returning a value or throwing. i tried to illustrate my point
by writing snippets of meta-code; but (stupidly) choose an example
involving a file descriptor (i did point out that it's meta-code and
that i'm not properly handling the file descriptor). i compared C
style, traditional erlang style (TradErl) and throwing style
(BettErl).

   richard o'keefee (rok) feel that returning tagged tuples is better.
he points out that my example is not proper, working code.  this is
indeed true but (i feel) irrelevant.

   he introduces a third erlang style (RokErl);

"just define
	ok({ok,X}) -> X;
	ok(Error) -> signal some kind of error."

   he then goes on to argue that RokErl is just as good as
BettErl. that's not actually true (since you only get the term that
didn't match, and no info where it came from), and in any case
irrelevant to my point; that TradErl (i.e. the bulk of existing code) is 
needlessly verbose and gives poor error info.

   since my (poorly chosen, i know) example didn't attempt to close the
file, rok swiftly concludes that file-closing is difficult in the
BettErl style, and asks; "A style that encourages leaks can hardly be
called a good style, now can it?". shame-facedly, i have to answer
"no".

   OTOH, that's a bit like asking "hey richard, have you given up smoking
crack yet?", isn't it? please answer yes or no.

   rok says; "The real issue is how exceptional the exceptional
condition is and whether it is likely that the caller can do anything
in an error case other than pass it on."

   i think the real issue is if one regards "exceptions" as truly
exceptional things, or if they are just exceptions to a rule. e.g. if
i read from a file, the rule is that i get data, and an exception is
that i reach eof.

   rok goes on by creating an example of his own in which RokErl and
BettErl look similar, and triumphantly exclaims;
"Funny how the difference becomes less clear-cut when you make
the example more realistic, isn't it?"

   hilarious. of course, the difference is the introduction of the ok()
wrapper. which, IMO, is a lame kludge.

   The score sheet now looks like this:

                         TradErl        BettErl   RokErl
More verbose		yes            no        a little
Worse error reporting	yes            no        a little
Encourages leaks	no             no        no
Lame Kludge Factor      0              0         1

   whatever. seems to me rok has shown that the proper way to use the
tagged tuple idiom is to write wrappers that removes the tags. and
even then it is still worse than the exception throwing style.

   but admittedly, my original example was lame. here's a better one. i
do realize that the TradErl implementetion can be shortened (by using
e.g. macros, wrappers, parse transforms, whatnot). but the point is that
this is the way most existing (good) code looks.

   fold/3 calls Fun/2 with the contents of FileName, broken up in 1000
   char blocks.

%% BettErl style. fold/3 returns the final Acc or throws.
%% open/2 and read/2 returns an FD/Data or throws
fold(FileName,Fun,Acc) ->
     FD = open(FileName,[read]),
     try fld(FD,Fun,Acc)
     after close(FD)
     end.
fld(FD,Fun,Acc) ->
     try fld(FD,Fun,Fun(read(FD,1000),Acc))
     catch eof -> Acc
     end.

%% TradErl style
%% tfold/3 returns {ok,Acc} or {error,R}
tfold(FileName,Fun,Acc) ->
     case file:open(FileName,[read]) of
         {ok,FD} ->
             case catch tfld(FD,Fun,Acc) of
                 {'EXIT',R} ->
                     %% we need this is Fun crashes
                     file:close(FD),
                     {error,R};
                 {error,R} ->
                     file:close(FD),
                     {error,R};
                 {ok,Val} ->
                     file:close(FD),
                     {ok,Val}
             end;
         {error,R} ->
             {file_open_error,FileName,R}
     end.
tfld(FD,Fun,Acc) ->
     case file:read(FD,1000) of
         {ok, Data} -> tfld(FD,Fun,Fun(Data,Acc));
         eof -> {ok,Acc};
         {error, Reason} -> {error,Reason}
     end.



More information about the erlang-questions mailing list