Thursday, November 28, 2013

ELENA 2: Messaging

There was major overhaul in the way how messaging is implemented in ELENA so in this tutorial I will once again cover this topic.

Unlike strong typed languages the process of invoking the method is called sending a message because the actual method resolving happens at run-time and is implemented by scanning through the target’s VMT. In ELENA it could be even more complex because the actual message can be calculated at run-time as well. It could be redirected to another object with the help of redirect method as well. So message sending is more powerful operation but it comes with a cost. In general it costs more than the conventional method calling. Using redirect handler adds another overhead. So it is not wonder that ELENA is slower than static binding languages. A lot of efforts were made in the new version to reduce this overhaul.

The major change was to allow several parameters to be passed with the message. Though it sounds simple in reality it required major changes in the language implementation, especially parameter dispatch routine (currently it still can be done only for single parameter). The order of parameters in the stack had to be reversed; redirect algorithm was modified and so on. Another change was an introduction of open argument list

Now, let’s look at messaging in details

As in the most of dynamic object-oriented languages the main way to interact with objects in ELENA is sending a message. Unlike others the message name is structured and consists of a verb, a signature and a parameter counter. The verb defines a message action, for example read or write some data. There are only limited set of possible verbs (e.g. eval[uate], add, set, get, run, seek and so on). In general the signature is user defined and describes the message parameters. It can be used to define some custom action as well (e.g. writeLine, which in fact is eval&writeLine(1)). If the signature is not provided the message is considered to be generic and can be qualified (for example by dispatching).

If the object wants to handle the message it has to contain the method with the same name. If no method mapping was found the flow is considered to be broken and the control goes to the next alternative flow (exception handler) or the program is stopped.

The simple code to send a message looks like this:

console write:"Hello World".

Note: "write" is a generic message; a literal constant is a parameter.

Several messages can be send in one statement, the parameter itself may be result of object interactions:

console write "2 + 2 =" write:(2 add:2).

We could use operators to have the shorter code:

console << "2+2=" << 2 + 2.

Note: In most cases "<<" is a synonym to "write" and "+" to "add".

Several parameters can be passed in the message as well:

control foreach:(1,2,3) &do:printingLn.

Ampersand is used to indicate that the signature has several arguments (subjects). The actual message name is eval&foreach&do(2).

The generic message can have several parameters as well:

consoleEx writeLine:”a+b=”:(a + b).

To be continued...

Monday, November 4, 2013

ELENA 2.0 Tutorial: Accumulator factory

In this tutorial we will implement another Rosetta code sample: Accumulator.

Our task is to implement the function which will return another function accumulating passed parameters.

Let’s start with declaring our accumulator function. Note that ELENA is an object-oriented language and any function is in fact an object (or in our case – a symbol).

#symbol EFunction =
{
   eval : x
   [
       ^ self append:x.
   ]
}.

Or we could simplify the code using a generic closure (function symbol):

#symbol EFunction =
 (:x) [ self append:x ].

Note that our code cannot be used stand alone, because we do not declare “append” method. It is in fact an object extension (that’s why it starts with E).

So another function should be declared – it will combine the passed variable (supporting “append” method) with our accumulating function – creating a wrap group object:

#symbol Accumulator = (:aVariable)
    [ Wrap(EFunction, aVariable) ].

To understand how this code works let’s recall what is a group object. In short group object overwrites SELF variable (but not $SELF one). Various group objects do it differently. Wrap one replaces SELF in the extender (the first one) with the content (the second one). To put it another way it wraps the extender around the content: when we call append method, Wrap group object redirects the message to its first member replacing SELF with the second one.

The use case will be the following:

#var x := Accumulator : (Integer new:1).
x:5.

Let’s optimize the code a bit, to allow our symbol accepting constant values as well

#symbol Accumulator =(:anInitialValue)
    [ Wrap(EFunction, Variable new:anInitialValue) ].

So we could drop the variable creating:

#var x := Accumulator : 1.
x:5.

The full code is below:

#define system.
#define system'dynamic.
 
#symbol EFunction = 
    (:x) [ self append:x ].
 
#symbol Accumulator = (:anInitialValue)
    [ Wrap(EFunction, Variable new:anInitialValue) ].
 
#symbol Program =
[
    #var x := Accumulator:1.
 
    x:5.
 
    #var y := Accumulator:3.
 
    console write:(x:2.3r).
].

Monday, October 7, 2013

ELENA 2.0 Tutorial: Add a variable to a class instance at runtime

In this tutorial we will implement Rosetta code sample - Add a variable to a class instance at run-time.

Though ELENA does not allow directly adding a field / method to the object it is possible dynamically to override any object with a help of the redirect method.

Let’s declare a wrapper class which will bind our class instance with a variable.

class Extender
{
    object theObject.
    object theField.
    
    constructor new : anObject
    [
        theObject := anObject.
    ]
    
    foo = theField.
    
    set foo : aValue
    [
        theField := aValue.
    ]
}

The code is simple: we declare a field and two methods accessing it: get&foo and set&foo: and an initializing constructor.

Now let’s declare a redirect method:

dispatch => theObject.

This method will redirect any unhandled message to the field - theObject. As a result we effectively dynamically override the object (so called horizontal inheritance).

Now let’s test the code:

    var anObject := Extender new:234.

    anObject set foo:"bar".

    console << anObject << ".foo=" 
            << anObject foo.

The output will be the following:

234.foo=bar

The full tutorial code is below:

class Extender
{
    object theObject.
    object theField.
    
    constructor new : anObject
    [
        theObject := anObject.
    ]
    
    foo = theField.
    
    set foo : aValue
    [
        theField := aValue.
    ]
    
    dispatch => theObject.
}

symbol program =
[
    var anObject := 234.
  
    // adding a field
    anObject := Extender new:anObject.

    anObject set foo:"bar".

    console << anObject << ".foo=" 
            << anObject foo.

    console readChar.
].

Monday, September 23, 2013

ELENA 2.0: Sum of Two Numbers Tutorial

In this tutorial we will learn how to create an object, read console and make simple operation with numbers.
First of all let’s create a variable and assigns a newly created object to it. To create an object we have to send a message "new" to its class:

var A := system’Integer new.
To read the console we have to send "readLine" to the console symbol

system’console readLine
The message will return the entered text. Now we have to convert it to the number. To do so we could use an extension – extensions'convertorOp

system’console readLine; convertTo:to:A.
The extension method "convertTo" overrides a literal and converts its value to an integer.
Then we will do the same for the second number:

var B := system’console readLine; 
            convertTo:(system’Integer new).
Now let’s sum two numbers, print the result and wait for any key

system’console writeLine: (A + B); readChar.
Our code works well if the user will enter a correct number, in all other cases the process will be broken. To warn the user if the number is wrong we have to catch an exception:

system’console readLine; convertTo:A
| if FormatError: (:e) [
    console writeLine:(e message); readChar.                    
    AbortException new; raise. 
].
So far so good. Now we could refactor our code a little. To do so we have to declare a helper extension EReader which will read and convert the number from the console

extension EReader
{
    loadFrom : aStream
        = aStream readLine; convertTo:self
            | if FormatError: (:e)
                [
                    console writeLine:(e message); readChar.
                    
                    AbortException new; raise.
                ].
}
So our code will look like this

A loadFrom:console.
How it works? EReader temporary overrides the variable but self still points to the original class.
Now let’s put all together

import extensions.

extension EReader
{
    loadFrom : aStream
        = aStream readLine; convertTo:self
            | if FormatError: (:e)
                [
                    console writeLine:(e message); readChar.
                    
                    AbortException new; raise.
                ].
}

symbol program =
[
    var A := Integer new; loadFrom:console.
    var B := Integer new; loadFrom:console.

    console writeLine: (A + B); readChar.
].

Wednesday, August 7, 2013

ELENA 2.0: Hello World Tutorial

In our first ELENA 2.0 tutorial let’s create a simple console program.

First we have to create a new project: File - New - Project. In the open dialog we have to select: Project type – console; Namespace – example1; Target file name – example1 and press OK.

Next let’s create a source file: File – New – Source File

Before continue we have to save it: File – Save All (IDE will ask if the new module should be included into the project – press Yes).

Now we are going to write our program. We will start with declaring the program main body – code symbol:

symbol program =
[
].

To print the message we have to send the message writeLine to system’console symbol:

system’console writeLine:”Hello World”.

After that we will wait for the user action.

system’console readChar.

Let’s make a simple optimization. We could declare system namespace so no need to write it every time. So our program looks like this:

symbol program =
[
    console writeLine:"Hello World".
    
    console readKey.
].

Before compiling the project we have to assign the program entry to our symbol. So select Project – Forwards…

In the open dialog enter the following line : 'program=example1'program, press Add and Save. (Starting from 1.9.24 this is no longer required. It is enough to declare program closure in the root name space)

Now we can run our program: Debug – Run.

Monday, July 8, 2013

ELENA 2.0 : Namespaces

Let’s start the language review with taking a look at the system structure.

ELENA API consists of modules (files with .NL extension) containing classes and symbols. Every class or symbol may be referred by its namespace (or to put it other way around a symbol namespace is a path to the symbol module). 

All source files (files with .L extension) located in the same folder are compiled into the corresponding module. A project file (a file with .PRJ extension) defines the root namespace and the output type (stand-alone executable, VM executable or a library). The project may produce several modules if it contains the files located in sub folders (the new module namespace consists of the root one plus the folder relative path)

Wednesday, April 3, 2013

ELENA 2: introduction

A lot of time has passed since my last post. So I would like to say what's going on with the language right now.

 I'm in the process of the deep language redesign. After analyzing my experience with the language I decided to get rid of some old ideas and simplify a lot. Though the language syntax will not change much the underlying logic will be overhauled. As a result the language will come closer to its inspiration - Smalltalk. Though it still be a different language with its own unique features. 

First of all there will be big changes with method parameters: it will be possible to have several parameters, no need to declare subjects. I will finally introduce exception handling. There will be possible to have several constructors. External links will be handled automatically, so no need in writing middle layer native code. 

The first alpha version will be released in May or June.

To be continued...