Erlang hints for an OO junkie

Chris Pressey cpressey@REDACTED
Tue Aug 10 22:45:30 CEST 2004


On Tue, 10 Aug 2004 21:31:27 +0200
"Johan Warlander" <johan@REDACTED> wrote:

> On Tue, 10 Aug 2004 20:03:02 +0200, Carsten Schultz wrote
> > On Tue, Aug 10, 2004 at 08:34:19PM +0400, Vlad Balin wrote:
> > > It's just fine, we succeed, we have a "class" queue defined now,
> > > with a number of "methods".  But here is one problem remains.
> > > Suppose we have defined another implementation of queue with a
> > > same interface.  How would we define a generic function working
> > > with both implementation then?
> > > Problem is that we supposed not to have derect access to the data
> > > structure of the abstract data type, so we need operations to be
> > > _polymorphic_.
> > [solution snipped]
> > 
> > I am not advocating this in any way, but you could also use a style
> > like in the appended module, if you really have to.
> 
> Thanks to both of you for pointing out some other approaches :)
> 
> I'm wondering if the solution really is to find a middle road
> somewhere.. because the more I think of it, the more it seem like I'll
> need most of the physical objects in the game world to actually be
> processes (or possibly group some of them together to be managed by a
> single process). The reason is that I'll need to propagate events. 

My two cents:

If it's "animate", if it has "dynamic behaviour", if it "moves" - model
it as a process.  If it isn't/hasn't/doesn't - model it as a record (or
a dictionary.)

So: people, motorcycles, windmills, radios, thunderstorms, etc are
processes.  Sandwiches, taverns, tables, mountains, etc are records.

To deal with the unorthogonality introduced by this, you can write
wrapper functions that work on either processes or records.  Something
like:

	get_description(Process) when is_pid(Process) ->
	    Process ! {self(), get_description},
	    receive
		{Process, get_description, Description} ->
		    Description
	    end;
	get_description(#object{ desc=Description }) ->
	    Description.

This gives you both encapsulation and polymorphism, two OO favourites :)

> The example I used before is good enough I suppose - if someone in a
> room talks, the sound will need to propagate into any container-like
> items in the room as well (as appropriate) so that people sitting in a
> wagon, or hiding in a chest or closet for that matter, will have a
> chance of hearing what the person is saying.

For this, you will need to implement some sort of broadcaster pattern. 
Although the medium through which the speech travels will be involved,
it need not be a process (because it's still inert - it doesn't have any
dynamic behaviour, it's just a carrier.)  Something like:

	say(Actor, Location, Speech) ->
	    Listeners = find_listeners(Location),
	    lists:foreach(fun(Listener) ->
		hear(Listener, Actor, Speech)
	    end, Listeners).

find_listeners(Location) would be something like a database query that
finds all the things in the vicinity of the Location that are capable of
hearing something said in the Location.  The Location would typically be
a record (not a process) and the listeners would typically be processes
(not records,) but that needn't be a hard and fast rule - you might have
magic swords that can respond to spoken commands or a family of
intelligent insects that have a discussion while sitting on a person's
scalp.  Again, if you write wrapper functions to do the polymorphism,
you don't have to worry about those distinctions as much.  And if you
have sub-locations (such as tables within a tavern,) you can search
recursively through adjacent/contained objects (maybe limiting the depth
of the search based on the volume of the speech) instead of relaying
messages around.

What I'm trying to say is that the propogation you're suggestion strikes
me as a kind of searching problem, and things don't *have* to be
processes in order for you to search through them.

That said, you could very well model everything as processes, and have
messages propogate from people to rooms back to people, and such.  This
may be a more elegant way to address the problem in some ways, but in my
mind it's not sufficiently more elegant to warrant doing it.  You can
have a *lot* of processes in Erlang, but even so, the more conservative
you are with them, the more efficient the result.  If you model
everything as a process you might be able to have 50K rooms, 50K items,
50K animals and 50K players; but if you only model "animate" things as
processes you'll be able to have 100K animals, 100K players, and who
knows how many rooms and items :)

Again, just my two cents.

> Going further into the problem domain, eventually I will begin to
> model Proximities, and those will be heavily dependent on the above
> interactions. A Proximity in this context is strictly speaking a
> location *within* a room, for
>  example one of the tables in a tavern. 
> 
> The way it'll work is that if people sit around one table and whisper
> together, an outside observer in the same room will only be able to
> see/hear that they are whispering, but not what. On the other hand, if
> they talk normally, you'd actually be able to hear it.. and if they
> start shouting, it'll easily come across into other proximities in the
> room (in this example, people around other tables will hear them). 
> 
> I'm used to implementing this as a container without any physical
> obstructions to the outside, since Proximities *do* essentially
> 'contain' people.
> 
> Of course, I don't know if there might a better way than using
> processes like this, to perform that particular feat..
> 
> Johan 
> 

Whichever way you choose to go, good luck!

-Chris
...too busy with DragonFly to do much Erlang hacking lately :/



More information about the erlang-questions mailing list