Ayende @ Rahien

Hi!
My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:

ayende@ayende.com

+972 52-548-6969

, @ Q c

Posts: 5,972 | Comments: 44,523

filter by tags archive

Sometimes imperative is so much easier


Take a look at the following Erlang function:

count_promises(Id, N, {_, PromisesQueue}) ->
    rec_count_promises(0, Id, N, PromisesQueue).

rec_count_promises(Count, _, _, []) ->
    Count;
rec_count_promises(Count, Id, N, [{Id, N, _, _} | RestQueue]) ->
    rec_count_promises((Count + 1), Id, N, RestQueue);
rec_count_promises(Count, Id, N, [_ | RestQueue]) ->
    rec_count_promises(Count, Id, N, RestQueue).

I am reading a codebase full of this sort of things, and it is really painful. I keep thinking back to how I would do it in C#:

public int CountPromises(int id, int n, Tuple<List<Record>, List<Record>> phase1)
{
     int count=0;
     foreach(var record in phase1.Item2)
       {
            if(record.Id == id && record.N == n)
                   count ++;
     }
     return count ;
}

Yet that is imperative, and involve mutating state. I agree, it is a huge improvement, but it can be made both functionally safe and easier to read:

phase1.Items2.Count(record => record.Id == id && record.N == n);

As I said, I am currently going through a codebase full of these sort of functions, and it is painful, annoying and irritating. I am not experienced enough with Erlang to be able to tell conclusively if this is idiomatic Erlang code, but I think so.


Comments

Paul Cowan

Did the Erlang code come from couchdb?

If so, I would be curious to know what benefit there is in rewriting couchdb on another platform?

Andrew Davey

Writing out the recursion and pattern matching for this function sure feels like a waste of time.

It seems to me that the Erlang code should be re-factored to make use of higher level functions, like "filter".

Demis Bellot

Yeah it's hard to see how this can can be more readable in anyone's mind. I'm aware the mathematical mind works differently and prefers the purity of functional programming without side-effects but does it work this different?

IMHO readability of code is just as important as succinctness, i.e. there's no point having really tight code with low signal/noise ratio if it takes others longer to scan and understand a page of code.

Max
Max

This is horrible functional programming style. I'm not a Erlang wizard, so this is how I would write the function in Haskell:

countPromises id n = length . filter ((id', n') -> id' == id && n' == n) . snd

Much better! If you want it to look like C# you can also define:

count p = length . filter p

countPromises id n = count ((id', n') -> id' == id && n' == n) . snd

If you use GHC, all the intermediate lists wil be fused away, so this will actually compile into the tight imperative loop you wrote above.

tobi

This cannot be idiomatic erlang code because it would mean that most erlang programmers are not very smart. That is hard to believe.

configurator

Oh. I thought you said "idiotic" Erlang code.

I think yes, it is.

Bobo

countpromises(Id, N, {, PromisesQueue}) ->

lists:foldr(fun(X,ACC) -> {I,NN,,} = X, if I==Id , NN==N -> ACC+1; true -> ACC end end , 0, PromisesQueue).

NoComments

Probably no comments in the mess either.

Igor K.

countpromises(Id, N, {, PromisesQueue}) ->

length(lists:filter(fun(X, Y, _, _}) -> X =:= Id andalso Y =:= N end, PromisesQueue)).

Apalmer

Doesnt look idiomatic functional programming at all, it looks like a mechanical conversion of an imperative loop with mutating state to a recursive function call with accumulators. Which is basic functional programming 101, but in general once the user learns that they can do this relieably, they then move on to composing simple functions over lists to accomplish the same goal. Not sure its possible that maybe there is some performance gain in the erlang implementation if you feel this was programmed by advanced functional programmers. A lot of times when performance is taken into account, an advanced programmer has to strip out all the nice functional patterns and put in some worst of both worlds imperative/functional chimera

Comment preview

Comments have been closed on this topic.

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. Production postmortem (5):
    29 Jul 2015 - The evil licensing code
  2. Career planning (6):
    24 Jul 2015 - The immortal choices aren't
  3. API Design (7):
    20 Jul 2015 - We’ll let the users sort it out
  4. What is new in RavenDB 3.5 (3):
    15 Jul 2015 - Exploring data in the dark
  5. The RavenDB Comic Strip (3):
    28 May 2015 - Part III – High availability & sleeping soundly
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats