Question about fun's

Shawn Pearce pearcs@REDACTED
Wed Jan 27 21:42:43 CET 1999


Ulf Wiger <ulf.wiger@REDACTED> wrote:
> Personally, I'd go with 'print' and 'empty' instead of tuples with only
> one element. You don't have a type checker that's gonna complain -
> Erlang really couldn't care less, but your match operation speeds up
> somewhat. A matter of preference, I guess.
> 
> > 
> > What are the drawbacks, ie is the fun going to cost me a large amount of
> > RAM, or a large amount of processing overhead on each message?
> 
> Funs don't cost much in terms of memory. You can look at how a fun is
> represented:
> 
> 
> -module(myclass).
> -export([new/0]).
> 
> new() -> 
>     F = save_state([]),
>     tuple_to_list(F).  %% hack to reveal the representation of a fun
> 
> save_state(State) ->
>         fun(Message) ->
>                 myclass:dispatch(State,Message)
>         end.
> 
> If you compile and run:
> 
> 1> myclass:new().   
> ['fun',myclass,0,7662692,{[]}]
> 
> That is, a 5-tuple. The rest is compiled and represented as one
> instance.
> 
> The processing overhead is roughly the same as for apply/3. A few
> microseconds per call.
> 
> On the minus side:
> In the current JAM implementation, error reporting for funs is lousy and
> code change on-the-fly doesn't work well (the fun's internal reference
> changes and the fun instance has to be recreated.)
> 
> Apart from this, I have found that it's most often counter-productive to
> use an object-oriented style of programming in Erlang. Personally, I
> spent my first 6 months with Erlang trying to make it object-oriented.
> After that, I had convinced myself that you get further by using Erlang
> as it was intended (granted, we didn't have funs in those days...)
> 
> You could do a similar thing without funs, to begin with:
> 
> -module(myclass).
> -export([new/0,
>          dispatch/2]).
> 
> new() -> [].
> 
> dispatch(State, print) -> io:format("~p~n", [State]);
> dispatch(State, {append,Item}) -> State ++ Item;
> dispatch(State, get) -> State;
> dispatch(State, empty) -> [].
> 
> then:
> 
> O = myclass:new().
> O1 = myclass:dispatch(O, {append,TheThingy}).
> 
> etc:
> 
> You may argue that the object-oriented aspect got lost:
> 
> -module(myclass).
> -export([new/0,
>          dispatch/2]).
> 
> 
> new() ->
>    {?MODULE, []}.
> 
> dispatch(State, print) -> io:format("~p~n", [State]);
> dispatch(State, {append,Item}) -> State ++ Item;
> dispatch(State, get) -> State;
> dispatch(State, empty) -> [].
> 
> -module(oo).
> -export([msg/2]).
> 
> msg({Class, State}, Msg) ->
>    Class:dispatch(State, Msg).  %% this uses apply/3 instead of funs
> 
> then:
> 
> O = myclass:new().
> O1 = oo:msg(O, {append,TheThingy}).
> O2 = oo:msg(O1, print).
> ...
> 
> 
> Useless exercise?
> 
> Perhaps. What you gain is that you avoid the negative aspects (bugs?) of
> funs, at little syntactical expense. I have written code like that.
> Sometimes, I find it justified (when the OO paradigm really adds
> advantages), but most of the time, it just makes the code harder to
> read, harder to write, and harder to maintain.
> 
> So what do I propose?
> 
> Look at modules like:
> 
> lists (lists:append(L1, L2), lists:reverse(L), ...)
> queue (queue:new(), queue:in(Q, Item), queue:out(Q), ...)
> application (application:start(Name), application:stop(Name), ...)
> 
> and so on. The big advantage of this style of programming is that
> programs become much easier to read, since the semantics are obvious.
> You still get a great deal of reuse, and your productivity will be very
> high.
> 
> I admit I haven't the faintest idea of what kind of program you're
> trying to write. Perhaps your problem domain really calls for
> object-oriented design? 
> 
> If so, forgive me, but it's very common for programmers new to Erlang to
> go overboard trying to make everything object-oriented. 

I'm one of the authors of the Casbah Project, an open source project,
(http://www.ntlug.org/casbah/).  Our entire system is very much object oriented
based, and has its "server" currently written in Java.  We are looking at also
implementing our server in Erlang, for obvious reasons.  The server is a very
"pluggable" architecture, but its all object-oriented based.  A language like
Objective-C would be ideal for building our server, as it is very dynamic in
its object-dispatch mechanism, etc.

Essentially parts of the system will need to invoke code on some plugin module
whose name isn't known until runtime, and even then will change on invoctions. 
I know that pretty much breaks erlang's ideas, but not that much:  because if
we pass in the same arguments, we'll still expect it to always return the same
result, it will just alter its behavior based on that input.  So if we pass in
an item of class NatrounFS, it should do a, if its of class NatrounSQL, it
needs to execute code b.

I didn't realize that the code example you showed above would work, and doh! I
should have thought about using oo:msg() to wrap around apply/3 rather than
using a fun.

We'll implement each class in its own module, but we really sort of need the
ability to have methods dispatched based on the class at runtime, rather than
at the time of the coding.

Thanks for the suggestions!


--
Shawn.

(The above are the rantings of a body without a mind.)




More information about the erlang-questions mailing list