GNU/EDMA Tutorial. Objects and Classes
 
PROGRAMMING
GNU/EDMA Tutorial. Objects and Classes
2021-06-19 | by David "DeMO" Martínez Oliveira

GNU/EDMA is library that implements several object oriented features in plain C. Its last version was 0.18.6 and there is a new 0.19.1 which fixes some bugs and is more functional. Version 0.18.6 added some functions that have not been documented elsewhere so I have decided to write a tutorial in case someone wants to use the system

Before going into the details of this first tutorial let me share a few words about GNU/EDMA. GNU/EDMA was the result of my Master Thesis many years ago. At that time (in the 90s) I decided that I wanted to release it as free software, so I wrote to the FSF to ask how to do it. At that time it was a bit confusing, specially for somebody without any legal background.

Meeting Free Software

I was very surprised when Mr Stallman answered my mail in person. We interchanged various mails and I have to say that I learnt a lot about the Free SW philosophy... something that has stayed with me since then. I will never be grateful enough for all the knowledge I've got those days.

Anyhow, at some point, Mr Stallman asked if I want EDMA to be part of the GNU project and I agree. Since then (that was sometime back in 1998) I was the maintainer for EDMA and I started naming it GNU/EDMA. I kept working on the system as I was planing to use it for my thesis, but eventually I had less and less time and at some point I was not able to work any more on it.

The advent of 64bits

In parallel, 64bits processors become popular and eventually all SW moved into 64bits and, as you may know if you read this blog, the GNU/EDMA implementation didn't worked with 64bits platforms. I learnt that the bad way when a colleague from La Coruña University was trying to use GNU/EDMA in his project and we found that the issue was that he was working on 64 bits architecture.

I still could force 32bits compilation and build the system and I did some more work to get rid of some bad decisions done in the early days, but around 2013, I released 0.18.6 and then I didn't have much time to work on EDMA anymore. I gave up on my PhD and have a lot of work in my current position plus additional personal issues.

And we get to 2021

So early this year (2021 in case you read this in the future :), somebody from GNU contacted me and asked to update the project. I reply that I have that issue with the 64bits platform and I haven't worked at all in the project in the last years so it will not make sense to be the maintainer anymore.

Actually, as nobody has expressed any interest on the project for years I was suggesting to cancel the project instead of looking for a new maintainer, especially taking into account that some of the concepts in GNU/EDMA are no longer any novel.

Fixing the 64bits

That was January/February. In June, for whatever reason I decided to give it a try to an idea I have had years ago to fix the issue with the 64bits. You can read about this here. I won't extend more on this.

However, will fixing this I saw a few other minor things that I could fix, and I started remembering some of the ideas from those young days and they sounded cool again :).... So I got some interest on the project.

Right now

So, this is the history up to right this moment on time. June 2021. I will write this series of tutorial just for completness and, while writing them I will fix some minor issues/bugs that are still around, and may further explore some of the ideas that I never fully developed.

In any case, at this point, GNU/EDMA is an unmaintainer package but is not cancelled so I cannot officially offer patches to the project. I have already fixed a few things and I will made them available to anybody reading this and, of course, in case a new maintainer is found for the project s/he will be welcomed to take any code that believe should fit his/her view.

Said that, let's get started with GNU/EDMA, installing the system and creating a simple Hello World! program.

While writing this tutorial I patched a few minor bugs. If you are planning to follow along the tutorial you can download the latest patched version from here.

Installing GNU/EDMA

GNU/EDMA is distributed as source code under a LGPLv3 license for the core and stock classes (to allow any other application to use it) and with a GPLv3 license for the tools that come with the framework... yes, let's call it framework as it is a cool word nowadays :).

So, you just need to uncompress the package, confugure it and install. My recomendation is to deploy it in a private folder instead of in the system folders. You know, configure sets everything up to install in /usr/local. I usually deploy GNU/EDMA at /opt/edma_dev. For that, first create the folder (you will need sudo) and then change ownership to your default user so you can run install and also deploy classes without sudoing all the time. If at the end you find the system useful and want to deploy it permanently, then sure, adjust permissions accordingly.

Summing up:

$ tar xzvf gnuedma-0.19.1.tar.gz
$ cd gnuedma-0.19.1.tar.gz
$ ./configure --prefix=/opt/edma_dev --enable-debug
$ make -j 8 # Or whatever number of cores you can use
$ make install

Note: If you are going to follow this tutorial, you better download gnuedma-0.19.2.tar.gz from here.

This should install the GNU/EDMA core in /opt/edma_dev, including the basic tools, the default shared classes and also the examples repository.

To check that everything has worked you can do:

$ source /opt/edma_dev/bin/edma-env.sh
$ edma-config --version
GNU EDMA 0.19.1

So far so good... Let's write our first GNU/EDMA application.

Hello World!!!

Indeed that will be the first application you will write. But we have to do it the GNU/EDMA way, otherwise this test will be useless. Fortunately (well, not fortunately, I have done that on purpose), there is a stock class named HELLO_WORLD. This class implements a method that just prints the Hello World!! message in the console and also the values of its two properties.. We will get back to this in a second. This is the code of the basic GNU/EDMA Hello World program:

#include <edma.h>

int main () {
  EDMAInit();
  
  OBJID id = edma_new_obj ("HELLO_WORLD");
  edma_met3 (id, "say");
  edma_free_obj (id);
  
  EDMAEnd();
}

Even if you do not know anything about GNU/EDMA you will likely understand what the program does. I will explain it line by line any way:

The first function call (EDMAInit) initialises GNU/EDMA. This function reads default class repositories and sets the system up, allocating any internal structure and initialising them. Any EDMAInit function has to be paired with an EDMAEnd() that basically frees all resources.

With the last version of GNU/EDMA and the introduction of Sally the Allocator calling EDMAEnd is not that important anymore. In the early versions of the system, shared classes were stored in shared memory and when the application crashed or ended without calling EDMAEnd the reference count of the shared memory went wrong and then things didn't worked as expected. The initial version of EDMA had a tool to manually delete all shared memory blocks using the ipcs tool.

Creating Objects

The rest of the program creates and object, calls a method and then, destroys the object.

Objects are created calling edma_new_obj. The class of the object you want to create is just a string and the function returns an object handler of type OBJID, that is actually just an integer.

A GNU/EDMA object is composed of different parts, depending on the class it belongs to. In this case, we are creating an object of a single class (no inheritance) with no virtual methods, so the object just contains some flags and a memory block to store the class properties (or instance variables if you want).

Let's see in a second how is all this defined. For now, edma_new_obj allows us to create an instance of any class known by the system. The same way edma_free_obj destroys the object freeing all resources allocated for it.

Finally edma_met3 is the way we have to invoke methods in an object. In this case we are executing method say on an instance of class HELLO_WORLD. say is a method that doesn't take parameters, otherwise we will just add the parameters after the method name.

Nothing really exciting here, except that classes and methods are specified using strings.... this gives the system its dynamic properties as we will see later but, as usually happens in these cases the price is that the typing system is weak, which has been one of the criticisms of the system I have got a couple of times... If you like, in this sense GNU/EDMA is a bit like JavaScript, were you can do almost anything with classes and object at run-time.

The HELLO_WORLD Class

So, I said that the HELLO_WORLD class is a stock class that is available for any GNU/EDMA application, so where does it comes from. The stock classes are defined in the shared class repository and that repository is specified in /opt/edma_dev/etc... supposing you installed GNU/EDMA at /opt/edma_dev. If you look to that file you will see something like this:

[General]
nClasses=25
....
[CLASS23]
ClassName=HELLO_WORLD
NameSpace=examples/hello
Machine=i386
OperatingSystem=LINUX
Implementation=libHELLO_WORLD
IDFParser=EDMAIDF
MajorVer=0
MinorVer=0

The repository stores the information needed by the system to access the class and create it so we can instanciate.

HELLO_WORLD is a class defined in the system repository, so the interface and the implementation are also in the associated system folder. The implementation (you can see above it is libHELLO_WORLD) are shared libraries stored at /opt/edma_dev/lib/edma/NAMESPACE and for this example the NameSpace is examples/hello.

Now you can go to /opt/edma_dev/lib/edma/examples/hello and you will find a shared library that actually contains the code for the methods defined by the class.

The class interface is located in /opt/edma_dev/share/REPO_NAME and the shared repository name is edma. There you will find an idf folder (idf stand for interface definition file), and inside that folder you will find multiple files named CLASS_NAME.idf. Let's take a look to the HELLO_WORLD.idf file.

[General]
Name=HELLO_WORLD
[SYS_DEF]
ModuleName=libHELLO_WORLD.so
[Definition]
PropertiesNum=2
MethodsNum=3
[Prop0]
Name=num
Type=EUINT32
Access=READ/WRITE
ArrayElems=
[Prop1]
Name=str
Type=EZSTRING
Access=READ/WRITE
ArrayElems=
[Met0]
Name=born
Signature=
Virtual=0
[Met1]
Name=rip
Signature=
Virtual=0
[Met2]
Name=say
Signature=
Virtual=0
[]

Yes, this format sucks, it is actually a windows .ini file, because the initial version of EDMA was coded for windows and the system already provided functions to read these files so, parsing was for free.... We will see later how to use different formats for our interfaces. The good thing about this format is that it is pretty obvious.

If you take a look to the file above will quickly figure out what it does. The first part defines properties (those are instance variables in our objects) and the second defines methods.

In this case we have two properties. One named num that is an integer and another one named str that is a string.

The class also defined three methods, all without accepting parameters or returning anything (the Signature fields are empty). The born and rip methods are the constructor and destructor for the object. When the object is created via edma_new_obj once all the data structures are setup, GNU/EDMA will invoke the born method on the object before returning the control to the main program. The same way, the rip method is executed just before destroying an object with edma_free_obj.

The method say, is the one we where using. It is a just a regular method.

The HELLO_WORLD implementation

Just to close the cycle, let me show you how does the HELLO_WORLD implementation looks like. You can find this in the source code of GNU/EDMA.

Class implementation for system stock classes are physically stored in shared library. Overall, a GNU/EDMA class is a kind of component with OOP capabilities... actually that was the original intention.

Let's chop the implementation is small pieces to make them easier to shallow.

#include <stdio.h>
#include <string.h>

#include <edma.h>

typedef struct
  {
     EUint32            num;
     EPChar             str;
   }DtHELLO_WORLD;
   

As any C program, it starts with the required includes. As a GNU/EDMA class, the edma.h is required to get all the system definition.

Then we found a structure that actually matches the properties defined for the class. Do you remember the interface file defining two properties?. Right. So this is a C structure that will allow us to access those properties in a more efficient way, from inside the class. Otherwise we would have to use the edma_wprop3 and edma_rprop3 to write and read properties respectively....

We will see how to use this structure in a sec. Let's see how the constructor looks like.

   
ESint32 EDMAPROC
HELLO_WORLDborn (OBJID IdObj)
{
  DtHELLO_WORLD *m;

  m=(DtHELLO_WORLD*)edma_get_data_ref(IdObj);

  edma_printf_obj(IdObj,"  [Constructor]");
  return 0;
}

The constructor (named born in GNU/EDMA) is a regular method that doesn't accept parameters (I have just noticed that this part is not completely implemented). The first thing we notice is that the method name is a bit longer, it is prefixed with the class name. This is a way to avoid name clashing when loading multiple classes that likely will have methods with the same name. Actually, the name is postfixed with the signature, but in this case there is no signature for the method, because it doesn't accept parameters.

Then we see that the method declares a pointer to the data structure defined at the beginning, that is actually the data block associated to a HELLO_WORLD object as per the interface definition.

The edma_get_data_ref function actually returns the pointer to the data block of the object passed as first parameter. This way we can access the properties of the object like:

m->num = 123;
// Instead of
edma_wprop3 (IdObj, "num", 123);

We can always use edma_wprop3 but, specially in the class implementation file, that will introduce a big overhead just to access the same thing.

Finally, we have the destructor named rip (that does the same thing than the constructor... just prints a message), and the say method.


ESint32 EDMAPROC
HELLO_WORLDrip (OBJID IdObj)
{
  DtHELLO_WORLD *m;

  m=(DtHELLO_WORLD*)edma_get_data_ref(IdObj);

  edma_printf_obj(IdObj,"  [Destructor]");
  return 0;
}
ESint32 EDMAPROC
HELLO_WORLDsay (OBJID IdObj)
{
  DtHELLO_WORLD *m;

  m=(DtHELLO_WORLD*)edma_get_data_ref(IdObj);

  edma_printf_obj(IdObj,"  [say] -------------------------------");
  edma_printf_obj(IdObj,"  [say] Hello world!!!!");
  edma_printf_obj(IdObj,"  [say] Property num : %d",m->num);
  edma_printf_obj(IdObj,"  [say] Property str : %s",m->str);
  edma_printf_obj(IdObj,"  [say] -------------------------------");

  return 0;
}

The say method, just shows the hello world message and then it prints its instance variables. The edma_printf_obj function, is a printf-like function that prepends the class of the object passed as first parameter to the string to be printed, so we can identify which object the message belongs to.

Compiling and running

After this journey through a basic system stock class we can now compile and run our test program. Do you remember?.... Doesn't matter I will show it again here:

#include <edma.h>

int main () {
  EDMAInit();

  OBJID id = edma_new_obj ("HELLO_WORLD");
  edma_met3 (id, "say");
  edma_free_obj (id);
  
  EDMAEnd();
}

To compile the program, GNU/EDMA comes with a script to create the compilation/linking flags required for building classes and applications. When it was created, pkgconfig didn't exist (or was not standard yet, cannot remember), so I create my own.

To compile our program we just:

$ gcc -o helloworld helloworld.c `edma-config --cflags-exe --libs-exe`

And now we can just run it:

$ ./helloworld
Trying to connect to EDMA Shared Allocator Agent ... CONNECTED
++ Using Sally Shared Allocator

GNU/EDMA 0.19.1 build [Jun 14 2021][Dev][0.19.1] starting up...
EDMA Startup process... OK
(HELLO_WORLD)  [Constructor]
(HELLO_WORLD)  [say] -------------------------------
(HELLO_WORLD)  [say] Hello world!!!!
(HELLO_WORLD)  [say] Property num : 0
(HELLO_WORLD)  [say] Property str : (null)
(HELLO_WORLD)  [say] -------------------------------
(HELLO_WORLD)  [Destructor]
-------------------[EDMAEnd]--------------------------------
No more process in GNU EDMA. Freeing All Resources...
Cleanup done!!

We see a few initialisation messages at the beginning about the shared allocation system and the version of GNU/EDMA, then we just see the output that we were expecting. At this point all the object properties are just set to 0.

Modifying properties

Let's change the program to show how to access the object's properties. We have already briefly mentioned that, but just to show you a real example:

#include <edma.h>

int main () {
  EDMAInit();
  
  OBJID id = edma_new_obj ("HELLO_WORLD");
  edma_wprop3 (id, "num", 123);
  edma_wprop3 (id, "str", "Bye, bye world!");
  edma_met3 (id, "say");
  edma_free_obj (id);
  
  EDMAEnd();
}

Now we can compile and run it:

$ gcc -o helloworld1 helloworld1.c `edma-config --cflags-exe --libs-exe`
$ ./helloworld1
Trying to connect to EDMA Shared Allocator Agent ... CONNECTED
++ Using Sally Shared Allocator

GNU/EDMA 0.19.1 build [Jun 14 2021][Dev][0.19.1] starting up...
EDMA Startup process... OK
(HELLO_WORLD)  [Constructor]
(HELLO_WORLD)  [say] -------------------------------
(HELLO_WORLD)  [say] Hello world!!!!
(HELLO_WORLD)  [say] Property num : 123
(HELLO_WORLD)  [say] Property str : Bye, bye world!
(HELLO_WORLD)  [say] -------------------------------
(HELLO_WORLD)  [Destructor]
-------------------[EDMAEnd]--------------------------------
No more process in GNU EDMA. Freeing All Resources...
Cleanup done!!

Pretty straight forward isn't it?

Local Classes

Shared stock classes are system-wide accessible. They are actually stored in shared memory so any change to them will be immediately seen by all applications using them. This can happen at run-time when hotswaping classes. We will talk about these functions later in this series.

However, most application need specific code that doesn't make sense to get accessible system-wide. For those cases, GNU/EDMA provides two options.

  • Define a local repository. A local repository, looks like the system repository we explored earlier in this post, but it is only accessible for the applications using it. Many applications can use the same repository, but each one will have a private copy. This is useful when you want to have a set of components that you will be reusing on different applications.
  • Define a local class. In this case, the class will be defined inside the application, pretty much like C++ or Java does (to mention two OOP languages), and it will only exist for that application at run-time.

Local classes even when conceptually are similar to C++ or Java classes, they are still defined dynamically. So any mistake you make using them cannot be detected at compile-time, that is part of the weak typing thingy. Overall, everything on GNU/EDMA can be done at run-time and in this specific case this feature allows to implement metaclasses (classes whose instances are other classes).

GNU/EDMA provides two APIs sets to define local classes. The so-called LEA functions and the IDF functions. Actually, LEA functions are just wrappers around IDF functions to create common classes easily. Let's add a class to our program using both techniques just for documentation processes.

LEA API

Let's create a local class named BYE_WORLD that does the same than HELLO_WORLD but printing the message Bye, bye World! instead.

#include <lea.h>

typedef struct byeworld_t {
  ESint32 num;
  EPChar  str;
} BYEWORLD;

ESint32 EDMAPROC
bye_world_say (OBJID id) {
  EDMA_THAT(BYEWORLD*, id);
  
  edma_printf_obj (id, "%s", "------------------------");
  edma_printf_obj (id, "%s", "[say] Bye, bye World!");
  edma_printf_obj (id, "[say] Property num : %d", that->num);
  edma_printf_obj (id, "[say] Property str : %s", that->str);
  edma_printf_obj (id, "%s", "------------------------");
  
  return 0;
}

int main () {
  CLASSID  cid;

  EDMAInit();

  cid = lea_create_class ("BYE_WORLD");
  lea_add_property (cid, "num", DT_ESINT32);
  lea_add_property (cid, "str", DT_EZSTRING);
  lea_add_method (cid, "say", "", (PPROC) bye_world_say);
  lea_finish_class (cid);
  
  OBJID id = edma_new_obj ("BYE_WORLD");
  edma_wprop3 (id, "num", 123);
  edma_wprop3 (id, "str", "Hello world!");
  edma_met3 (id, "say");
  edma_free_obj (id);
  
  EDMAEnd();
}

Now we can compile and run :

$ gcc -o helloworld2 helloworld2.c `edma-config --cflags-exe --libs-exe`
$ ./helloworld2
Trying to connect to EDMA Shared Allocator Agent ... CONNECTED
++ Using Sally Shared Allocator

GNU/EDMA 0.19.1 build [Jun 14 2021][Dev][0.19.1] starting up...
EDMA Startup process... OK
(BYE_WORLD)------------------------
(BYE_WORLD)[say] Bye, bye World!
(BYE_WORLD)[say] Property num : 123
(BYE_WORLD)[say] Property str : Hello world!
(BYE_WORLD)------------------------
-------------------[EDMAEnd]--------------------------------
No more process in GNU EDMA. Freeing All Resources...
Cleanup done!!

Sure, we haven't implemented the constructor and destructor to keep the example short... But you should be able to implement them by yourself when you finish reading the code explanation.

BYE BYE WORLD

Let's dissect the code in small pieces:

#include <lea.h>

typedef struct byeworld_t {
  ESint32 num;
  EPChar  str;
} BYEWORLD;

When I implemented the LEA functions I started considering splitting the API in different include files. This was the first one, so if you do not need the LEA functions you just include edma.h but if you need them, include lea.h that will also include edma.h for you.

Then we find the same data structure we have seen for the HELLO_WORLD stock class. Nothing special so far. Let's jump now to the main program where the class is defined:

int main () {
  CLASSID  cid;

  EDMAInit();

  cid = lea_create_class ("BYE_WORLD");
  lea_add_property (cid, "num", DT_ESINT32);
  lea_add_property (cid, "str", DT_EZSTRING);
  lea_add_method (cid, "say", "", (PPROC) bye_world_say);
  lea_finish_class (cid);
  
  OBJID id = edma_new_obj ("BYE_WORLD");
  // everything is the same than before from this point

The first thing we see is the type CLASSID. This type represent a Class Identifier and it is the way GNU/EDMA identifies classes. Then we find the class definition.

First we need to tell the system the name of the class we want to create. In this case it is BYE_WORLD. After that we can start adding properties and methods to the class using the functions lea_add_property and lea_add_method.

The properties types can be found on edma.h. But I will list them here for your convenience:

DT_EUINT8      : Unsigned integer 8 bits
DT_EUINT16     : Unsigned integer 16 bits
DT_EUINT32     : Unsigned integer 32 bits
DT_ESINT8      : Signed integer 8 bits
DT_ESINT16     : Signed integer 16 bits
DT_ESINT32     : Signed integer 32 bits
DT_EBYTE       : Byte (8 bits)
DT_EWORD       : Word (16 bits)
DT_EDWORD      : Double Word (32 bits)
DT_ECHAR       : Char
DT_EBOOL       : Boolean
DT_EREAL64     : Double
DT_EZSTRING    : Zero terminated string
DT_EBUFFER     : EDMA_BUFFER (this is a generic buffer)
DT_EOBJECT     : EDMA Object
DT_EUSER       : User defined type
DT_EPOINTER    : Pointer

Signatures are strings containing the following substrings:

U8      : Unsigned integer 8 bits
U16     : Unsigned integer 16 bits
U32     : Unsigned integer 32 bits
S8      : Signed integer 8 bits
S16     : Signed integer 16 bits
S32     : Signed integer 32 bits
R64     : Double
Z       : Zero terminated string
X       : Expandable object... It is substituted by the 
          class of the object passed as parameter
O       : EDMA Object
A       : EDMA Buffer
LClass; : Expects a parameter of type Class
P       : Pointer

Signature values in the table above accepts two modifiers.

r   : The type that follows is the method return type
s   : This parameters is an output parameter (passed as pointer)

I will just add a few examples here to illustrate this:

ZrS32           : ESint32 met (EZString par1)
S32S32sS32      : ESint32 met (ESint32 p1, ESint32 p2, ESint32 *p3)
LHELLO_WORLD;rO : OBJID   met (OBJID id)

In the last example EDMA will determine the class of the object passed as parameter and use that to find the appropriated method. We will look into the details of this later when we talk about polymorphism and dynamic dispatching.

Method definition and THAT

The last piece of the class definition is the method implementation. GNU/EDMA methods are implemented as regular C functions. Let's take a look to the method defined in our test class:

ESint32 EDMAPROC
bye_world_say (OBJID id) {
  EDMA_THAT(BYEWORLD*, id);
  
  edma_printf_obj (id, "%s", "------------------------");
  edma_printf_obj (id, "%s", "[say] Bye, bye World!");
  edma_printf_obj (id, "[say] Property num : %d", that->num);
  edma_printf_obj (id, "[say] Property str : %s", that->str);
  edma_printf_obj (id, "%s", "------------------------");
  
  return 0;
}

The return type is ESint32. This is for convention, when no return type is indicated in the signature, the system assumes that it will return an integer. The same that happens in C.

The EDMAPROC modifier is a constant intended to add functions modifiers if needed. They were used in the earlier versions of GNU/EDMA but nowadays they actually are empty.

Then we find the method name and the parameters. As this is a local class, we can use any name for the method that we want... In case of a clash, the compiler will let us know. Note that this is different for classes defined in its own shared library. The first parameter for each GNU/EDMA method is always an OBJID... expect for static methods... but let's keep it simple for now.

This is the same than in most programming languages. We need to tell the system which object will receive the message. Most OOP programming languages provides some syntactic sugar, usually in the form of:

  theObject->theMethod (theParameter1, theParameter2);

On GNU/EDMA, we just put the object as first parameter....

  theMethod (theObject, theParameter1, theParameter2);

There is a way to enable this kind of syntax but it doesn't allow us to access all the GNU/EDMA capabilities so we will not discuss it for now. It is just an optimisation for simple cases.

Most OOP languages passes the target object to the function as a hidden parameter, usually named this or self. To mimic this behaviour GNU/EDMA provides a simple macro to define a variable named that to access the object properties.

#define EDMA_THAT(type,id) type that = (type) edma_get_data_ref (id)

As you can see, the EDMA_THAT(BYTEWORLD*,id) in our class will expand to:

BYTEWORLD *that = (BYTEWORLD*) edma_get_data_ref (id)

We have seen this construction in the HELLO_WORLD class to access the object properties directly. This macro just do that in one shot and gives a default name to the pointer.

Creating the class using the IDF functions

The main difference between the IDF functions and the LEA functions is its verbosity. IDF allows us more fine tuning of the different class elements as we will see in a second, but most of the time we do not need that.... that is why we have the LEA functions.

This is the code to create the BYE_WORLD class from last section using IDF functions:

  cid = edma_idf_get_free_class_id (EDMA_LOCAL_CLASS);
  edma_idf_set_class_name (cid, "BYE_WORLD");
  edma_idf_set_class_namespace (cid, "LOCAL");
  edma_idf_set_class_version (cid, 0, 0);
  edma_idf_set_class_attribs (cid, 0, 0, 0);

  edma_add_local_class_property (cid, "num", DT_ESINT32, E_L, 0);
  edma_add_local_class_property (cid, "str", DT_EZSTRING, E_L, 0);
  edma_add_local_class_method (cid, "say", "", (PPROC) bye_world_say, 1, 0, 0);

  edma_idf_set_class_id (cid);

As you can see, the sequence is exactly the same... it is just that the functions have more parameters. Let's go function by function so you get to know what all those zeros and ones mean:

  • edma_idf_get_free_class_id. This function just gives as a CLASSID handler for our new class
  • Then edma_idf_class_name/namespace/version are self-explanatory.
  • The edma_idf_set_class_attribs is a bit more cryptic. The three parameters indicates respectively if the class is: SIU Proxy, IDF Parser or EMI Handler.... These are just special types of classes. We will talk about them later in this series
  • The edma_add_local_class_property add two parameters when compared with the lea_add_property. Forth parameter is indicates the property access, it can be READ, WRITE or READ/WRITE (the constants we defined in Spanish L for read -leer- and E for write -escribir-). The last parameter is the number of elements in case the property is an array.
  • The edma_add_local_class_method adds three parameters that actually flags. The meaning of those flags in order are: Is the method virtual?, is the method static? and is the method abstract?

Therefore, this is a more detailed API and some times you really need to use this one, but in most of the cases all these extra parameters are set to zero and that is actually what the LEA functions does.

There are some additional IDF and LEA functions but it doesn't make sense to talk about them until we introduce some other concepts from GNU/EDMA.... We will be revisiting the class creation process as we advance exploring the GNU/EDMA OOP features.

CONCLUSIONS

I think this is enough for now. In this tutorial we have learn how to install GNU/EDMA and how to write a HELLO WORLD program using stock classes and defining our own local class. We have also learn how to create and destroy object as well as access its properties and execute the methods defined by the classes.

I have fixed a few bugs while writing this tutorial and I'm afraid there are some more that I will in the near future. For the time being, you can download the latest patched version from here.
 
Tu publicidad aquí :)