[erlang-questions] If Condition vs. Multiple Function Clauses

Jachym Holecek freza@REDACTED
Fri Jun 14 16:04:23 CEST 2013


# Lars Herbach 2013-06-14:
> I'm currently working myself through the "?tudes for Erlang" book [1] and in
> exercise it wks's to write a recursive function, calculating the greatest
> common divisor for two numbers N and M. The suggested solution is a single
> gcd/2 function with an If condition and recursion:
> 
> gcd(M, N) ->
>     if M == N -> M;
>        M > N -> gcd(M - N, N;
>        true -> gcd(M, N - M)
>     end.

Not entirely correct: what happens if you invoke 'gcd(-3, 9)' for example?
Same applies to the version below.

> I by myself took another way, working with multiple function clauses (did I
> name it right?):

Yes, that's correct naming. Note that multiple clauses are just a convenient
way to write things, 'gcd/2' is still just one function. It's instructive to
have a look at the result of 'erlc +to_core xxx.erl', that gives you Core
Erlang translation of your source -- a slightly more lowlevel representation
with less sugar on top and more uniformity.

> gcd(M, N) when M == N ->
>     M;
> gcd(M, N) when M > N ->
>     gcd(M - N, N);
> gcd(M, N) ->
>     gcd(M,  N - M).

I'd prefer this style myself as well, and from history of this list I think
many people would agree.

'If' expressions are quite useful, but in different use cases -- some number of
simple checks on a few unrelated values, when you feel splitting the checks to
another mini-function doesn't improve clarity (and/or you can't be bothered to
invent yet another function name ;-).

> Now I've got two questions about that:
> 1) Is my solution still recursive, since I practically call different
> functions?

Certainly recursive, tail-recursive even (doesn't matter in this case though,
you have as much stack space as you like -- only relevant consideration is
'bounded' vs. 'unbounded'). You're not calling different function, there's
only one 'gcd/2' in your code with a case analysis in it -- just like in
the first case.

At this level ("what does my code compile down to") the result of running
'erlc +to_asm xxx.erl' is useful -- that gives you BEAM assembly dump, quite
readable even if you don't exactly know what some/most instructions mean.

> 2) Are there any benefits in regards of efficiancy for the first solution?

No, at least in this simple case they compile down to almost the same ASM,
I'd expect that to be true pretty much all the time.

Recommended to optimize for clarity and simplicity. In the systems Erlang
is typically used for efficiency comes from entirely different places than
messing about with individual lines, expressions or functions. Unless you
have a loadtest proving the contrary for your particular project ;-), and
even then optimization wouldn't probably take more than an afternoon, so
no reason to worry. Focusing on more global dataflows, load distribution,
points of contention, safety of various internal protocols, load mitigation,
fault isolation + propagation etc. is better use of your time, but also a
bit of an advanced topic -- not sure existing literature covers it much?

(Recent discussion between Max Lapshin and Tim Watson illustrates the
really important considerations very well, for instance. There were
many excellent posts by others as well over time -- sorry, couldn't
possibly excavate all the links. :-/)

But for completeness -- Here's Erlang efficiency guide:

  http://www.erlang.org/doc/efficiency_guide/introduction.html

HTH,
	-- Jachym



More information about the erlang-questions mailing list