Erlang Mailing Lists

Author Message

<  Erlang questions mailing list  ~  Extending Functionality: gen_server_ext

cpressey at catseye.mb.ca
Posted: Wed Mar 19, 2003 4:15 pm Reply with quote
Guest
On Fri, 14 Mar 2003 10:28:23 +0100
"Vlad Dumitrescu (EAW)" <Vlad.Dumitrescu_at_erv.ericsson.se> wrote:

> Hi guys,
>
> I happen to know this Vlad person Very Happy and he likes to be the fool that
> throws the stone into the lake and let 20 wise people try for a month
> to figure how to pick it back.
> [... gen_server_ext ...]

Hi Vlad,

I think you're really onto something here (for dynamic behaviour at least,
i.e. when you already know for sure you're going to have a process), I
just wanted to clarify how it works.

First, it occurs to me that I don't know any good term for "module which
implements a behaviour", so I'm going to use "behaver" for better or worse
(sounds a lot like "behaviour" when spoken so I'm open to better
suggestions.)

So - my impression is that, when you write a behaver for gen_server_ext,
you typically code it so that when it receives a message it doesn't
understand, it passes it on to the next behaver with
gen_server_ext:next_*()

The other option open seems to be that any unrecognized message would be
passed along to the next behaver in the chain. (a bit like gen_event?)

I can see why you would want to go with the first method - it's more
flexible and more explicit/predictable - but I think there are some minor
oddities with it being explicit, too - could you accidentally call
next_cast within a call handler? (then what happens? Is this "legal"?)

-Chris


Post generated using Mail2Forum (http://m2f.sourceforge.net)
Vlad.Dumitrescu at erv.er
Posted: Wed Mar 19, 2003 5:21 pm Reply with quote
Guest
Hi,

> So - my impression is that, when you write a behaver for
> gen_server_ext,
> you typically code it so that when it receives a message it doesn't
> understand, it passes it on to the next behaver with
> gen_server_ext:next_*()
>
> The other option open seems to be that any unrecognized
> message would be
> passed along to the next behaver in the chain. (a bit like
> gen_event?)

> I can see why you would want to go with the first method - it's more
> flexible and more explicit/predictable - but I think there
> are some minor
> oddities with it being explicit, too - could you accidentally call
> next_cast within a call handler? (then what happens? Is this
> "legal"?)

Yes, it should be legal. I think it's a lot like virtual methods: you can ignore the previous implementation, or you can reuse it and select from it what is relevant.

The second option can only handle messages that "fall through" and are not handled at all in the current handler. This is way too rigid, for example if root handler handles {get, Data, Index} and in the new handler I want to only handle differently {get, Data, 0}, I can't.

One could also use regular gen_server and hardcode the next_call to a specific module. This would work in an inheritance hierarchy, but what I would like to do (inspired by Jay) is free composition of independent behaviours.

I hope that what I wrote makes sense. Test is starting to dance before my eyes, so I'm on my way home now. :-)

Best regards,
Vlad


Post generated using Mail2Forum (http://m2f.sourceforge.net)
cpressey at catseye.mb.ca
Posted: Wed Mar 19, 2003 5:44 pm Reply with quote
Guest
On Wed, 19 Mar 2003 18:18:48 +0100
"Vlad Dumitrescu (EAW)" <Vlad.Dumitrescu_at_erv.ericsson.se> wrote:

> Hi,
>
> > So - my impression is that, when you write a behaver for
> > gen_server_ext,
> > you typically code it so that when it receives a message it doesn't
> > understand, it passes it on to the next behaver with
> > gen_server_ext:next_*()
> >
> > The other option open seems to be that any unrecognized
> > message would be
> > passed along to the next behaver in the chain. (a bit like
> > gen_event?)
>
> > I can see why you would want to go with the first method - it's more
> > flexible and more explicit/predictable - but I think there
> > are some minor
> > oddities with it being explicit, too - could you accidentally call
> > next_cast within a call handler? (then what happens? Is this
> > "legal"?)
>
> Yes, it should be legal. I think it's a lot like virtual methods: you
> can ignore the previous implementation, or you can reuse it and select
> from it what is relevant.

But surely the client isn't expecting the call to be transformed into a
cast... ?? My vague feeling is that ideally there should be one function,
gen_server_ext:next(), that goes to the same type of handler (cast, call,
info etc) in the next behaver.

> The second option can only handle messages that "fall through" and are
> not handled at all in the current handler. This is way too rigid, for
> example if root handler handles {get, Data, Index} and in the new
> handler I want to only handle differently {get, Data, 0}, I can't.

Very true.

> One could also use regular gen_server and hardcode the next_call to a
> specific module. This would work in an inheritance hierarchy, but what I
> would like to do (inspired by Jay) is free composition of independent
> behaviours.

Also agreed.

Another question: what are the pros and cons of having to call next_call()
et al, as opposed to returning a value like {next_call, ...} from the
handler, and having gen_server_ext pay attention to that?

> I hope that what I wrote makes sense. Test is starting to dance before
> my eyes, so I'm on my way home now. Smile
>
> Best regards,
> Vlad

Still before noon here :)

Thanks for the clarification,
-Chris


Post generated using Mail2Forum (http://m2f.sourceforge.net)
vlad_dumitrescu at hotmai
Posted: Wed Mar 19, 2003 7:36 pm Reply with quote
Guest
> But surely the client isn't expecting the call to be transformed into a
> cast... ?? My vague feeling is that ideally there should be one function,
> gen_server_ext:next(), that goes to the same type of handler (cast, call,
> info etc) in the next behaver.

Oh, sorry -- I didn't read your question properly. Long day, lots of work
Smile Of course my answer only applies to calling next_call from a handle
call.

> Another question: what are the pros and cons of having to call next_call()
> et al, as opposed to returning a value like {next_call, ...} from the
> handler, and having gen_server_ext pay attention to that?

If you return with {next_call, ...} then you can't get the answer back and
refine it. It's something in between the two options you mentioned before, I
think.

I have this feeling that there's a lot more to dig out here.

regards,
Vlad


Post generated using Mail2Forum (http://m2f.sourceforge.net)
jay at duomark.com
Posted: Thu Mar 20, 2003 2:15 pm Reply with quote
Guest
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





Post generated using Mail2Forum (http://m2f.sourceforge.net)
martin at vailsys.com
Posted: Thu Mar 20, 2003 4:55 pm Reply with quote
Guest
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
>
>
>




Post generated using Mail2Forum (http://m2f.sourceforge.net)
vances at motivity.ca
Posted: Thu Mar 20, 2003 6:30 pm Reply with quote
Guest
On Thu, Mar 20, 2003 at 10:55:37AM -0600, martin j logan wrote:
}
} Code is mostly referentially transparent except when it is
} "simpler" to cheat and have a global,


I was thinking recently about how I struggled with how to write
code without global variables when learning Erlang. "How the hell
can you live without globals?" I asked. It reminded me of learning
the C language. "How the hell can you live without GOTOs?"(*) I
asked having only ever programmed in BASIC. I've never used either
and no longer see any reason to do so.

-Vance

(*) C does have a goto but you're told not to use it just as you're
told not to use the process dictionary.


Post generated using Mail2Forum (http://m2f.sourceforge.net)
enewhuis at futuresource.
Posted: Thu Mar 20, 2003 6:40 pm Reply with quote
Guest
I agree.

----- Original Message -----
From: "martin j logan" <martin_at_vailsys.com>
To: "Jay Nelson" <jay_at_duomark.com>
Cc: <erlang-questions_at_erlang.org>
Sent: Thursday, March 20, 2003 10:55 AM
Subject: RE: Extending Functionality: gen_server_ext


> 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
> >
> >
> >
>



Post generated using Mail2Forum (http://m2f.sourceforge.net)
martin at vailsys.com
Posted: Thu Mar 20, 2003 7:10 pm Reply with quote
Guest
I really should have said side-effect not used global as an example of
one.
I was actually referring to something like ETS. It seems to me that it
can serve much the same purpose as put/2 get/1 i.e a side effect of
sorts or "global" storage at one scope or another. We all try to stay
away from such things but sometimes we break referential transparency,
alter a value that has nothing to do with the expression being
evaluated, when it is convenient.

Cheers,
Martin

On Thu, 2003-03-20 at 12:29, Vance Shipley wrote:
> On Thu, Mar 20, 2003 at 10:55:37AM -0600, martin j logan wrote:
> }
> } Code is mostly referentially transparent except when it is
> } "simpler" to cheat and have a global,
>
>
> I was thinking recently about how I struggled with how to write
> code without global variables when learning Erlang. "How the hell
> can you live without globals?" I asked. It reminded me of learning
> the C language. "How the hell can you live without GOTOs?"(*) I
> asked having only ever programmed in BASIC. I've never used either
> and no longer see any reason to do so.
>
> -Vance
>
> (*) C does have a goto but you're told not to use it just as you're
> told not to use the process dictionary.




Post generated using Mail2Forum (http://m2f.sourceforge.net)
spearce at spearce.org
Posted: Thu Mar 20, 2003 7:14 pm Reply with quote
Guest
Erlang has a two kinds of globals:

registered processes
named ets tables

Without either you'd be up a creek without a paddle, or at least
being forced to hand an argument to every function to lookup a
process - what a mess.

You simply cannot write complex programs easily (meaning with few
keystrokes) without SOME form of globals. It just happens that
Erlang's concept of globals are actually not dangerous, quite unlike
globals in most object and imperative programming languages.

Vance Shipley <vances_at_motivity.ca> wrote:
> On Thu, Mar 20, 2003 at 10:55:37AM -0600, martin j logan wrote:
> }
> } Code is mostly referentially transparent except when it is
> } "simpler" to cheat and have a global,
>
>
> I was thinking recently about how I struggled with how to write
> code without global variables when learning Erlang. "How the hell
> can you live without globals?" I asked. It reminded me of learning
> the C language. "How the hell can you live without GOTOs?"(*) I
> asked having only ever programmed in BASIC. I've never used either
> and no longer see any reason to do so.
>
> -Vance
>
> (*) C does have a goto but you're told not to use it just as you're
> told not to use the process dictionary.

--
Shawn.

Last night the power went out. Good thing my camera had a flash....
The neighbors thought it was lightning in my house, so they called the cops.
-- Steven Wright


Post generated using Mail2Forum (http://m2f.sourceforge.net)
vances at motivity.ca
Posted: Thu Mar 20, 2003 7:37 pm Reply with quote
Guest
Ah well that is another story isn't it?

You can do two main things to share knowledge between processes in
Erlang:

1) store it in ETS

2) store it in the State data of a server process

The latter is probably a more pure solution. You can call ETS
cheating in the same way that the process dictionary is cheating
if you wish. I call it optimizing. :)

I use ETS quite often for this purpose. I'm especially prone to:

ets:update_counter(Tid, callReference, 1).


-Vance


On Thu, Mar 20, 2003 at 02:14:24PM -0500, Shawn Pearce wrote:
}
} Erlang has a two kinds of globals:
}
} registered processes
} named ets tables


Post generated using Mail2Forum (http://m2f.sourceforge.net)
ulf.wiger at telia.com
Posted: Thu Mar 20, 2003 9:27 pm Reply with quote
Guest
Well, you can actually implement a program that perfectly mimics ETS, using
only processes and message passing (and some nifty data structure, like
dict).

The only tangible difference is that performance will be roughly 30x slower.
;-)

Semantically, I don't think ETS tables are dirtier than processes, for this
very reason.

/Uffe

----- Original Message -----
From: "Vance Shipley" <vances_at_motivity.ca>
To: <erlang-questions_at_erlang.org>
Sent: den 20 mars 2003 20:37
Subject: Re: Extending Functionality: gen_server_ext


>
> Ah well that is another story isn't it?
>
> You can do two main things to share knowledge between processes in
> Erlang:
>
> 1) store it in ETS
>
> 2) store it in the State data of a server process
>
> The latter is probably a more pure solution. You can call ETS
> cheating in the same way that the process dictionary is cheating
> if you wish. I call it optimizing. Smile
>
> I use ETS quite often for this purpose. I'm especially prone to:
>
> ets:update_counter(Tid, callReference, 1).
>
>
> -Vance
>
>
> On Thu, Mar 20, 2003 at 02:14:24PM -0500, Shawn Pearce wrote:
> }
> } Erlang has a two kinds of globals:
> }
> } registered processes
> } named ets tables



Post generated using Mail2Forum (http://m2f.sourceforge.net)
cpressey at catseye.mb.ca
Posted: Fri Mar 21, 2003 12:00 am Reply with quote
Guest
On Wed, 19 Mar 2003 20:36:38 +0100
"Vlad Dumitrescu" <vlad_dumitrescu_at_hotmail.com> wrote:

> > But surely the client isn't expecting the call to be transformed into
> > a cast... ?? My vague feeling is that ideally there should be one
> > function, gen_server_ext:next(), that goes to the same type of handler
> > (cast, call, info etc) in the next behaver.
>
> Oh, sorry -- I didn't read your question properly. Long day, lots of
> work:-) Of course my answer only applies to calling next_call from a
> handle call.

No problem. It probably wouldn't be a common typo, and I'm sure there'd
be a way to catch it before anything weird happens... by examining the
call stack, perhaps :)

> > Another question: what are the pros and cons of having to call
> > next_call() et al, as opposed to returning a value like {next_call,
> > ...} from the handler, and having gen_server_ext pay attention to
> > that?
>
> If you return with {next_call, ...} then you can't get the answer back
> and refine it. It's something in between the two options you mentioned
> before, I think.

Yeah, makes sense.

> I have this feeling that there's a lot more to dig out here.
>
> regards,
> Vlad

I dunno, it sounds better and better the more I think about it.

Consider an example, say you have a server and you want to add logging of
some kind. All you need to do is add another behaver inside
gen_server_ext, "in front of" your server, that logs whatever, then calls
next_call. Seems more elegant to me than having a seperate gen_server for
logging which delegates to the original gen_server.

But that's kind of a contrived example, I'll try to think of a better one.

On the subject of what I've been exploring - that is, having a seamless
transition between processless and processful objects - I had a bit of an
epiphany this afternoon - I think it would turn out to be something like
Ulf's mdisp package (which I unfortunately haven't looked at closely
enough yet), except more dynamic. I have something half-coded that I'll
try to finish - basically, I have a bunch of things in an ETS table, and a
function notify/2 which sends a thing a message. If the thing is inactive
(no process,) it gets activated first (a process is spawned for it.) The
process generally runs a receive statement (which can deactivate itself
after a timeout, if need be.) This should let me track tens (or maybe
hundreds) of thousands of things, but only have as many processes as are
actually needful at any given time.

I'll keep y'all updated... :)

-Chris


Post generated using Mail2Forum (http://m2f.sourceforge.net)
Vlad.Dumitrescu at erv.er
Posted: Fri Mar 21, 2003 8:46 am Reply with quote
Guest
Hi,

> From: martin j logan [mailto:martin_at_vailsys.com]
> 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.

I can assure you the discussion not have anything to do with being
smart or not. If anything, maybe with my own inability to grasp key
concepts. :-)

> 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.

Yes, you are absolutely right!

> 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.

Here I don't really agree. Erlang is just as you say, but not anything
about Erlang is simple. Take for example OTP (there was a thread
recently about this) and please anybody who can really say he/she
masters it, raise your hand! I think there won't be more than ten
hands raised... the reason: OTP is complex, even if it's built on
Erlang.

Now is there anyone doubting the need for OTP in a complex system
setting? Not many hands here either, I'd guess... the reason:
OTP is useful. We accept the price of added complexity because it
saves effort somewhere else.

What we are talking about here about extendig Erlang, is not really
about the language, but about OTP. The language is a base to build on,
with higher-level abstractions. If it weren't like that, we would all
still write assembler. What we are exploring is another approach to
building functionality. Maybe in the end it will not look at all like
we are discussing it today, maybe it will be much simpler. But for now
I can only think of it in these terms.

best regards,
Vlad


Post generated using Mail2Forum (http://m2f.sourceforge.net)
Vlad.Dumitrescu at erv.er
Posted: Fri Mar 21, 2003 10:24 am Reply with quote
Guest
Hello,

> From: Jay Nelson [mailto:jay_at_duomark.com]
>Chris and Vlad discussed:
>> Extensions to gen_server to support "behavers" and pseudo
>> inheritance call chains ...
> Chained processes - deep inheritance
<...snipped...>
> Interface amalgam - shallow inheritance
<...snipped...>

You make some interesting observations, and I will have to sit down
and think about it properly before replying. Right now, I'd like to
make some observations of my own.

What I think it would be best (inspired from both your and Chris'
ideas) is some kind of behavioural composition. It might involve a
separate process per simple behaviour, or maybe thay can be combined
in a single process. It was the latter I was thinking about when
writing gen_server_ext: one process implementing several
behaviours. But this latest idea of the Amalgam, is really interesting.

What I'd like to be able to do is create a process by specifying
several interfaces/behaviours it will support, a GUI related example
might be for a button: I need let's say 'drawable', 'clickable',
'mouse_over'. Just by naming them, I get the functionality, and I can
(if I want) to override some of the functionality to better suit the
button's needs. There will be some callbacks that the behaviours need:
for example 'mouse_over' can call button:on_mouse_over(), where the
pointer can be set to a hand instead of an arrow. If the button shall
become inactive, it will be enough to just disable it's 'clickable'
behaviour.

Potential problem: how to ensure that these behaviours do not have
overlapping interfaces? (i.e. message tags or callback names that are
the same)

Maybe a better analogy than "objects" is "components". Use behaviours
(as processes or as modules) as components, building stones for more
advanced components and finally whole systems. This didn't work so
well for OO components, but this doesn't mean the basic idea is
flawed.

Of course, all this can be done by hand, but it seems like a general
enough functionality to implement once, test properly and reuse. Just
like gen_server, for example :-)

best regards,
Vlad



Post generated using Mail2Forum (http://m2f.sourceforge.net)

Display posts from previous:  

All times are GMT
Page 1 of 2
Goto page 1, 2  Next
This forum is locked: you cannot post, reply to, or edit topics.

Jump to:  

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum