Extending Functionality: gen_server_ext
martin j logan
martin@REDACTED
Thu Mar 20 17:55:37 CET 2003
Hello,
I have been following this thread since it started with some
interest. I fear that I am not quite smart enough for all of this. This
whole notion feels distinctly un-erlang. Erlang is simple, straight
forward and fairly consistent, that is what makes it great. Processes
are painfully easy to conceptualize, and I can make them talk, its all
so easy. I don't think about mutex. My logic variables once assigned are
not going to change value unexpectedly. Code is mostly referentially
transparent except when it is "simpler" to cheat and have a global,
again, real easy. Erlang is simple and expressive. It allows for rapid
development and ease of refactoring. While the ideas that are expressed
in this thread are quite interesting and have much merit I think that
they would serve to undermine erlangs greatest strength - simplicity.
Cheers,
Martin
On Thu, 2003-03-20 at 08:05, Jay Nelson wrote:
> Chris and Vlad discussed:
>
> > Extensions to gen_server to support "behavers" and pseudo
> > inheritance call chains ...
>
> This seems an interesting approach to reusability or extension
> of functionality. I haven't thought about a specific problem that
> it would apply to but I have some general thoughts about a
> structural architecture. I guess these features could be useful
> in a situation where you have two machines, one having more
> functionality than another (but the lesser functionality reused)
> or when users can login with differing levels of privileged access.
> I'm sure there are many other applications, the main issue being
> whether you want dynamic modification of behaviour or a static
> application structure.
>
> Chained processes - deep inheritance
>
> This seems to be the thrust of the initial thinking. It mirrors the
> deeper inheritance structures used in OO. The bottom of a
> chain is the base behaviour in a gen_server, and refinements
> are placed in front of the base like popcorn strung on a thread.
>
> Issues:
>
> 1) Explicit interface vs. implicit interface: use explicit delegation
> and fail if message unhandled, or pass unhandled requests down
> the chain until they are handled and then back up the chain
>
> 2) Allow installation of handlers the way gen_event does to get
> situationally adaptive behaviour?
>
> 3) Multiple inheritance: what if two base chains are joined by
> a single gen_server? Not allowed or deterministic searching for
> unhandled messages to be passed to base chain.
>
> 4) If the chain is deep, there could be a lot of wasted message
> passing searching for the right handler. You may want to use
> memoization to cache the found handler in an ets table the first
> time it is used. Even in a dynamic scenario, you could de-momoize
> if a new handler is installed.
>
> 5) Death of a single process can interrupt much computation.
>
> 6) Single process can only participate in one chain. A separate
> instance is needed to participate in a different chain.
>
>
> Interface amalgam - shallow inheritance
>
> Create a single Amalgam process (similar to supervisor) that combines
> the desired interfaces from several gen_servers. gen_servers
> are all on equal footing, supervisor created using an ordering
> of the gen_servers which may or may not be modified after
> creation (Amalgam interface specification).
>
> 1) Explicit interface vs. implicit interface: Explicit works the same
> way as before -- unhandled messages fail. Implicit relies on the
> ordering Amalgam interface specification when searching
> for message handler.
>
> 2) Installation of handlers should not occur on gen_servers, but by
> modification of Amalgam interface specification.
>
> 3) Inheritance is explicitly defined -- no ambiguity or restrictions.
>
> 4) Message passing only one level deep: Amalgam <--> gen_server
>
> 5) Death of a single process only eliminates some features; it may
> be anticipated and a less capable process answers, dynamic relaunching
> (ala supervisor behaviour) reinstalls.
>
> 6) A single process can participate in any number of Amalgams.
>
>
> The first approach cannot model arbitrary computations as easily.
> The second affords more control over inheritance, and allows
> simultaneous reuse. Here is an example of an Amalgam:
>
> amalgam:start_link( Server, Workers )
>
> Server -> name, pid
> Workers -> Ordered list of tuples
>
> amalgam:start_link( Window,
> [ gen_window, {File_menu, Gen_menu}, {Edit_menu, Gen_menu},
> {My_address_form, Gen_address_form, Gen_form},
> {Ok_cancel_buttons}]
>
> The amalgam:init() function would start all the processes and then build
> a call table using left to right ordering of list elements. If a process in a
> tuple goes down, the others in that tuple may be used as backup handlers.
> If all processes representing one element of the list go down, that bundle
> of functions is not available until at least one process is restarted.
>
> You may still want an explicit chain, or may be forced to use an explicit
> chain if the network topology does not allow the Amalgam to directly access
> a process. A generalized approach would combine the two techniques,
> but my programming style would favor single level Amalgams because it
> is a clearer expression of the computation desired. The same processes
> could participate in two Amalgams, but with a different ordering to get a
> different behaviour. A person logging in could be handled by collecting
> a set of privileges from the database, then dynamically constructing an
> Amalgam that presents only the interfaces that they are allowed to access.
> Refusing to propagate a missing handler can be a feature.
>
> The Amalgam could be combined with a gen_fsm to dynamically add or
> subtract processes from the call table based on the current state of the
> FSM. This is a reasonably easy model to understand that gives rise to
> a complex network of process behaviour that is manageable and fault-
> tolerant.
>
> jay
>
>
>
More information about the erlang-questions
mailing list