1. Classless class-oriented programming
- Posted by jmduro Oct 24, 2021
- 1103 views
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
2. Re: Classless class-oriented programming
- Posted by jmduro Oct 24, 2021
- 1095 views
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
3. Re: Classless class-oriented programming
- Posted by dr_can Oct 31, 2021
- 981 views
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.
4. Re: Classless class-oriented programming
- Posted by jmduro Nov 01, 2021
- 928 views
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