1. Classless class-oriented programming

In a previous article I showed a preprocessor to allow class-like programming. There are many other ways to do the job.

Here is one which could even be used with previous preprocessor.

Here is the library (classes.e):

namespace classes 
 
include std/convert.e 
 
-- INTERNAL CONSTANTS 
constant CLASS_NAME   =1, CLASS_PROPERTY=2,   CLASS_METHOD=3 
constant PROPERTY_NAME=1, PROPERTY_VALUE=2 
constant METHOD_NAME  =1, METHOD_ROUTINE_ID=2 
constant CLASS_ID     =1, ENTITY_VALUES=2 
 
-- INTERNAL VARIABLES 
public sequence classes = {}, entities = {} 
 
-- INTERNAL FUNCTIONS 
procedure error_message(sequence msg) 
  puts(2, "Error: " & msg & "\n")  
  abort(1)  
end procedure 
 
-- GLOBAL CLASS FUNCTIONS 
 
-- define a ClassName 
-- given the ClassName Name returns the ClassName ID 
public function class(sequence className) 
  classes = append(classes, {className, {}, {}}) 
  return length(classes) 
end function 
 
-- define a ClassName property 
public procedure addProperty(integer classID, sequence propertyName, object defaultValue) 
  if classID > 0 then 
    classes[classID][CLASS_PROPERTY] = append(classes[classID][CLASS_PROPERTY], {propertyName, defaultValue}) 
  else 
    error_message(sprintf("addProperty(%d, \"%s\", %s): no ClassName parameter\n", 
                      {classID, propertyName, to_string(defaultValue)})) 
  end if 
end procedure 
 
-- define a ClassName method 
public procedure addMethod(integer classID, sequence methodName, integer routineId) 
  if classID > 0 then 
    classes[classID][CLASS_METHOD] = append(classes[classID][CLASS_METHOD], {methodName, routineId}) 
  else 
    error_message(sprintf("addMethod(%d, \"%s\", %d): no ClassName parameter\n", 
                      {classID, methodName, routineId})) 
  end if 
end procedure 
 
-- get the class name of a class ID 
public function findClass(sequence name) 
  for i = 1 to length(classes) do 
    if equal(name, classes[i][CLASS_NAME]) then return i end if 
  end for 
  return 0 
end function 
 
-- find property 
public function findProperty(integer classID, sequence property) 
  for i = 1 to length(classes[classID][CLASS_PROPERTY]) do 
    if equal(property, classes[classID][CLASS_PROPERTY][i][PROPERTY_NAME]) then 
      return i 
    end if 
  end for 
  return 0 
end function 
 
-- find method routine_id 
public function findMethod(integer classID, sequence method) 
  for i = 1 to length(classes[classID][CLASS_METHOD]) do 
    if equal(method, classes[classID][CLASS_METHOD][i][METHOD_NAME]) then 
      return classes[classID][CLASS_METHOD][i][METHOD_ROUTINE_ID] 
    end if 
  end for 
  return 0 
end function 
 
-- GLOBAL ENTITY FUNCTIONS 
 
-- create an Entity of the class ClassName 
public function new(integer classID) 
  sequence class = classes[classID] 
  sequence values =  {} 
  for i = 1 to length(class[CLASS_PROPERTY]) do 
    values = append(values, class[CLASS_PROPERTY][i][PROPERTY_VALUE]) 
  end for 
  entities = append(entities, {classID, values}) 
  return length(entities) 
end function 
 
-- get entity class ID 
public function getClassID(integer entityID) 
  return entities[entityID][CLASS_ID] 
end function 
 
-- get property value 
public function getProperty(integer entityID, sequence property, object defaultValue=0) 
  integer classID = entities[entityID][CLASS_ID] 
  integer propertyID = findProperty(classID, property) 
  if propertyID then 
    return entities[entityID][ENTITY_VALUES][propertyID] 
  end if 
  return defaultValue 
end function 
 
-- set property value 
public procedure setProperty(integer entityID, sequence property, object val) 
  integer classID = entities[entityID][CLASS_ID] 
  integer propertyID = findProperty(classID, property) 
  if propertyID then 
    entities[entityID][ENTITY_VALUES][propertyID] = val 
  end if 
end procedure 
 
-- call a method (function) within an Entity 
public function callMethod(integer entityID, sequence method, object methodParams= {}) 
  integer classID = entities[entityID][CLASS_ID] 
  integer methodID = findMethod(classID, method) 
  if methodID then 
    return call_func(methodID, {entityID, methodParams}) 
  end if 
  return -1 
end function 
new topic     » topic index » view message » categorize

2. Re: Classless class-oriented programming

Here is an example of usage:

include std/datetime.e 
include std/console.e 
include classes.e 
 
function get_years(atom secs) 
  atom days = floor(secs/86400) 
  return floor(days/365.25) 
end function 
 
function describe(integer entityID, sequence params) 
  atom secs = diff(getProperty(entityID, "birth_date"), now()) 
  printf(1, "\nHello! I speak %s.\n", {getProperty(entityID, "mother_tongue")}) 
  if length(params) then 
    printf(1, "I am %d years old. I was born in %s (%s).\n", {get_years(secs), getProperty(entityID, "birth_place"), params[1]}) 
  else 
    printf(1, "I am %d years old. I was born in %s.\n", {get_years(secs), getProperty(entityID, "birth_place")}) 
  end if 
  return 0 
end function 
 
function sound(integer entityID, sequence params) 
  sequence name = getProperty(entityID, "name") 
  if equal(getProperty(entityID, "energy"), "electricity") then 
    puts(1, name & ": Bzzz\n") 
  else 
    puts(1, name & ": Vroom\n") 
  end if 
  return 0 
end function 
 
procedure main(sequence cmd) 
  object void 
 
  integer TPerson = class("TPerson") 
 
  addProperty(TPerson, "birth_date", now()) 
  addProperty(TPerson, "birth_place", "") 
  addProperty(TPerson, "mother_tongue", "") 
  addMethod(TPerson, "describe", routine_id("describe")) 
 
  integer TVehicle = class("TVehicle") 
 
  addProperty(TVehicle, "name", "") 
  addProperty(TVehicle, "nb_wheels", 0) 
  addProperty(TVehicle, "energy", "") 
  addMethod(TVehicle, "sound", routine_id("sound")) 
 
  integer englishman = classes:new(TPerson) 
  setProperty(englishman, "birth_date", datetime:new(2010, 5, 14)) 
  setProperty(englishman, "birth_place", "Liverpool") 
  setProperty(englishman, "mother_tongue", "english") 
  void = callMethod(englishman, "describe", {"Merseyside"}) 
 
  integer scooter = classes:new(TVehicle) 
  setProperty(scooter, "name", "Scooter") 
  setProperty(scooter, "nb_wheels", 2) 
  setProperty(scooter, "energy", "gazoline") 
 
  integer car = classes:new(TVehicle) 
  setProperty(car, "name", "Car") 
  setProperty(car, "nb_wheels", 4) 
  setProperty(car, "energy", "electricity") 
 
  puts(1, "\n") 
  void = callMethod(scooter, "sound") 
  void = callMethod(car, "sound") 
end procedure  -- main 
 
main(command_line()) 
maybe_any_key() 

He is the resulting code:

 
Hello! I speak english. 
I am 11 years old. I was born in Liverpool (Merseyside). 
 
Scooter: Vroom 
Car: Bzzz 
Press Any Key to continue... 

Compared to the method used with the preprocessor, this one allows to define more than one class per file at the cost of a loss of speed.

Enjoy!

Jean-Marc

new topic     » goto parent     » topic index » view message » categorize

3. Re: Classless class-oriented programming

The relationship between OOP, as a set of principles, and OE has long been an interest of mine.

As it says somewhere in the RDS documentation, Euphoria has (many of) the features of OOP without the formal syntax adopted by OOP language developers. To this end, I have constructed what I think of as a neat, Euphoria-like, approach to OOP. It can be found at https://github.com/CANewbould/OE4OOP. I have also included a very primitive dot-notation pre-processor, if only to allow code to copy the "standard" OOP layout.

I should appreciate your reaction.

new topic     » goto parent     » topic index » view message » categorize

4. Re: Classless class-oriented programming

I tested your library before I updated my own one (Simple OOP library, 2011).

I don't know why, but I can't get into the concept. Maybe I'm too old for that (I'm 61).

I found my own previous library too ccomplex either.

regards

Jean-Marc

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu