Skip to content

Commit 4abfb96

Browse files
committed
Add guidelines on judicious use of recursion
1 parent ef18f7c commit 4abfb96

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-0
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ Table of Contents:
6565
* [Properly use logging levels](#properly-use-logging-levels)
6666
* [Prefer the https protocol when specifying dependency locations](#prefer-the-https-protocol-over-others-when-specifying-dependency-urls)
6767
* [Suggestions & Great Ideas](#suggestions--great-ideas)
68+
* [Avoid recursion when possible](#avoid-recursion-when-possible)
6869
* [CamelCase over Under_Score](#camelcase-over-under_score)
6970
* [Prefer shorter (but still meaningful) variable names](#prefer-shorter-but-still-meaningful-variable-names)
7071
* [Comment levels](#comment-levels)
@@ -538,6 +539,16 @@ handling.
538539

539540
Things that should be considered when writing code, but do not cause a PR rejection, or are too vague to consistently enforce.
540541

542+
***
543+
##### Avoid recursion when possible
544+
> Occasionally recursion is the best way to implement a function, but often a fold or a list comprehension will yield safer, more comprehensible code.
545+
546+
*Examples*: [alternatives to recursion](src/recursion.erl)
547+
548+
*Reasoning*: Manually writing a recursive function is error-prone, and mistakes can be costly. In the wrong circumstances, a buggy recursive function can miss its base case, spiral out of control, and take down an entire node. This tends to counteract one of the main benefits of Erlang, where an error in a single process does not normally cause the entire node to crash.
549+
550+
Additionally, to an experienced Erlang developer, folds and list comprehensions are much easier to understand than complex recursive functions. Such contstructs behave predictably: they always perform an action for each element in a list. A recursive function may work similarly, but it often requires careful scrutiny to verify what path the control flow will actually take through the code in practice.
551+
541552
***
542553
##### CamelCase over Under_Score
543554
> Symbol naming: Use variables in CamelCase and atoms, function and module names with underscores.

src/recursion.erl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
-module(recursion).
2+
3+
-export([recurse/1, fold/1, comprehension/1]).
4+
5+
%%
6+
%% Example:
7+
%% Different functions to capitalize a string
8+
%%
9+
10+
%% BAD: makes unnecessary use of manual recursion
11+
recurse(S) ->
12+
lists:reverse(recurse(S, [])).
13+
14+
recurse([], Acc) ->
15+
Acc;
16+
recurse([H | T], Acc) ->
17+
NewAcc = [string:to_upper(H) | Acc],
18+
recurse(T, NewAcc).
19+
20+
%% GOOD: uses a fold instead to achieve the same result,
21+
%% but this time more safely, and with fewer lines of code
22+
fold(S) ->
23+
Result = lists:foldl(fun fold_fun/2, [], S),
24+
lists:reverse(Result).
25+
26+
fold_fun(C, Acc) ->
27+
[string:to_upper(C) | Acc].
28+
29+
%% BEST: in this case, a list comprehension yields the
30+
%% simplest implementation (assuming we ignore the fact
31+
%% that string:to_upper can also be used directly on strings)
32+
comprehension(S) ->
33+
[string:to_upper(C) || C <- S].

0 commit comments

Comments
 (0)