Erlang hints for an OO junkie

classic Classic list List threaded Threaded
54 messages Options
123
Reply | Threaded
Open this post in threaded view
|

Erlang hints for an OO junkie

Jay Nelson
I just finished writing an article for the Snowbird ICFP workshop on
erlang entitled "Structured Programming Using Processes".  Look for it
when the conference comes out or check my website in November.

The basic premise in the paper is to think of data flows and processes
rather than OO.  In OO an object is stored and represented in a single
place with all the code that can access the data.  In erlang, messages
are sent from process to process so data can be stored in whatever
format is best for each process.  You may neeed to keep things in a
database, so you can have one table per object type, or coerce all to
fit in a single table with some extra columns.  A process could read the
currently relevant ones in as a list and dole them out to other
processes for manipulation.  User commands can be received, transformed
and routed to the process holding the object in question.

For your gaming problem you need to decide what must be done
concurrently and what must be done sequentially.  Everything else can go
either way.  If you have a process for each person or monster (animate
entities), internal to the process can be their possessions which they
can give to another process in exchange for something else.  The same
can happen with traits.

If you are stuck on objects, make a process for every object.  You will
run into some problems, but you may feel comfortable.

jay



Reply | Threaded
Open this post in threaded view
|

Erlang hints for an OO junkie

Johan Warlander
On Mon, 09 Aug 2004 08:32:27 -0700, Jay Nelson wrote
> I just finished writing an article for the Snowbird ICFP workshop on
> erlang entitled "Structured Programming Using Processes".  Look for
> it when the conference comes out or check my website in November.

Will certainly do :)

> The basic premise in the paper is to think of data flows and
> processes rather than OO.  In OO an object is stored and represented
> in a single place with all the code that can access the data.  In
> erlang, messages are sent from process to process so data can be
> stored in whatever format is best for each process.  You may neeed
> to keep things in a database, so you can have one table per object
> type, or coerce all to fit in a single table with some extra
> columns.  A process could read the currently relevant ones in as a
> list and dole them out to other processes for manipulation.  User
> commands can be received, transformed and routed to the process
> holding the object in question.

I haven't even started looking at database handling etc.. I take it Mnesia
would be the way to go? However, I definitely think I'd go for a table per
object type. Here's where I run into the OO ghost again, though.. Given two
different objects, a chair and a backpack, they have some traits in common (in
the OO world I'd have them inherit from CONTAINER).. but

>
> For your gaming problem you need to decide what must be done
> concurrently and what must be done sequentially.  Everything else
> can go either way.  If you have a process for each person or monster
> (animate entities), internal to the process can be their possessions
> which they can give to another process in exchange for something
> else.  The same can happen with traits.

I think I have a vague idea of what you're getting at :) I'm also realising
that it's probably not entirely useful to try to think of things in terms of
what I would've done in an OO language..

Either way, would you be able to give me some pointers on where to start
implementing a simple scenario like the one below, in a process-oriented way?

1) The world consists of simple rooms with a textual description, linked
together in the four cardinal directions.

2) Players can walk around between these rooms, and will see the room
descriptions as well as other players in the same room.

3) Players can communicate with others in the same room by talking.

4) Any entity, not just player characters, should be able to receive
communication messages in the form of talking or acting.. This becomes
important for allowing non-player characters to act on what players do later
on, and also enchanted items might be activated by certain actions or words etc.*

* Not to mention going further with containers, when you want to model in-game
vehicles etc - someone sitting in a wagon pulled by a horse, in a particular
room, would most likely be modeled by the game as being inside a container in
the room, which itself is also a container.

It's pretty much the most basic stuff, and given your hints above, I figure
that each player (person) would be a process. The rooms, however.. a single
resource process of some kind, that would keep track of the game geography and
how to navigate it?

> If you are stuck on objects, make a process for every object.  You
> will run into some problems, but you may feel comfortable.

Nah, I'm trying to learn something new in the process. Feeling comfortable
isn't my highest priority ;)

Johan


Reply | Threaded
Open this post in threaded view
|

Erlang hints for an OO junkie

Johan Warlander
In reply to this post by Jay Nelson
On Mon, 09 Aug 2004 08:32:27 -0700, Jay Nelson wrote
> I just finished writing an article for the Snowbird ICFP workshop on
> erlang entitled "Structured Programming Using Processes".  Look for
> it when the conference comes out or check my website in November.

Will certainly do :)

> The basic premise in the paper is to think of data flows and
> processes rather than OO.  In OO an object is stored and represented
> in a single place with all the code that can access the data.  In
> erlang, messages are sent from process to process so data can be
> stored in whatever format is best for each process.  You may neeed
> to keep things in a database, so you can have one table per object
> type, or coerce all to fit in a single table with some extra
> columns.  A process could read the currently relevant ones in as a
> list and dole them out to other processes for manipulation.  User
> commands can be received, transformed and routed to the process
> holding the object in question.

I haven't even started looking at database handling etc.. I take it Mnesia
would be the way to go? However, I definitely think I'd go for a table per
object type. Here's where I run into the OO ghost again, though.. Given two
different objects, a chair and a backpack, they have some traits in common (in
the OO world I'd have them inherit from CONTAINER).. but

>
> For your gaming problem you need to decide what must be done
> concurrently and what must be done sequentially.  Everything else
> can go either way.  If you have a process for each person or monster
> (animate entities), internal to the process can be their possessions
> which they can give to another process in exchange for something
> else.  The same can happen with traits.

I think I have a vague idea of what you're getting at :) I'm also realising
that it's probably not entirely useful to try to think of things in terms of
what I would've done in an OO language..

Either way, would you be able to give me some pointers on where to start
implementing a simple scenario like the one below, in a process-oriented way?

1) The world consists of simple rooms with a textual description, linked
together in the four cardinal directions.

2) Players can walk around between these rooms, and will see the room
descriptions as well as other players in the same room.

3) Players can communicate with others in the same room by talking.

4) Any entity, not just player characters, should be able to receive
communication messages in the form of talking or acting.. This becomes
important for allowing non-player characters to act on what players do later
on, and also enchanted items might be activated by certain actions or words etc.*

* Not to mention going further with containers, when you want to model in-game
vehicles etc - someone sitting in a wagon pulled by a horse, in a particular
room, would most likely be modeled by the game as being inside a container in
the room, which itself is also a container.

It's pretty much the most basic stuff, and given your hints above, I figure
that each player (person) would be a process. The rooms, however.. a single
resource process of some kind, that would keep track of the game geography and
how to navigate it?

> If you are stuck on objects, make a process for every object.  You
> will run into some problems, but you may feel comfortable.

Nah, I'm trying to learn something new in the process. Feeling comfortable
isn't my highest priority ;)

Johan


Reply | Threaded
Open this post in threaded view
|

Erlang hints for an OO junkie

Johan Warlander
<oops.. managed to cut that one off.. here goes; sorry about the double post
before, experiencing some problems with my mail client!>

On Mon, 9 Aug 2004 21:26:00 +0200, Johan Warlander wrote

> > The basic premise in the paper is to think of data flows and
> > processes rather than OO.  In OO an object is stored and represented
> > in a single place with all the code that can access the data.  In
> > erlang, messages are sent from process to process so data can be
> > stored in whatever format is best for each process.  You may neeed
> > to keep things in a database, so you can have one table per object
> > type, or coerce all to fit in a single table with some extra
> > columns.  A process could read the currently relevant ones in as a
> > list and dole them out to other processes for manipulation.  User
> > commands can be received, transformed and routed to the process
> > holding the object in question.
>
> I haven't even started looking at database handling etc.. I take it Mnesia
> would be the way to go? However, I definitely think I'd go for a
> table per object type. Here's where I run into the OO ghost again,
> though.. Given two different objects, a chair and a backpack, they
> have some traits in common (in the OO world I'd have them inherit
> from CONTAINER).. but

..but they might also have some data that is unique to each object, and some
ways of using one that would work different or not at all with the other. I've
not yet wrapped my mind around how to do proper data and code re-use in Erlang.

Johan


Reply | Threaded
Open this post in threaded view
|

Erlang hints for an OO junkie

Jay Nelson
In reply to this post by Johan Warlander
Johan Warlander wrote:

>different objects, a chair and a backpack, they have some traits in common (in
>the OO world I'd have them inherit from CONTAINER).. but
>  
>
Avoid inheritance if you can.  Why do you think you need it?

Re: containers -- processes are one of the best containers available.  
They have a unique name, can be found by the operating system or vm so
you don't need to write access code, they contain only those things
passed as arguments in the server loop and they send things to another
container (process).  Writing the paper helped me discover that this is
probably the most important aspect of a process, providing an isolatable
container of computation -- the second being that it serializes all
requests, so it is very good at maintaining a particular state.  That is
why FSMs are so sweet in erlang.  I find concurrency useful, but one of
the less important characteristics of processes.

>Either way, would you be able to give me some pointers on where to start
>implementing a simple scenario like the one below, in a process-oriented way?
>
>1) The world consists of simple rooms with a textual description, linked
>together in the four cardinal directions.
>
>2) Players can walk around between these rooms, and will see the room
>descriptions as well as other players in the same room.
>
>3) Players can communicate with others in the same room by talking.
>  
>
At this point you have a choice as to processes: people or rooms.  
Everyone says make the concurrent or animate things processes, so the
obvious choice is people, right?  Well... rooms are linked more or less
permanently in a certain fashion, people aren't.  How would you connect
people, and for how long?  People talk to each other but does that cause
them to change state?  Maybe, but not usually.  But people carry weapons
and other objects and give them to others.  In that sense they are
containers of things, and they also happen to be containers of
attributes and characteristics and skills.

Rooms are fundamentally really good containers.  Things move in and out
of them; objects can be rearranged inside them.  Moving in or out, or
picking up or leaving something changes the state of the room as well as
the person.  But the primary mechanism of the game is for people to move
from room to room.  I would start with a geographic map of rooms, and
create a single process per room with interconnections only between
adjacent rooms.  The people and objects in the room would be maintained
in some sort of tree or list and passed as the state variable of the
room.  A message to enter or leave would cause a person to be added to
or removed from the state, with a confirmation for entering or a removal
from the list for leaving (after sending an enter to the destination
room process).

 People could be records or processes.  Processes would let you send
messages like pick up object, set down object, etc.  Either way the
people themselves could be sent as a message from one room to another.

Start with this and forget the rest of the game.  See how far it takes
you, and what code looks like for moving around.  I would just start
with rooms and people moving from room to room and seeing who else is
present.  If you make a room a process, with a list of people processes
in it as the state variable of a looping server, I think you'll find the
code is trivial (hint: look at the package lists for things like
member).  Once you can do that, then grapple with what it means for one
person to talk to another.  It will be the fundamental problem of your
entire program.  If you are hung up on having the program model the real
world accurately, you will never solve the problem of people talking to
one another.  The rest should be straight forward.

jay



Reply | Threaded
Open this post in threaded view
|

Erlang hints for an OO junkie

Johan Warlander
On Mon, 09 Aug 2004 21:35:32 -0700, Jay Nelson wrote
> Avoid inheritance if you can.  Why do you think you need it?

Hmm.. I'm trying to figure that out myself. I think I'll just go ahead as
below, and see what happens -- if I still think I need inheritance for some
particular issue, I'll try to have someone convince me there's a better way to
solve my concern ;)

> Re: containers -- processes are one of the best containers
> available.  They have a unique name, can be found by the operating
> system or vm so you don't need to write access code, they contain
> only those things passed as arguments in the server loop and they
> send things to another container (process).  Writing the paper
> helped me discover that this is probably the most important aspect
> of a process, providing an isolatable container of computation --
>  the second being that it serializes all requests, so it is very
> good at maintaining a particular state.  That is why FSMs are so
> sweet in erlang.  I find concurrency useful, but one of the less
> important characteristics of processes.
>
> >Either way, would you be able to give me some pointers on where to start
> >implementing a simple scenario like the one below, in a process-oriented way?
> >
> >1) The world consists of simple rooms with a textual description, linked
> >together in the four cardinal directions.
> >
> >2) Players can walk around between these rooms, and will see the room
> >descriptions as well as other players in the same room.
> >
> >3) Players can communicate with others in the same room by talking.
> >  
> >
> At this point you have a choice as to processes: people or rooms.  
> Everyone says make the concurrent or animate things processes, so
> the obvious choice is people, right?  Well... rooms are linked more
> or less permanently in a certain fashion, people aren't.  How would
> you connect people, and for how long?  People talk to each other but
> does that cause them to change state?  Maybe, but not usually.  But
> people carry weapons and other objects and give them to others.  In
> that sense they are containers of things, and they also happen to be
> containers of attributes and characteristics and skills.
>
> Rooms are fundamentally really good containers.  Things move in and
> out of them; objects can be rearranged inside them.  Moving in or
> out, or picking up or leaving something changes the state of the
> room as well as the person.  But the primary mechanism of the game
> is for people to move from room to room.  I would start with a
> geographic map of rooms, and create a single process per room with
> interconnections only between adjacent rooms.  The people and
> objects in the room would be maintained in some sort of tree or list
> and passed as the state variable of the room.  A message to enter or
> leave would cause a person to be added to or removed from the state,
> with a confirmation for entering or a removal from the list for
> leaving (after sending an enter to the destination room process).
>
>  People could be records or processes.  Processes would let you send
> messages like pick up object, set down object, etc.  Either way the
> people themselves could be sent as a message from one room to another.
>
> Start with this and forget the rest of the game.  See how far it
> takes you, and what code looks like for moving around.  I would just
> start with rooms and people moving from room to room and seeing who
> else is present.  If you make a room a process, with a list of
> people processes in it as the state variable of a looping server, I
> think you'll find the code is trivial (hint: look at the package
> lists for things like member).  Once you can do that, then grapple
> with what it means for one person to talk to another.  It will be
> the fundamental problem of your entire program.  If you are hung up
> on having the program model the real world accurately, you will
> never solve the problem of people talking to one another.  The rest
> should be straight forward.

Okay, I'm starting to look at this in a completely different way than when I
set out to do this.. Thanks! I'll play around with the ideas you've given me
and see what it comes to. As you say, just starting out with rooms, people and
communication will probably help me understand and evolve a model for how to
do this, without getting too complex too fast.

On a sidenote, while I know I probably shouldn't be thinking about this quite
yet, where would I start running into performance problems as far as
concurrent processes go?
Looking forward (pretty far), there'd probably be a stage at which I'd have a
few thousand rooms (1k - 5k perhaps), a similar amount of computer-generated
creatures with highly varying degrees of complexity in their behaviour
patterns, 20-70 concurrent players (pretty few, but probably resource
intensive) and several processes to govern things like weather, time of day,
etc. All in all, perhaps upwards of 10 000 processes.. where most of them,
admittedly, would have very low resource utilisation. Of course, strictly
speaking inanimate items might also end up being modeled as processes.. and if
so that number could rise to 15 000 in the above scenario.


Thanks for all your help so far :)

Johan


Reply | Threaded
Open this post in threaded view
|

Erlang hints for an OO junkie

Vlad Dumitrescu-4
In reply to this post by Johan Warlander
From: "Johan Warlander" <johan>
> ..but they might also have some data that is unique to each object, and some
> ways of using one that would work different or not at all with the other. I've
> not yet wrapped my mind around how to do proper data and code re-use in
Erlang.

You might also want to check out this Corrado Santoro's Exat, at
http://www.diit.unict.it/users/csanto/exat/index.html. It has a nice
implementation of something that might become "objective erlang".

I believe you will learn a lot more from trying to do it "the clean Erlang way".
For me it was a wonderful revelation when I finally managed to snap out of the
OO mindset. Not that it's wrong, but it's not an universal solution either.

regards,
Vlad



Reply | Threaded
Open this post in threaded view
|

Erlang hints for an OO junkie

Thomas Lindgren-5
In reply to this post by Johan Warlander

--- Johan Warlander <johan> wrote:
> where would I start running into performance
> problems as far as
> concurrent processes go?

My rules of thumb (possibly obsolete) are these:
- one Erlang VM (node) can have about 200,000
processes
- one freshly started process uses about 1 KB

Using objects-as-processes and ubiquitous message
passing, a la method invocation in OO, _might_ become
a performance problem. Erlang is asynchronous, so if A
sends a message to B, some effort is needed to context
switch from A to B, and some time may pass before B is
scheduled to handle the message. (Clever
implementations may get rid of some overhead, but it's
probably good to be aware of the issue.)

If you want something OO-like for code organization,
have a look at Erlang's "behaviours". They work in the
same spirit as Java's "interfaces". I would also
suggest taking a look at "abstract data types", if you
haven't already.

Best,
Thomas



               
__________________________________
Do you Yahoo!?
Yahoo! Mail - 50x more storage than other providers!
http://promotions.yahoo.com/new_mail


Reply | Threaded
Open this post in threaded view
|

Erlang hints for an OO junkie

Johan Warlander
In reply to this post by Vlad Dumitrescu-4
On Tue, 10 Aug 2004 09:15:16 +0200, Vlad Dumitrescu wrote
> I believe you will learn a lot more from trying to do it "the clean
> Erlang way". For me it was a wonderful revelation when I finally
> managed to snap out of the OO mindset. Not that it's wrong, but it's
> not an universal solution either.

Agreed; that's what I'm looking for, first and foremost - to learn what the
Erlang way is :)

Nonetheless, I had a brief look at one of the presentations on the site you
pointed me to, and it seems very interesting if you were to actually use an OO
approach in Erlang. As you say, there's no universal solution, so I guess the
option is always interesting to have.

Thanks,
Johan


Reply | Threaded
Open this post in threaded view
|

Erlang hints for an OO junkie

Johan Warlander
In reply to this post by Thomas Lindgren-5
On Tue, 10 Aug 2004 01:12:43 -0700 (PDT), Thomas Lindgren wrote
> My rules of thumb (possibly obsolete) are these:
> - one Erlang VM (node) can have about 200,000
> processes
> - one freshly started process uses about 1 KB

Well, that was a bit better than I would've imagined :) If those numbers are
obsolete, I would guess performance has changed for the better rather than worse.

> Using objects-as-processes and ubiquitous message
> passing, a la method invocation in OO, _might_ become
> a performance problem. Erlang is asynchronous, so if A
> sends a message to B, some effort is needed to context
> switch from A to B, and some time may pass before B is
> scheduled to handle the message. (Clever
> implementations may get rid of some overhead, but it's
> probably good to be aware of the issue.)

Right, though I suspect messages will not be sent at all as frequently as I'd
be calling methods in an OO approach - rather I imagine that one message would
be preceded by some work on the sending side, and generate some work on the
receiving side, instead of sending a big burst of messages back and forth..

I've been browsing Ulf Wikstr?m's "Design Patterns for Simulations in
Erlang/OTP" and that currently leads me to believe that most messages will be
actual events.. though exactly how I don't know yet, I'll need to start
exploring the problem more thoroughly first I think :)

> If you want something OO-like for code organization,
> have a look at Erlang's "behaviours". They work in the
> same spirit as Java's "interfaces". I would also
> suggest taking a look at "abstract data types", if you
> haven't already.

I've been glancing at behaviours, so we'll see what happens.. I'm trying to
avoid OO-like just for the sake of being like OO, though. If I end up leaning
towards OO-like organisation for aspects of the program, I hope it'll be
because I've become well aquainted with most of the common solutions available
in Erlang, and decided that the OO-like solution is the most appropriate for
the task.

Johan


Reply | Threaded
Open this post in threaded view
|

Erlang hints for an OO junkie

Vlad Balin-2
In reply to this post by Thomas Lindgren-5
>> where would I start running into performance
>> problems as far as
>> concurrent processes go?

> My rules of thumb (possibly obsolete) are these:
> - one Erlang VM (node) can have about 200,000
> processes
> - one freshly started process uses about 1 KB
Exactly. This is one of the reasons why processes cannot be used as objects.

> Using objects-as-processes and ubiquitous message
> passing, a la method invocation in OO, _might_ become
> a performance problem. Erlang is asynchronous, so if A
> sends a message to B, some effort is needed to context
> switch from A to B, and some time may pass before B is
> scheduled to handle the message. (Clever
> implementations may get rid of some overhead, but it's
> probably good to be aware of the issue.)

There's an another problem. Erlang is functional language, where destructive
updates and other side effects are not desirable things.

If you will use processes as a unit of incapsulation (think of it as object)
you
will introduce destructive updates, and loose the benefits of Erlang as
functional language.
I'm going to demonstrate it.

Process is "object", with a message loop dispatching "messages", like in a
Smalltalk.
Something like this:

loop( State ) ->
        receive { Caller, MethodName, Params } ->
                { Result, NewState } = apply( className, MethodName, [ State | Params ] ),
                Caller ! Result,
                object( State )
        end.

And you may want to call "methods" like this:

invoke( Object, Method, Params ) ->
        Object ! { self(), Method, Params },
        receive Result -> Result.

And you're using the process ID as a reference to the "object". Cool. Your
objects
has state, you may pass objects as a parameters and do other familiar
things. But
look here, what would be the often seen in your code:

method( State, Object1 ) ->
        { AggregatedObject, _, _ } = State,
        { invoke( AggregatedObject, doDestructiveUpdate, [ Object1 ] ), State }.

Miracle! State of the caller has _not_ been changed when we have updated its
part.
An innocent message sending side effect has been grown in evil destructive
update.
If you going to use it your design as a leading principle, the better idea
would be
to use Smalltalk instead, not to emulate it in Erlang.

So what is wrong here? Processes should _not _ be widely used as unit of
incapsulation, or you will not take benefit of referential transparency. And
if you do so,
you would better use non-functional language.



Reply | Threaded
Open this post in threaded view
|

Erlang hints for an OO junkie

Vlad Balin-2
>> So what is wrong here? Processes should _not _ be widely used as unit of
>> incapsulation, or you will not take benefit of referential transparency.
And
>> if you do so,
>> you would better use non-functional language.

> You forgot to suggest what the OP should use in place of processes. He
> seems genuinely interested in what the 'right' way to do things is.  I'm
> interested in the results of the discussion too, it's educational as I
> haven't been using Erlang very long myself.

> Thankyou
> --
> David N. Welton

I'm sorry. This questions should better be addressed to the functional
programming gurus, however I will add my 10 cents too.

As in normal languages,
the first thing we could use in design should probably be an incapsulation,
or so called "abstract data types". Types, which are defined by the
operations
in them rather than their structure. For example, consider queue
implementation
from the standard library. It has not obvious (at least for imperative
programmer)
data structure, similar to Okasaki's queue (pair of two lists). Module queue
exposes queue constructor (new), and all of necessary operations (in, out,
etc).
#So we can create the queue
Queue = queue:new(),
#put in some elements
Q1 = queue:in( Element1, Queue ),
Q2 = queue:in( Element2, Q1 ),
#and pass it as a parameter
doSomething( Q2 ).

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

An answer is that we should pass the module name ("class name") to this
function
in a some way...
Queue = anotherQueue:new(),
generic_function( anotherQueue, Queue ).
...and use it as a prefix for queue "methods" in function implementation.

To make it looking more "cool" (more close to the "classic" OO style) we
could include
module ID in data structure. Let's suppose that object in a top level is
always a tuple,
and the first element always contains the module name. Than we could invoke
"methods"
like this:

invoke( Object, Method, Params ) ->
        apply( getelement( 0, Object ), Method, [ Object | Params ] ).

I think you got an idea. I believe that people who have an experience of
development
in Erlang could suggest more effective and elegant approaches.

Vlad Balin



Reply | Threaded
Open this post in threaded view
|

Erlang hints for an OO junkie

Vlad Balin-2
> invoke( Object, Method, Params ) ->
> apply( getelement( 0, Object ), Method, [ Object | Params ] ).

> I think you got an idea. I believe that people who have an experience of
development
> in Erlang could suggest more effective and elegant approaches.
like this, for example ;)

class( Object ) -> element( 0, Object ).

generic_function( Object ) ->
        Class = class( Object ),
        Class:callMethod( Object ).

Hope have not made mistakes now :)

Vlad Balin



Reply | Threaded
Open this post in threaded view
|

Erlang hints for an OO junkie

Carsten Schultz-2
In reply to this post by Vlad Balin-2
Hi!

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.

Greetings,

Carsten

--
Carsten Schultz (2:38, 33:47), FB Mathematik, FU Berlin
http://carsten.codimi.de/
PGP/GPG key on the pgp.net key servers,
fingerprint on my home page.
-------------- next part --------------
-module(queue).

-export([empty_list_queue/0,empty_okasaki_queue/0,
         is_empty/1,in/2,out/1]).

list_empty() ->
    [].

list_is_empty([]) ->
    true;
list_is_empty([_|_]) ->
    false.

list_in(X, L) ->
    [X|L].

list_out(L) ->
    [H|T] = lists:reverse(L),
    {H, lists:reverse(T)}.


okasaki_empty() ->
    {[], []}.

okasaki_is_empty({[], []}) ->
    true;
okasaki_is_empty(_) ->
    false.

okasaki_in(X, {In, Out}) ->
    {[X|In], Out}.

okasaki_out({In, [X|Out]})->
    {X, {In, Out}};
okasaki_out({In, []}) ->
    [X|Out] = lists:reverse(In),
    {X, {[], Out}}.

-record(queue_dict, {is_empty, in, out}).

make_gen_queue(Empty, Is_Empty, In, Out) ->
    {#queue_dict{is_empty=Is_Empty, in=In, out=Out}, Empty()}.

empty_list_queue() ->
    make_gen_queue(fun list_empty/0, fun list_is_empty/1,
                   fun list_in/2, fun list_out/1).

empty_okasaki_queue() ->
    make_gen_queue(fun okasaki_empty/0, fun okasaki_is_empty/1,
                   fun okasaki_in/2, fun okasaki_out/1).

is_empty({D, Q}) ->
    (D#queue_dict.is_empty)(Q).

in(X, {D, Q}) ->
    {D, (D#queue_dict.in)(X, Q)}.

out({D, Q}) ->
    {O, Q0} = (D#queue_dict.out)(Q),
    {O, {D, Q0}}.
                   

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20040810/9023f85b/attachment.bin>

Reply | Threaded
Open this post in threaded view
|

Erlang hints for an OO junkie

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

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.

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


Reply | Threaded
Open this post in threaded view
|

Erlang hints for an OO junkie

Matthias Lang-2
In reply to this post by Vlad Balin-2
Vlad Balin writes:

 > There's an another problem. Erlang is functional language, where destructive
 > updates and other side effects are not desirable things.

 > If you will use processes as a unit of incapsulation (think of it as object)
 > you> will introduce destructive updates, and loose the benefits of Erlang as
 > functional language.
[...]
 > If you going to use it your design as a leading principle, the better idea
 > would be to use Smalltalk instead, not to emulate it in Erlang.

Desperately avoiding side effects feels a bit like trying to write
Haskell programs in Erlang. I don't know if that's better or worse
than trying to write Smalltalk programs in Erlang, but it'll also lead
to disappointment, especially when implementing a system with a lot of
inherent concurrency (e.g. a switch).

Using a process for encapsulation _is_ a common, normal and useful
thing to do in Erlang. I'm not advocating transforming an OO design
into an Erlang implementation by replacing all objects with a process,
but often a process _is_ a useful unit of encapsulation.

Matthias


Reply | Threaded
Open this post in threaded view
|

Erlang hints for an OO junkie

Chris Pressey
In reply to this post by Johan Warlander
On Tue, 10 Aug 2004 21:31:27 +0200
"Johan Warlander" <johan> 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 :/


Reply | Threaded
Open this post in threaded view
|

arithmetic anomaly?

Charles Blair

with the erlang shell i get this:

(1024*1024-1) / 1024.
1024.00

the equivalent expression on the same platform (NetBSD on Intel) in
the clisp implementation of common lisp gives me this:

(/ (- (* 1024 1024) 1) 1024.0)
1023.999

ocaml:

# float_of_int (1024*1024-1) /. 1024.0;;
- : float = 1023.99902344

python:

(1024*1024-1) / 1024.
1023.9990234375

the following gives a more expected result in erlang, so i wonder
whether it's not a rounding error somewhere:

(1024*1024-6) / 1024.
1023.99



Reply | Threaded
Open this post in threaded view
|

arithmetic anomaly?

Michał Ptaszek
You forgot one line:

1> (1024*1024-1)/1024.
1024.00
2> io:format("~.5f",[v(-1)]).
1023.99902ok

It is just an rounding to 2 decimal thing. The erlang shell
by default gives you 2 decimals and that is correctly rounded
up to 1024.00.

/Peter

>
> with the erlang shell i get this:
>
> (1024*1024-1) / 1024.
> 1024.00
>
> the equivalent expression on the same platform (NetBSD on Intel) in
> the clisp implementation of common lisp gives me this:
>
> (/ (- (* 1024 1024) 1) 1024.0)
> 1023.999
>
> ocaml:
>
> # float_of_int (1024*1024-1) /. 1024.0;;
> - : float = 1023.99902344
>
> python:
>
> (1024*1024-1) / 1024.
> 1023.9990234375
>
> the following gives a more expected result in erlang, so i wonder
> whether it's not a rounding error somewhere:
>
> (1024*1024-6) / 1024.
> 1023.99
>


--
Peter Lund
http://lundata.se,+46 70 543 9416


Reply | Threaded
Open this post in threaded view
|

arithmetic anomaly?

Johan Warlander
In reply to this post by Charles Blair
On Wed, 11 Aug 2004 00:05:55 -0500 (CDT), chas wrote

> with the erlang shell i get this:
>
> (1024*1024-1) / 1024.
> 1024.00
>
> the equivalent expression on the same platform (NetBSD on Intel) in
> the clisp implementation of common lisp gives me this:
>
> (/ (- (* 1024 1024) 1) 1024.0)
> 1023.999

Well.. it's not exactly yesterday that I had my math classes, but rounding of
1023.999 to two decimals would go up, wouldn't it, since the third decimal is
>= 5? Thus, 1024.00.

Johan



123