[erlang-questions] Any wisdom to offer on "tagged return values"

Joe Armstrong erlang@REDACTED
Wed May 6 17:12:45 CEST 2009

On Wed, May 6, 2009 at 10:41 AM, mats cronqvist <masse@REDACTED> wrote:
> "Richard O'Keefe" <ok@REDACTED> writes:
>> On 6 May 2009, at 4:27 am, Ulf Wiger wrote:
>>> Also, functions that return tagged values don't compose well.
>>> I've found that I don't use composition that much in my code,
>>> and I think it's something that one can certainly go overboard
>>> with. The problem that frequent case matching clutters up the
>>> code is a bigger issue, IMHO.
>> When you are writing code for a specific use,
>> there's a rule of thumb that I use.
>> I think it makes sense for library code too.
>> Basically, it's "let it crash".
>> Spelling it out,
>>   - if the immediate caller of a function will know what to
>>     do with the "exceptional" result, return a tagged value
>>   - if it won't, so that the code would be cluttered up with
>>     stuff that just passes the buck, throw an exception.
>> For library code, you have to make (informed) guesses about
>> whether the caller is _likely_ to have anything useful it
>> can do with the "exceptional" result.
>  Well put.
>  Now, the start of this thread was that Kevin was sceptical re this
>  Programming Rule; "Use tagged return values." I think it's safe to say
>  that he's right. Following this rule will make you write sub-optimal
>  code.

I think the rule should be "Use distinguished return values" -

Look at the design of the dict interface.

We might have said dict:find(Key, Dict) -> Val | '$undefined'.

But someday some code might break because a programmer
wrote dict:store(Key, '$undefined', Dict). So when find is called
there is absolutely no way of knowing if the key was in the dictionary
or not.  The purpose of the {ok, Val} | error return value is to
make the return values "distinguishable".

If you can guarantee that you will never ever insert a '$undefined'
value into the dictionary then you could omit the tag.

dict:fetch(Key, Dict) returns a value or raises an exception if the
Key is not in the dictionary. This is deliberate.

If the logic of the application is such a certain key *must* be in
the dictionary at a certain point in the program then use dict:fetch

if the logic is such that if the key is missing and you cannot recover
from the error use dict:fetch

If the logic is such that you can handle both the missing and present
cases then use dict:find.

It's not really about tagging, its about distinguished values.

You could of course use dict:find for everything and use
(catch dict:find) instead of dict:fetch but this would be ugly.

Correct use of find or fetch depending upon the context makes
the program a lot clearer - since it signal the programmers intention.
if they say dict:fetch(Key, ...) then they are saying "at this point in the
program it is an error if Key has not previously been inserted in the
dictionary, and it it is not there it is an error. find signals that
may or may not be there.

I would always prioritize clarity over efficiency, unless your code
just has to be blindingly fast - so you might break this rule if you
want to write faster but less clear code.



More information about the erlang-questions mailing list