Re: Euphoria Objects

new topic     » topic index » view thread      » older message » newer message

John wrote:


> Creating objects with Euphoria?
> I am kinda new with all this and
> fuzzy about objects in general.

You can think of an object as a collection of attributes about a thing.
These can often be represented in a { object, attribute, value } tuple. For
example, here's a representation of a cat:

   { MyCat, name, Mr. Fleabag }
   { MyCat, color, orange }
   { MyCat, attitude, snooty }
   { MyCat, prime directive, sleep }

You get the general idea. You can have as many attributes for an object as
you want.

Implementing this is pretty simple: create a database of { object,
attribute, value ) tuples:

   sequence db
   db = {}

It's often convenient for objects have some sort of persistance, beyond the
scope of the routine that created them. For this reason, you probably want
to store your object in some global object, instead of a local variable.
That way, you can pass the object's identifier to some routine, and the
routine can permanantly alter the object, without having to pass it back to
the caller.

You need to be able to set, remove, and find tuples. Here's an example of
what some of those routines might look like if you didn't care about
efficiency:

   function findVal( object key, object attribute )
      -- return index of object's attribute in database
      for i = 1 to length( db ) do
         if equal( db[i][1], key )
         and equal( db[i][2], attribute ) then
            return i
         end if
      end for
      return 0
   end function

   function getVal( object key, object attrib )
      -- return the value of an object's attribute
      integer at
      at = findVal( key, attrib )
      if at then
         return db[at][3]
      else
         return "unknown"
      end if
   end function

   procedure setVal( object key, object attrib, object val )
      -- set or replace the value of an object's attribute
      integer at
      at = findVal( key, attrib )
      if at then
         db[at][3] = val
      else
         db &= {{key, attrib, val}}
      end if
   end procedure


Often, objects belong to classes, which are generalizations about a
particular kind of thing. For example, "cat" could be a class:

   { cat, order, mammal }
   { cat, favorite food, tuna }

I've declared that cats (in general) are all mammals, and have tuna as their
favorite food. However, if my object declares something other than the
class:

   { MyCat, favorite food, Fatty Deli Snax }

then the object takes precedence.

Classes can inherit from other classes. For example, "cat" could inherit
from "mammal":

   { cat, class, mammal }
   { mammal, fur bearing, true }
   { mammal, milk producing, true }

In this case, "mammal" would be the superclass of "cat". This could continue
on and on, up the chain.

At this point, it makes sense to rewrite the getVal() routine to implement
inheritance:

   function getVal( object key, object attrib )
      integer at
      at = findVal( key, attrib )
      if at then
         return db[at][3]
      else
         -- recursively call the class
         at = findVal( key, "class" )
         if at then
            return getVal( db[at][3], attrib )
         else
            return "unknown"
         end if
      end if
   end function

If this were more than a toy example, I wouldn't be using the object
database to store class tuples. For one thing, there's too much chance for a
name collision. But let's move on...

Here's an example of the code in action:

   -- a convenience function
   procedure printVal( object key, object attrib )
      puts( 1, getVal( key, attrib ) & '\n' )
   end procedure

   -- class defaults
   setVal( "cat", "color", "orange" )
   setVal( "cat", "favorite food", "tuna" )
   setVal( "cat", "name", "Kitty" )

   -- my cat
   setVal( "myCat", "class", "cat" )
   setVal( "myCat", "name", "Mr. Fleabag" )
   setVal( "myCat", "color", "brown" )

I can ask Euphoria what color my cat is:

   printVal( "myCat", "color" )

and Euphoria responds with "brown", which is part of the object's
information. If I ask what his favorite food is:

   printVal( "myCat", "favorite food" )

Euphoria responds with "tuna", which was inherited from his class. If I ask
for his age:

   printVal( "myCat", "age" )

Euphoria searches through the object, then the class, and superclasses (if
there are any) and finally responds "unknown".

Classes typically have "methods", which are simply a fancy name for
routines. Methods can be implemented using by placing routine_id's in as
values, and the calling something like this:

   procedure method( object key, object attrib. sequence args )
      object val
      val = getVal( key, attrib )
      if equal( val, "unknown" ) then
         puts( "unknown method " & attrib & "\n" )
      else
         call_proc( val, args )
      end if
   end procedure

So you could create class methods like this:

   procedure dog_talk()
      puts( 1, "woof" )
   end procedure
   setVal( "dog", "talk", routine_id("dog_talk") )

   procedure cat_talk()
      puts( 1, "meow" )
   end procedure
   setVal( "cat", "talk", routine_id("cat_talk") )

You can then call the method like this:

   method( "myCat", "talk", {} )

and Euphoria calls the correct method if it finds it among the object,
class, or superclass. If you created a dog:

   addVal( "fido", "class", "dog" )

and called the same "talk" method:

   method( "fido", "talk", {} )

Euphoria responds "woof", calling with the dog method. This feature of the
same routine name ("talk") having different behaviors depending on the class
is known as "polymorphism".

Objects, attributes, value; persistance; classes, superclasses, inheritance;
methods and polymorphism... that just about covers it.

I hope this helps!

-- David Cuny

new topic     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu