ELENA Programming Language: Programming with ELENA
Alex Rakov, Jul 2009

To start programming with ELENA it is good to understand the basic concepts behind it. This article describes general ideas and features of the language. It is presumed that the reader is familiar with common concepts and terms of object-oriented programming(OOP).

Agreement on terms

Firstly let us define the term "class" as a statement describing the object and the term "object" as an instance of the class located in the memory. Both terms could be used in the text mostly with the same meaning.

Secondly let us define the term "method" as a way how the object reacts to the message sent by others (or itself) to it. "Message" in this case is a named operation (request) which could be accompanied with a parameter (message variable). So then in the text the phrase "send a message" is used it is equivalent of the phrase "call a method by sending the appropriate message". The mapping between methods and messages is defined in the class virtual method table(VMT). If no mapping was found the operation is considered to fail.

General features

Being a pure object-oriented(OO) language with late binding ELENA (like SmallTalk) has no types, interfaces or any other attributes of structural programming. Practically all referring entities in the language are objects. Any variable is in fact a reference to the object allocated in the program heap. The literal and numeric constants are references to the objects located in the data section as well (unlike C# or Java). Moreover any reference to the class name is a reference to the object (in fact it is the normal way how to create objects in ELENA). That is why classes have no special methods called constructor. Due to the garbage collection there are no destructors as well. Unlike many other object-oriented languages ELENA does not support the concepts of special "class" methods and fields (which are in fact equivalent to "normal" functions / variables in none oo-languages). Furthermore the language requires that the message could have only one parameter (for the message without explicit parameter a reference to the special object nil is used).

A class may declare the alternative ways to react to the message (by declaring roles with these particular methods) and switch them (by taking these roles). A class functionality could be extended with a set of external classes (run / design - time mutation).

Finally ELENA introduces the concept of message chains. The code could be considered as a chain of messages where executing of every next message depends on the result of previous one. When one of messages is failed (mostly either the object has no appropriate method or deliberately breaks the execution) the chain considered as broken. It is possible to declare alternative chains which are executed if previous ones are broken. So then the chain is broken the control goes to the closest alternative chain. If no alternative chains is declared the program is finished. (it is roughly similar to the exception handling routine in languages like C++).

Late binding

ELENA is a language with late binding. It means that the actual type of variable (class reference) could be defined only during the program run-time. It makes it harder to find and fix the errors from one side and eliminates all mess with type-casting, multi-inheritance (of interfaces) from other side. So effective programming with ELENA (or in fact with any dynamic OO language) is not possible without taking this feature into account.

The concept of late binding is introduced to achieve the real code polymorphism but it makes the program more complex (by increasing the number of possible object interactions). To minimize this side effect we could use two techniques namely protocols and code patterns.

A protocol (do not confuse it with the concept of interface) is a set of possible actions which could be done with the class which claims to support it. In reality this means that the protocol is a simple list of messages for which we define the expected actions. The class may not support all the messages in the protocol. It may support several protocols or none of them.

Code pattern is a special object implementing particular algorithm with provided parameters (it is similar to C++ template). For example an array enumeration could be implemented as a code pattern where an array and an action for each array item (in ELENA it is object too) are parameters. A code pattern has no knowledge about the parameters except the protocols they should support. Usually they implement well defined algorithms which could be used in combination with each other (e.g. combination of an array enumeration with comparing the values could be used to search a value in the enumerable list or array).

So if we actively use the code patterns and correctly implement the protocols the number of possible object interactions is relative small. Moreover if we limit the number of public messages (in fact the number of interaction between objects belonging to different modules) the system becomes well structured (on the level modules, which we could consider as a black boxes).

Message chains

ELENA is a language with a reduced operational set. Practically the only supported operation is sending a message to the object with a parameter. Conditional (#if) statement extends this operation with possibility to use multi-statement blocks and loop (#loop) one just repeats it until it fails. The only way to control the flow is message chaining.

An ELENA program code is a sequence of actions (sending a message) enclosed in square brackets (Unlike Smalltalk the sub code is a sequence of action as well). The execution of every next action happens only if the previous one was successful. Otherwise the control goes to the closest alternative action and the flow continues. So we have a number of alternative chains of messages all leading to the program end (that is why the language does not support the concept of exception i.e. abnormal termination of the program flow).

Alternative message chains are used in ELENA not only for handling exceptional situation but (and mostly for) conditional branching. The program code could explicitly break the execution (by sending fail message) to indicate the negative result of the method.

Reduced class interfaces

One of the basic idea behind ELENA language is a concept of reduced class interface. It assumes that there is only limited way to interact with the object on the base of protocols supported by it. Any class method should perform an atomic operation, be quite small and support only one parameter. So any "complicated" operation could be broken into several "simple" ones. As a result we will get the relatively big number of "simple" objects where the principle "I know how - you know when" could be used throughout the system.

Moreover the strong concept of reduced class interfaces limits the possible operations between classes (belonging to different modules) to the small list of well-defined messages (verbs) which could be applied to object properties (nouns). For example the class gcomp'Edit supports only variable public protocol (get and set value). To show / hide it we should use common property gprop'Visible (which in fact a separate symbol). So the code for showing the control looks like:

     gcomp'Edit->gprop'Visible << basic'True.
The property symbol contains the code which could be shared (reused) with any other control supporting appropriate protocol. In other words the concept of properties allow to extend the classes with the common code without need to inherit them from the common ancestor. All we need for this is just to implement several basic methods required by the protocol.

The same rule could be applied to any "complicated" operation. In general the "systems with the reduced interfaces" tend to have bigger number of classes with simpler interfaces then the "normal" ones and more actively cooperate with each others to solve any possible task.

Class Mutation: Roles

ELENA language introduces several "brand new" features, one of them is roles (or static mutation). This feature allows classes to have several sets of methods (or several different ways to react to them).

It is desirable that the way how the class reacts to the method depends on its internal state. Though the total number of different object states is big enough we could always select several extreme ones (such as an empty string, unassigned container). Such cases could be implemented as class roles which could contain the code which is applicable only in this situation so no need to check for this extreme state throughout the class code. Only in the place where this state could be changed (copying the literal value, assigning the object) we will check the situation and apply (shift in ELENA term) these roles or return to normal one (shifting to "default" role).

In most cases the bulk of the code would not be affected so there could be only several quite simple roles. But in some situation the whole code is divided between roles. E.g. Boolean variable could have two (or three) roles: true, false values (and undefined one). It is possible to override the roles in the child class (though at the moment you need to override all role methods).

The operation of applying role is quite simple and affect any object reference (because the actual VMT reference is changed; that's why we could speak about the mutation). There is no big code overhead (except an extra VMT) and roles should be actively used instead of extra checking in the code. It is a good practice to recognize the code which has some extreme cases and put it into the appropriate roles (so we will get at the end very small, if no at all, code duplication). The rest of the code should be still implemented in the main body.

Class Mutation: "Any" handlers

Another interesting ELENA feature is the possibility to declare a class extension (or "any" handler). It allows the object to override some messages at run-time (so we could speak about the dynamic mutation).

"Any" handler is a special method which redirects any unhandled message (i.e. messages which are not mapped in the class or its base classes) to the specified target. The target could be a single object (actually mutation) or collection (some sort of multiple inheritance). There are two types of redirecting to the collection: annex and cast modes. In case of annex mode the message is redirected to the first member of the collection which has the appropriate method (extending). For the second type the message is sent to all collection members (broadcasting).

There are number of places where the "any" handler concept could be applicable starting from code sharing (horizontal multi-inheritance) to the dynamic object mutation. It does not create a big code overhead and is actively used throughout ELENA library code and samples. For example it could be used to create a container class which in most cases is invisible (messages are redirected to the content) but still allows to change its content (via private messages so no name conflict is possible). So it could be passed to the code expecting the content without any modification which could be an advantage if it in turn passes the parameter to the third part code (e.g. if we wish to extend the communication line between two parts of the system without rewriting the layer between them) and so on.

Conclusion

Summing all above it is clear that programming in ELENA is quite challenging and requires some new patterns comparing with "traditional" languages. The most restricted feature of limited object interface means that we cannot always call desired method of the class belonging to the different namespace scope (in the simplest case to the different module). Let's assume we design the computer card game. We have three classes: engine'Master, players'Human and game'Rulebook. engine'Master cannot simply call the players'Human method to notify on the given card. game'Rulebook cannot directly call engine'Master to notify on the new round and so on.

To resolve these limitations we could use one of the several behavior patterns. The class cannot call the other one private method but is able to reacts on it - so called "one way interaction" (such cases should be well defined and limited). So players'Human class could declares the appropriate method handlers to get the information from outside its scope. If the classes (like game'Rulebook and engine'Master) requires two-way interactions they could use well-defined common properties. For example game'Rulebook could support game'Rounds property which returns the collection of game rounds used by engine'Master to play the game. The property have public interface and could be used from any module.

Another restriction prevents the method to have more then one parameter. As a result the method parameter tends to become an active partner. The method has to ask the parameter to return the required information, so the method caller has some control of the method work (in combination with dynamic mutation we could have real two-way interaction).

In general due to the interface limitation ELENA tends to avoid the complicated method logic (so called "spaghetti" code). It is actively reused (due to property code). The number of inter-module references is limited. It avoids excessive inheritance with the help of class extension / dynamic mutations. The number of objects is quite big and most of them actively interact with each other (the number of inter-class calls are much higher then inner-class ones). Due to its dynamic nature the code is polymorphic and could be modified in run-time.

P.S.

ELENA is not only the experimental but actively developing language. So it may happen that a part of the article could be obsolete and modified time to time to reflect the current changes. If you become interested in the language please visit this page to see the current language concept.


Copyright (c) Alex Rakov, 2006-2009

ELENA Home
SourceForge.net Logo