Shame on everybody standing by who knew it all along and chuckled with glee:
Index /= null orelse throw(index_null).
*love it* *beautiful* *ouch* *ey! stop that!*
I am still trying hard to avoid the need for a one armed if as per the
reasons brought up in this thread.
Many times I succeed and the extra effort pays off in a yet better
understanding of the FP ways.
However, whenever the desire is for more informative error messages ---
over 'just let it crash' --- anything else clutters the code and
one-armed ifs *are* the right thing to use there because I don't care
for all the other cases. In such cases I am not interested in what value
may be returned because I will break away anyway.
And better error messages are a legitimate constraint sometimes. I
understand it's not in Erlang's heritage in some way.
Message passing and IO are other areas where side effects are the focus,
not return values. And where therefore one-armed ifs could be a honest
thing.
From all the help, which I want to say *thank you* for, the following
had been the strongest advice that stuck with me in its simplicity and
fair abstraction:
Robert Virding wrote:
> ... however you choose to use 'if', or any other
> construction for that matter, Erlang is a functional language and
> everything returns, and must return, a value.
Thanks, Robert, this reminder helped to get into the right thinking
often times!
> So even if 'if' didn't
> need to have an explicit default or else case then it would still have
> to return a value. We would never be able agree on a default value
> anyway. :-) 'nil' is not a good value here as it has no inherent
> meaning in Erlang as it does in Lisp.
>
It probably held true 80% of the times when I ran into a subjective (<-
qualifier inserted for Rich!) need of a one-armed-if.
But whenever exceptions come into play, the return value argument can
become mute I found, in FP. As suggested by the fact that the result of
the after-body of try-catch-after constructs are discarded as well.
Currently I'd argue that in an analogous way the second arm of 'case' or
'if' is not necessarily-necessary when the only arm that matters is
ending on throw/erlang:error/exit. If I wisen up, I promise I'll retract.
I did find very many occasions where instead of a 'case', the correct
pattern matching in the function head made all the difference, or a
'case' structure could with some deliberation be rewritten to have a
sensical second arm.
But especially when I need to throw an error /from/ a place 'higher up'
in the call stack to put more information with it, I couldn't always
find a sensible way to use the second arm of and 'if' or 'case'. (Re
throwing from higher up: e.g. a list may have been consumed in its
entirety 'lower down' when I realize a dead end is hit. And so I can't
show it in the error message if it's thrown from there. Unless I add a
parameter.)
Thank you again for all your thoughts, they are very much appreciated.
Henning
> I think I found my one-armed-if at long last!
>
> Shame on everybody standing by who knew it all along and chuckled
> with glee:
>
> Index /= null orelse throw(index_null).
Sounds like you've rediscovered Perl's
<condition> || die <message>;
idiom. It's generally recommended in Erlang to use 'error'
for errors, not 'throw'.
It's not really clear to me how much of an improvement this
is over
if <guard> -> ok end
>
> But whenever exceptions come into play, the return value argument
> can become mute I found, in FP.
I think you mean "moot" (mOOt, subject to debate)
not "mute" (mEWt, silent).
> As suggested by the fact that the result of the after-body of try-
> catch-after constructs are discarded as well. Currently I'd argue
> that in an analogous way the second arm of 'case' or 'if' is not
> necessarily-necessary when the only arm that matters is ending on
> throw/erlang:error/exit. If I wisen up, I promise I'll retract.
I don't think anybody was arguing against
if <all is well> -> <good result> end
when the *intention* is that the process should crash/raise an exception
on failure. Indeed, no second arm is required in this case. But then,
the programmer's intentions are much more clearly stated if you write
?define(ASSERT(Guard), if Guard -> ok end).
...
?ASSERT(<all is well>),
<good result>
> But especially when I need to throw an error /from/ a place 'higher
> up' in the call stack to put more information with it, I couldn't
> always find a sensible way to use the second arm of and 'if' or
> 'case'.
Give an example.
With exception handling there are at least two separate issues:
- unwind-protect; ensuring that actions are properly undone when
an exception occurs
- recovery and resumption.
The big issue about exception handling is that the exception has
to be *recognised*, *understood*, and *recovered from*.
One would have to see the context, but things like 'index_null' have
a nasty habit of referring to data other than stuff the original
caller passed in, and might not even be able to name.
It really is important to see a real example here.
asso
[io:format("Values: ~p\n",[Vs]) || Vs/=[]]
Looks funny at first but you soon get used to it.
John
Sent from my iPhone
________________________________________________________________