[erlang-questions] feedback on my solutions to programming erlang second edition

Joe Armstrong erlang@REDACTED
Sat Aug 15 16:59:12 CEST 2015


On Fri, Aug 14, 2015 at 1:17 PM, Garrett Smith <g@REDACTED> wrote:
> This function does two things that are unrelated, it returns a file
> and it prints a message to stdout.
>
> https://github.com/rwobben/programming_erlang_exercises/blob/master/chapter_6/my_file.erl#L8
>
> Erlang uses two different patterns for surfacing errors from functions...
>
> Tagged tuples:
>
> do() -> {ok, Value} | {error, Error} | error
>
> and exceptions:
>
> do() -> Value
>
> In the first form, the caller must handle the value accordingly.
> dict:find/2 is an example of this:
>
> http://erlang.org/doc/man/dict.html#find-2
>
> It's important in this case to use patterns that can differentiate
> between a good value and an error. We use {ok, Value} and {error,
> Error} respectively. If the error doesn't have or need any detail, use
> the atom error by itself. Don't do this though:
>
> do() -> Value | {error, Error} | error
>
> as it forces an order of pattern matching (and precludes error
> tuples/atom as valid results), which is easily avoided by tagging the
> good value as {ok, Value}.
>
> In the second form, the caller can safely assume that the value is
> correct, otherwise an exception would be raised (which doesn't have to
> be handled, though can be). dict:fetch/2 is an example of this:
>
> http://erlang.org/doc/man/dict.html#fetch-2
>
> There's never a case IMO where a function should handle an error
> internally by printing a message somewhere and returning the atom ok,
> which is what your function does. Imagine the chagrin of a caller
> assuming everything is fine, then discovering that ok is not a binary,
> failing. Then what, a human has to screen scrape stdout somewhere?
> This reminds me of a common Java pattern:
>
> try {
>     return do();
> catch (Exception e) {
>     e.printStackTrace();
>     return null;
> }
>
> As horrifying as this code is (truly) I see it *all the time*.
>
> People often ask which form of error surfacing is correct here -
> tagged tuples or exception. Both are correct and should be used - but
> according to the intent of the function. The dict module I think is a
> great example (find vs fetch).
>
> In my own practice, I tend to follow this order of progression:
>
> - Functions return good values, not tagged tuples
>
> - Avoid any non "happy path" code and let Erlang deal with the
> unhandled cases - i.e. your code only reflects what you care about
> handling, nothing else
>
> - In cases where a function itself (internally) has to deal with a
> tagged error, raise an error with appropriate context
>
> - If the function is low enough level that *it's job* is to surface
> *either* success or failure, then IMO it must use tagged tuples -
> that's its design and not a matter of aesthetics
>
> So, again, in progression of thinking, I'd start your function off like this:
>
> read(File) ->
>     {ok, Bin} = file:read_file(File),
>     Bin.
>
> The caller doesn't have to worry about getting some weird value and
> Erlang will stop dead in its tracks if there's a problem reading that
> file. Perfect!
>
> Except that in this case, you'll get a 'bad match' error that will
> complain about an error result, but it won't tell you about the file
> involved. So being slightly speculative about needing that information
> in case of an error, I'd write it this way:
>
> read(File) ->
>     case file:read_file(File) of
>         {ok, Bin}-> Bin ;
>         {error, Err} -> error({read_file, File, Err})
>     end.
>
> But I concede that this is speculative - it's just in this case I have
> enough experience with this type of function to know that I'll
> certainly be interested in the file if something's wrong (this is
> obvious). But by default, I'd avoid that speculation and get some
> experience running the code to tell me if I need to take the next step
> of handling error cases explicitly and generating fuller-context
> exceptions. My motive there is to avoid typing *any* error handling
> code at all. That's IMO the right starting point. Then, let yourself
> be dragged reluctantly into error handling code by experience.

I was going to reply on-line here but broke this into a separate mailing.
It touches what I call the must/may convention - if you read my latest
posting you'll see what I mean

/Joe

>
> In any case, stick to the two conventions here of surfacing errors.
>
> Otherwise from what I saw things look great!
>
> Now find *something to build* :)
>
> On Fri, Aug 14, 2015 at 3:29 AM, Roelof Wobben <r.wobben@REDACTED> wrote:
>> Hello,
>>
>> I did the first 6 chapters of the Erlang programming book second editon.
>>
>> Now I wonder if I did things the righr way and if there are any
>> improvements.
>>
>> My code can be found here:
>> https://github.com/rwobben/programming_erlang_exercises
>>
>> I did not do the chapter 5 exercises because then you need to use map and
>> that one is in R17 where I work on R16.
>>
>> Roelof
>>
>>
>> ---
>> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware.
>> https://www.avast.com/antivirus
>>
>> _______________________________________________
>> erlang-questions mailing list
>> erlang-questions@REDACTED
>> http://erlang.org/mailman/listinfo/erlang-questions
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions



More information about the erlang-questions mailing list