[erlang-questions] Avoiding boilerplate code when using gen_server

Joe Armstrong erlang@REDACTED
Wed Mar 21 20:35:36 CET 2012


My last post got sent before it was ready - (moral don't compose code
in the browser) - I meant to say:


-module(bank).
-behavior(e2_service).

-interface([deposit/1, withdraw/1, ask/0]).

init() -> 0.

deposit(_From, X, N) -> {noreply, X+N}.

withdraw(_From, X, N) ->
    if X < N -> {reply, no, X};
       true  -> {reply, X, N-X}
    end.

ask(_From, N) ->
    {reply, N, N}.

%% The caller will just say

bank:deposit(10)
bank:withdraw(12)

Pretty easy to code up with a few simple code transformations

I had an interesting conversation with a guy who knew Ruby on Rails
he attributed part of the success of RoR to the autogeneration of
large numbers of stub functions from database schemas.

I think there are many users who don't care how things work
provided they *do* work and who are quite happy with
"do this, and this and this and it will work"

(( actually things like eclipse etc. encourage this kind of mind-set
   - first you ask a load of questions that nobody on this planet
understands - then you create a bundle of mysterious files with
undocumented and mysterious contents - then you press the big
"build" button and with a bit of luck it works ))

/Joe

On Wed, Mar 21, 2012 at 8:22 PM, Garrett Smith <g@REDACTED> wrote:
> On Wed, Mar 21, 2012 at 1:28 PM, Tim Watson <watson.timothy@REDACTED> wrote:
>> On 21 Mar 2012, at 15:29, Garrett Smith wrote:
>>>
>>> http://e2project.org/
>>>
>>
>> I've looked at this before and I like the general concept, and I suspect if it gets up to a suitable quality could be a good candidate for moving into OTP proper over time.
>>
>>>> From the API functions you call out to gen_server:call/2 and on top of that
>>>> you need to implement a handle_call/3 function clause that matches whatever
>>>> format you used for wrapping the incoming message.
>>>>
>>>> The question was: why don't you use an IDL (Interface Definition Language)
>>>> approach instead of writing all that code that has to match up in order to
>>>> work?
>>>
>>> Erlang has a "parse transform" feature that would let you embed such
>>> an "IDL" in a single module, and could generate the "boilerplate".
>>>
>>> I initially started down this road with e2, but decided against it for
>>> these reasons:
>>>
>>> - Erlang is already a *very* simple language - let's just use it
>>> - Auto generated functions are hard to document, test, etc.
>>
>> In what way are auto generated functions hard to test? Why can you not generate documentation for them as you would hand coded functions? Good code generation tools will support the latter case and I'm not at all convinced that the charge of being 'hard to test' is at all true, especially for code generated by a parse transform.
>
> This may come down to personal taste. I don't like having to dig
> around in parse transform code to understand what my module looks
> like.
>
> eunit is a great example. If you really love eunit, then I'm not going
> to convince you :)
>
>>> - Hiding the client-server distinction in Erlang is a terrible disservice
>>
>> I agree with this wholeheartedly, but don't see what it has to do with code generation.
>
> If you consolidate both the client and server functions into one
> function, you've obfuscated an important distinction.
>
>>> IMO, e2 solves the problem of "too much boiler plate". It's really
>>> easy and requires zero magic.
>>>
>>> Here's a "gen_server" equivalent in e2:
>>>
>>> https://github.com/gar1t/e2v2/blob/master/examples/ping/src/ping_server.erl
>>>
>>
>> This is pretty cool though. :)
>>
>>> You might object to the separation of "ping" and "handle_msg" -- it
>>> appears to be just one function, so why break it up into two pieces?
>>>
>>> The problem is that it's not one function -- it's definitely *two*
>>> very separate pieces of code.
>>
>> Absolutely and a good point!
>>
>>>
>>> When you write a gen_server style module, you're writing code that
>>> support client-server interactions. You have, in the same module, code
>>> that is called by the "client" and code that is called by the
>>> "server". If you don't grok this, you're missing the entire point of
>>> this type of module.
>>>
>>> Code that hides this difference -- e.g. a parse transform that gloms
>>> the client and server functions into one -- is IMO a Really Bad Idea.
>>>
>>
>> I don't necessarily agree with this, as the parse transform can be applied to a -spec which is potentially as intention revealing as a hand written function. I do take your point about them being two separate functions and perhaps in this particular case (for gen_server) you are actually correct and having two hand coded parts is actually better. I don't buy 'code-gen is bad' as a general argument (which perhaps you weren't going so far as to make anyway), and I do see your point in this instance.
>
> I'm certainly not arguing against code generation. I think Erlang's
> parse transform scheme is *very* good -- flexible enough to enable
> elegant solutions but with enough complexity to scare off casual "meta
> programmers".
>
> But -- I think there should be a very clear payoff for using a parse
> transform. I don't think the discussion here, which is "boilerplate"
> is a good application for that.
>
> A good example of a value-add parse transform IMO is modlib, which
> lets you create mods for inets httpd withou causing your brain to
> explode [1].
>
>>> As an example of how this client/server difference is important,
>>> consider form validation in a web app. There are two places you can
>>> run code to validate form input -- you can validate it in the browser
>>> using JavaScript, or you can send the form data to the server. Web
>>> developers may opt for browser validation to avoid the expense of
>>> sending data to the server -- or they might prefer it on the server.
>>> Either way, it's an important consideration.
>>>
>>> This same dynamic applies to gen_server style modules. If you stick
>>> with it, I think you'll appreciate the separateness of client and
>>> server facing code.
>>>
>>> As for the boilerplate, I couldn't agree with you more!
>>>
>>> Garrett
>>>
>>> P.S. I'm giving a talk on e2 at the SF Factory in a couple weeks,
>>> where I'll get into this in more details. Also, the e2 docs and github
>>> project are in slight disarray at the moment, but will be put in order
>>> this weekend!
>
> [1] https://github.com/gar1t/modlib
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions



More information about the erlang-questions mailing list