Sunday, July 25, 2010

Group Objects Example

Let's consider the use of group objects.

In the next example I will demonstrate how to extend and customize code using branch-free self modifying code.
(Note that 'project' should be replaced with a name of the source file)

// --- namespace shortcuts ---
#define basic'* = std'basic'*.
#define ctrl'* = std'patterns'*.
#define list'* = std'collections'*.

#symbol Printing = anItem =>
[
// prints a parameter
'program'output << eshownext =" anItem">
[
// replace itself with ESkipNext
#inline elena'172 (self, $self, project'ESkipNext).
].

#symbol ESkipNext = anItem =>
[
// redirects the call to the next group item
$next proceed:anItem.

// replace itself with EShowNext
#inline elena'172 (self, $self, EShowNext).
].

#symbol Program =>
[
#var aList := list'List.
aList += 1 += 2 += 3 += 4 += 5 += 6.

// extending
'program'output << "All items:%n".
#group(ctrl'EEnum, aList) run:Printing.

// customizing
'program'output << "Every second item (1,3,...):%n".
#group(ctrl'EEnum, aList) run:#group(ESkipNext, Printing).

'program'output << "Every second item (2,4,...):%n".
#group(ctrl'EEnum, aList) run:#group(EShowNext, Printing).
].

The program start in Program symbol. Firstly we have to create a collection.

#var aList := list'List.
aList += 1 += 2 += 3 += 4.

In the code below we will enumerate every member of the collection and print it.

// extending
'program'output << "All items:%n".
#group(ctrl'EEnum, aList) run:Printing.

aList is extended with ctrl'EEnum adapter. EEnum is a FOR EACH pattern, executing the action for every member of the collection it is combined with. Printing is a simple action which prints a provided parameter. In combination this code prints every member of the collection.

Let's consider how could we customize it to print only every second item without if statement.

// customizing
'program'output << "Every second item (1,3,...):%n".
#group(ctrl'EEnum, aList) run:#group(ESkipNext, Printing).

Printing action is combined with a special adapter ESkipNext. ESkipNect redirects the flow to the next group item and modify the group by replacing itself with EShowNext. So during the next call EShowNext will be executed. EShowNext in its turn replaces itself with ESkipNext and so on. As a result we will print every second item of the collection. A voila.

To be continued...

Thursday, July 22, 2010

Group Objects

Let us define a group object as a collection of the objects accessible through the common instance reference. The member objects may or may not have any relations with each other. They may or may not have intersecting message mapping. The content of the group can be changed dynamically during the object life time (self-modification). The member objects can be a part of different groups or be single. They may not even notice they become a part of the group (dynamic overriding). The group can be persistent or temporally created to solve the particular task. In general the group objects are treated like "normal" ones and no special routines are required to work with them. If two or more members have duplicate methods either the first message mapping is resolved (exclusive mode) or all duplicate methods are executed (broadcast mode) depending on the group type.
So how may group objects be used? Let us consider several possible use cases: code customization, "branching-free" / self-modifying algorithms and horizontal inheritance.

Customizing / Extending existing code


The concept of the group object may be used for modifying the existing code. Sometimes only minor changes should be applied to the code to be reused. Commonly we may override the class. Or we could combine it with the special adapter class containing only the methods we would like to change (actually dynamically override it, see horizontal inheritance). Though this two patterns are quite equivalent, the group can be formed with any object implementing a particular protocol at a run time. And in contrast to an aggregation we have to implement only the methods we would like to change without affecting others (which is quite important for the dynamic language where we do not always know the object type). Moreover in some cases we will not need to write a new code at all, only combining well-defined components. In general it allows us to inject the code into the complex system without big modifications and this injection may be invisible for other parts of it.

"Branching-free" algorithms


The content of the object group may be changed during its life time and it gives us quite an interesting feature: every time the group internal state is changed its actual content may be changed as well. Though the total number of the different states is quite big we can always select several extreme ones (empty list, unassigned reference, read-only collection and so on), place the code related to them into a separate control object (or several ones) and combine it with the main code. So when the group state is changed the control object replaces itself with the appropriate one instead of checking the state every time (alternatively the control object may have a several set of VMTs). Self modifying group can be used as well in many cycle algorithms where the first or the last action are different from the main ones. The real "branch free" code is unlikely to be feasible but the moderate usage can still simplify the code.

Horizontal inheritance


Group object can be used as an alternative to a multiple inheritance as well. Common satellite classes can be included in different groups allowing them to share the code without actually inheriting it, helping us to reduce the depth of inheritance tree.

Having looked at several use cases let us examine the possible implementation of the group object concept.

Possible implementation


Being born as a part of the dynamic language study the group object definitely requires a pure polymorphic language with a late binding. For implementation simplicity the concept of limited object interface was introduced. We presume that any class method may have only one input and one output parameters. If the method does not require any parameter a special void parameter is passed (e.g. nil constant). If the method does not require to return anything it returns itself (e.g. self variable). As a result we have a system with relatively big number of "simple" classes actively interacting with each other to resolve any task (so we can say that the number of inter-class calls tends to be higher than the number of inner-class ones). Finally let us introduce a proxy handler concept. The proxy handler is a special kind of a method which is executed every time there is no message mapping in the class VMT. It may redirect the call to the specific target.
Summering all above any group object consists of the array of group members and a VMT containing only a special proxy handler. Depending on the type of the group it redirects the call to the first object handling the appropriate message (exclusive mode) or to all members (broadcast mode). Every time a member method is called the reference to the group is passed to it rather than to the object itself. So when the method calls another object method it is in fact redirected to the group (dynamic overriding).
The only problem with this approach (except performance of course) is an access to the object fields. To solve it we need to keep the reference to the object as well. In a standalone mode both variables refer to the object. In fact having two object references allows the programmer to decide whether the method call might be overridden or not.

Name conflicts


But how predictable could such groups be? After all we combine the objects which are not always well known to us. Will there be any message conflict leading to unexpected results? To ease this problem we may introduce the concept of the message namespace. The words in a human language are quite ambiguous and as a result the message names may be ambiguous too. "AND" could be bitwise or Boolean operation, "GET" may return any value and so on. So let us introduce a special language entity of a message scope which describes well-defined term (e.g. "integer", "boolean") and list possible operations with it (e.g. "get", "and" ,...). Any message used by the group member should belong to one or another message scope (which has to exist physically). As a result the chance that the different members of the group will use occasionally similar messages is quite small.

Critical review


Though the scheme above seem a bit complex it costs not so much: an extra check per message call and an additional object variable (if we compare it with the cost of transition from a static call to a dynamic one). But in any case we are facing a bigger concern - redundancy. It is easy to show that most of the possible features could be implemented without groups (after all any high level programming language is translated to the machine codes and by definition cannot be more powerful than the assembler).

So is the introduction of the new entity really justified? And though there is no simple answer to this question several reasons can be mentioned. First of all it promotes more polymorphic and extendable code. The possibility to customize the object behavior without actually knowing much about it (except supporting protocols) will give a programmer more flexible way to deal with existing / reusable code. Secondly this approach reshapes the system structure. Instead of multifunctional classes we will get plenty of rather simple ones with limited functionality which can be easily tested and reused. And finally combining them into super entities makes the system more open and configurable.
To summarize this type of redundancy may be a key factor how to build and maintain more powerful and complex systems with an open architecture. And though it is too early to say if the concept of the group object makes the difference it can give a boost to active use of more structural self-modifying collaborative code.

Wednesday, July 21, 2010

General language overview

In the next several posts I will try to describe the language general overview, proposed programming paradigm and basic code patterns. So let's begin.

ELENA is an object-oriented programming language with the late binding. It means that it belongs to the same class as Smalltalk rather than C# or Java. It is a non-mainstream language and is used as a testbed for experiments with the language design, dynamic and self-modifying code and so on. So don't expect it will be easy to learn. Probably someone may say it is weird but I like its dynamic nature. It has weak sides but it DOES work. And finally it is a live language in the process of developing.

Let's consider several major language features which I will discuss in more details later.

ELENA is a language with the reduced class interfaces. 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. 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 (though it is possible to provide "subject" for each verb, i.e. with "get" verb we can use several distinct messages: int'get or game'player'get). The method cannot have more than 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 some kind of two-way interaction).

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. 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.

ELENA is a dynamic language supporting different run-time code manipulations. One of them is a static mutation. It is presumed that an object may have several alternative sets of VMTs (roles) and switch between them depending on its state. Though the total number of these states can be big enough we could always select several extreme ones (such as an empty string, unassigned container). Such cases could be implemented as class roles containing the code which is applicable only in the particular state. Only in the place where it could be changed (copying the value, assigning the object) we will check the situation and switch between roles. 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).

ELENA supports a dynamic mutation as well. It means that we can dynamically override any public object method. This mutation could be either stable or temporal (if it is included into the temporal object group) and be accessible both inside and outside the mutated object (though inside the object we can explicitly decide if we allow overriding). It is possible either extends the object with some custom code or combine it with the number of other objects (so called object satellites) into a group object (will be described in the next post).

Concept of the group objects is one of the most interesting ELENA feature and I will continue to investigate it hoping that it will help to create self-modifying systems with truly open architecture (that in my opinion may lead to creating a very complex highly adaptive autonomous programs).

Yet another programming language

Probably every person hearing about a new language asks this question: why yet another programming language? I cannot say about all but me. When I decided 10 years ago to create a new programming language I had several reasons. First of all it was a perfect way to learn C++ (as many Russians I came from Pascal & Delphi world). But most of all I was interested in object-oriented programming. For me it was a perfect chance to learn more about it. I was fascinated with Smalltalk and decided to do something similar. Writing the compiler is a quite challenging task but it cannot be compared with the task of creating a language or a programming paradigm (after all the most valuable things in our world are ideas). So after several attempts to invent / create something original I decided to follow other way: implement something simple and gradually modify it in hope to find something interesting. So step by step the language grew (practically any part of the compiler / language was rewritten / refactored at least several times) and now it has nothing common with the one I decided at the beginning. And though many of its ideas which I thought were original are used in other languages ELENA has its own individuality and style.

So how could I answer on this question? Is ELENA yet another programming language. The answer is not simple. Yes, ELENA may be considered as another amateur language with small source code base and lack of bug tracking functionality. And no, ELENA is a conceptual language. It is designed to examine / prove feasibility of several basic concepts. From the beginning I tried to make the language as dynamic as possible. My ultimate goal is to create the programming systems with truly open architecture, the systems which can be modified / extended in run time, the system where a big number of "simple" objects actively cooperate with each other forming group objects, able to self-modify. Will the language become something more than experimental one? Only time will show. Honestly I have no idea where the language will be in the next several years. One thing I may say definitely - it will be different.

In this blog I will try to show my current ideas and the state where the language is.