Friday, January 28, 2011

Rosseta code tutorials:Add a variable to a class instance at run-time

Another Rosetta code sample here

Though ELENA does not support adding a function / variable at a run time this could be simulated with the help of a group object (Note that ELENA does not allow a direct access to the object fields at all).

So we have to create a group member FieldContainer which will hold the variable and a pair of the methods to access it (get / set).

First of we have to declare a new subject (a property name) - foo
#subject foo.

Then a property container:
#class FieldContainer
{
#field theValue.

#method foo'set : anObject
[
theValue := anObject.
]

#method foo'get = theValue.
}

So now we could extends any existing object
// adding a field
anObject := #group(anObject, FieldContainer).

anObject set &foo:"bar".

#var aConstant := #group("My String", FieldContainer).
aConstant set &foo:"boo".

'program'Output << anObject foo.

Rosseta code tutorials:Ackermann function

Let's implement Ackermann function - Rosettacode.

Because ELENA is a pure object-oriented language we have to create the object which will calculate the function. This object will only evaluates the parameter so we have to declare symbol with the single method "evaluate" (note that a new class can be declared both as implicit symbol - #class MyClass {} and as an explicit one -
#symbol MyClass = { ..}, the only difference that the symbol cannot have fields and be inherited).

#symbol Ackermann =
{
    a_function &m:anM &n:anN
    [
        #if anM
            ifequal:0 [ ^ anN + 1. ]
            | greater:0 ?
            [
                #if anN
                    ifequal:0 [ ^ self a_function &m:(anM - 1) &n:1. ]
                    | greater:0 ? 
                    [ 
                        ^ self a_function 
                             &m:(anM - 1) 
                             &n:(self a_function &m:anM &n:(anN - 1)). 
                    ].
            ].
        
        $self fail.
    ]
}.

The implementation is quite straight-forward but there are several things I would like to explain. Any ELENA method has only one parameter but it is still possible to pass several ones using the argument list (which is in fact the single object which returns the expected arguments). The argument names have to be declared beforehand
(see - Method calling syntax).

Let's declare the required subjects.

#subject a_function, m, n.

Secondly Ackermann function is defined for n and m bigger or equal to zero. So we have to decide what to do if one of the parameters is negative. ELENA does not support exceptions so we have to break the program flow. It is done by sending the special non-existing message - fail - to itself.

self fail.

Now we could calculate our function:

'program'Output << Ackermann a_function &n:1 &m:1.

Let's modify our code using the appropriate signature (note that << and write are synonyms):

'program'Output write &ackermann &m:0 &n:3.

To use this signature we have to declare a class with a "signature" hint:

#class(signature:(a_function, m, n)) AckermanValue
{
    #field(arg:m)theM.
    
    #field(arg:n)theN.
    
    #method m'get = Int64Value::theM.
    
    #method n'get = Int64Value::theN.
    
    #method save : aWriter = aWriter write &:(Ackermann a_function:self).
    
    #method literal_writer'read : aWriter
    [
        aWriter << "A(" << theM << "," << theN << ")=" << Int64Value::self.

        ^ aWriter.
    ]
}

Note that declaring AckermanValue class we do not specify its type (ELENA is actually a type-less language but we could assign a subject to it which can be used as its "type " by multi-dispatching mechanism), so 'program'output will not know how to print it. We have to add a new method to implement a custom print action.

#class AckermanValue
{
...   
    #method save : aWriter = aWriter write &:(Ackermann a_function:self).
    
    #method literal_writer'read : aWriter
    [
        aWriter << "A(" << theM << "," << theN << ")=" << Int64Value::self.

        ^ aWriter.
    ]
}

The expression output will be the following:

A(0,3)=4

Thursday, January 27, 2011

ELENA 1.6.0 released

This release includes major language changes (method calling overhaul, simplified message argument list syntax, new classes and several critical bug fixes) as well as refactored ELENA standard library.

A new concept of method signature is introduces (reusing code, simplifying the message
sending syntax). In general the number of subjects was reduced. For example the subject content is no longer supported. The generic verbs are now used to set / get indexer / variable content.
1.5.6:
anArray@3 content'set:anObject

1.6.0:
anArray@3 indexer set:anObject


The subject bool was removed as well. Compare:
1.5.6:
#if (anInteger >= -2147483646)bool'or:(anInteger <= 2147483647)?

1.6.0:
#if (anInteger >= -2147483646)or:(anInteger <= 2147483647)?


I will post several tutorials describing 1.6.x features.

http://sourceforge.net/projects/elenalang/files/ELENA/1.6.0/ELENA-1.6.0.zip/download

Saturday, January 15, 2011

ELENA Programming Language:method calling syntax

In this post I would like to make a short overview of ELENA method syntax features (starting from 1.5.6.9 version).

ELENA programming language (unlike many others) introduces several limitation on the programmer free will over naming and using methods. First of all the method can have only one parameter. Secondly there are special rules how the method could be named (apart from private ones, which we will ignore in this post).

The simplest method declaration may look like this (in case of in-line class, the keyword is omitted):
#method subject'verb : parameter
[
]



As you see the method name consists of two parts: a subject (a noun) and a verb. The verb defines an expected operation, the subject describes a method parameter (a list of possible operations with it).
If the message do not have a subject part it is considered to be generic (and can be used for multi-dispatching). The 'GET' messages may omit their verbs. The following expressions are equivalent: “aNumber int'get” and “aNumber int” (“int” is a subject).

There are a limited list of verbs in ELENA (though this lists will be expanded with the time, to avoid possible verb overuse). Let's name them: add, and, append, back, check, clear, clone, close, delete, dispatch, divide, do, equal, evaluate, find, free, get, greater, if, ifequal, ifless, ifnot, increase, insert, is, isnot, less, load, multiply, new, not, notequal, notgreater, notless, open, or, proceed, process, react, read, reduce, repeat, rewind, run, save, send, separate, set, start, stop, subtract, wait, write, xor.

There are synonyms (operators) for some verbs. Unlike normal verbs, operators have lower parsing order. These codes are equivalent - “a << b + c int'get” and “a write:(b add:(c int'get))”. Operatiors are generic verbs and cannot have subjects. Let's name the operators and their verbs:
== - equal,
!= - notequal,
>= - notlesss,
<= - notgreater,
> - greater,
< - less,
? - is,
! - isnot,
@ - seek,
=> - evaluate,
>> - read,
<< - write,
+ - add,
- - subtract,
* - multiply,
/ - divide,
+= - append,
-= - reduce,
*= - increase,
/= - separate

Unlike verbs the subject names are not limited (it is not recommended to give a name equal to a verb, because of possible ambiguity). But the subject should be declared before the use. The syntax looks like this:
#subject subject, argument1, argument2.

It is possible to import subjects declared in another packages (the subjects declared in the project are automatically imported in all following modules).

#subject math'dictionary'*.


If there is a name conflicts between subjects declared in different modules it is possible to provide an alias (will be implemented in 1.6.0).

#subject math'* = math'dictionary'*.


It is possible to import the subjects to the whole project (std'dictionary, std'dictionary'protocols, std'dictionary'types subjects are imported automatically to any program or library).

Though the method may have only one parameter it is still possible to provide several arguments with the help of argument objects. Let's consider how we could declare the method with an argument list.

#method subject'verb &argument1:anArgument1 &argument2:anArgument2
[
]



This code will be compiled into the following:

#method subject'verb  : anArguments
[
#var anArgument1 := anArguments argument1'get.
#var anArgument2 := anArguments argument2'get.
]



The similar syntax could be used for passing multiple arguments to the method (note that it doesn't matter if the method declaration uses an argument list).

anObject subject'verb &argument1:anArg1 &argument2:anArg2.


This code will be compiled into the following:

anObject subject'verb: { argument1'get = anArg1. argument2'get = anArg2 }.


As it was already said above the subject defines the method parameter. This feature is used in ELENA for implementing multi-dispatching.

Let's declare three classes A, B, C and assigns subject1 to the class A, subject2 to the class B (class C does not have assigned subject).

#hint(subj:subject1)
#class A
{
}

#hint(subj:subject2)
#class B
{
}

#class C
{
}



Now we will declare the fourth class which will deal with them.

#class D
{
#method subject1'set : anObject [ … ]

#method subject2'set : anObject [ … ]

#method set : anObject [ … ]
}



We are going to call the verb set with instances of classes A, B and C. According to our notation for the instance of the class A we have to call subject1set, for an instance of B – subject2'set. Because the class C does not have an subject we should call generic method set (it is expected that the generic methods are able to work with “unknown” objects). So lets declare three variables and call the appropriate methods.

#var anA := A.
#var aB := B.
#var aC := C.

D subject1'set:anA subject2'set:aB set:aC.



But in most cases we do not know its type (in ELENA its class or supported subject). It is possible dynamically resolve the appropriate message. Let's add a special attribute to the generic method.

 #hint(disp)
#method set : anObject [ … ]



Now we could simplify the code and the appropriate message will be called automatically

D set:anA set:aB set:aC.


And finally let's consider the concept of an argument signature. A signature allows to define the message subject on the base of argument list (static multi-dispatching).

Let's presume we have a following argument list

#method subject'set &argument1:anArg1 &argument2:anArg2 &argument3:anArg3 […]


Instead of passing every time all three arguments we could define three alternative argument signature: &argument1 & argument2, &argument2 & argument3 and &argument1 & argument3.

#hint(subj:subject, signature:(argument1, argment2), signature:(argument2, argment3), signature:(argument1, argment3))
#class CustomArgumentList
{
#hint(arg:argument1)
#field theArg1.

#hint(arg:argument2)
#field theArg2.

#hint(arg:argument3)
#field theArg3.

#method argument1'get = theArg1 nil'isnot | back:0.

#method argument2'get = theArg2 nil'isnot | back:0.

#method argument3'get = theArg3 nil'isnot | back:0.
}



(Note that the signature class, should be declared in the same module where the first argument is declared). The mapping between argument value and a signature class field is defined by arg hint.

So now we could use simplified syntax to call subject'set

anObject set &argument1:anArg1 &argument2:anArg2.
anObject set &argument2:anArg2 &argument3:anArg3.
anObject set &argument1:anArg1 &argument3:anArg3.



Note that the order of the argument subjects play important role. &argument2 &argument1 and argument1 &argument2 are different signatures.

If the argument list contains only one argument it will be automatically translated into an appropriate message.

anObject argument1'set:aParam and anObject set &argument1:aParam are equivalent.


The signature cannot be used in the method declaration. If no appropriate signature can be found the generic method will be called.

Friday, January 14, 2011

Weekly release: 1.5.6.9

1.5.6.9 is a snapshot of the work on upcoming major 1.6.0 release. Part of the code was not yet ported to the new platform. Nevertheless it includes all major improvement designed for 1.6.0.

The main change of the coming release is an improved argument syntax. Let's compare -
1.5.6.4:
'program'Output << 
translit'Transliteration::translit'RusLat run:aSource << "%n%n".

1.5.6.9:
'program'Output write &_cyril2lat &literal:aSource << "%n%n".

“&_cyril2lat &literal:aSource” - is called argument signature and allows to reuse the code.
For example we could use the same signature in another method without any change in basic'String code –
basic'String append &_cyril2lat &literal:aSource


In the next posts I will discuss it in details