Wings 3D Development Forum

Full Version: Tidy recursion
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Which is the best recursion method?
I like the first one, but does it introduce too much overhead?

1)
Code:
get_indices(<<>>) ->
    [];
get_indices(Bin) ->
    {<<I:16/unsigned-little-integer>>,NewBin} = split_binary(Bin, 2),
    [I|get_indices(NewBin)].

2)
Code:
get_indices(<<>>) ->
    [];
get_indices(Bin) ->
    {<<I:16/unsigned-little-integer>>,NewBin} = split_binary(Bin, 2),
    [I] ++ get_indices(NewBin).

3)
Code:
get_indices(Bin) ->
    get_indices(Bin, []).
get_indices(<<>>, Result) ->
    lists:reverse(Result);
get_indices(Bin, Result) ->
    {<<I:16/unsigned-little-integer>>,NewBin} = split_binary(Bin, 2),
    get_indices(NewBin, [I|Result]).
nemyax Wrote:I like the first one, but does it introduce too much overhead?
Considering what we have here I prefer the 2nd one.
In some situations the 1st can result in a list of list that would require to use lists:flatten to make it a plain list - depending on how you will use it.

(05-17-2013, 12:22 PM)nemyax Wrote: [ -> ]Which is the best recursion method?
Always as possible try to use List Comprehensions or - in this case - Bit String Comprehensions - it's faster!

In your case:
Code:
get_indices(Bin) ->
    [ I || <<I:16/little>> <= Bin ].
Simple like that!

p.s.
1) you don't need to write this full declaration: I:16/unsigned-little-integer
writing just I:16/little will produce the same result and would make your code easy to read.
In accord with Bit Syntax Expressions documentation, unsigned and integer are default value for the type specifier list.

2) It's good see someone else coding for Wings3d. Smile
micheus
Thanks for the tips.
My doubts are due to Joe Armstrong saying this in Programming Erlang in a section about tail recursion:
Quote:if you write a function F that never returns (such as loop()), make sure that you never call anything after calling F, and don’t use F in a list or tuple constructor.
In both 1 and 2, the last expression looks like a list constructor, so it might inflate the stack noticeably if the binary is huge (I don't know for sure — no idea how these expressions would be compiled).
I think I picked up the trick with the arity bump and the introduction of an accumulator from the Wings source, so there must be a reason why this is used.
By contrast, the Haskell examples I've seen don't make a fuss about using the x:myFunction xs notation, and it really does look neat.

(05-18-2013, 06:22 AM)micheus Wrote: [ -> ]It's good see someone else coding for Wings3d. Smile
Well, what's the use. No one seems to be using my crap =)
Micheus is right, the binary comprehension is the best for this code.

So example is kind of bad, for the question.
And the answer is that it depends, you will have to measure which one is fastest,
in current release, previously example 3 was always best and will be always be
if you don't need the lists:reverse at the end.
Now (since Björn have made some optimizations in erlang) if you really want
the fastest implementation you will have to measure, but for most of the
cases it doesn't matter if you use 1) or 3)
Number 2 is ugly and creates an unnecessary extra list.

If you want to return more than one thing only 3) is possible.

What I think Joe is saying is to avoid doing something like this.

init() ->
Result = loop(),
{ok, Result}.

loop() ->
receive
quit -> 42;
Msg -> io:format("Msg ~p~n",[Msg]),
loop()
end.

Which must save init function on the stack until loop returns.
See: http://en.wikipedia.org/wiki/Tail_call for a better explanation :-)
(05-20-2013, 01:50 PM)dgud Wrote: [ -> ]Number 2 is ugly and creates an unnecessary extra list.
Good to know, even I prefer it to the 1st. Thanks.