Saturday, March 11, 2017

Multi-methods in ELENA

In this tutorial I will show how multi-methods are implemented in ELENA

To take part in parameter dispatching classes should be declared with dispatchable attribute.

type value :: MyValue.

class MyValue :: dispatchable(value)
{
}

To dispatch the parameter we have to send cast message to it:

class MyClass
{
    eval : o
    [
        o cast:%eval to:$self.
    ]
    
    eval value
    [
        console writeLine:"value".
    ]
}

This approach works quite good for a single parameter. For several parameters this approach works not so good. It is possible to resolve them using several nested closures. Currently general solution is not possible. But basic data types support limited two parameter dispatching:

class MyValue :: dispatchable(value)
{
    add : n : m
        = n cast:%add and:m to:$self.
        
    add int:n int:m
    [
        console writeLine:"int&int".
    ]        
        
    add int:n long:m
    [
        console writeLine:"int&long".
    ]        
        
    add long:n int:m
    [
        console writeLine:"long&int".
    ]        
        
    add int:n literal:m
    [
        console writeLine:"int&literal".
    ]        
        
    add literal:n int:m
    [
        console writeLine:"literal&int".
    ]        
        
    add char:n int:m
    [
        console writeLine:"char&int".
    ]        
        
    add int:n char:m
    [
        console writeLine:"int&char".
    ]        
}

symbol program =
[
    var o := MyClass new.
    
    o add:1:2.
    o add:1:2l.
    o add:1l:2.
    o add:1:"string".
    o add:"string":2.
    o add:#32:2.
    o add:1:#32.
].

The result will be:

int&int
int&long
long&int
int&literal
literal&int
char&int
int&char

Friday, March 10, 2017

ELENA 3.0 : event handler

In this short article I will show how to implement event handler using a new attribute : event

To declare a new event handler we should declare the field with event attribute:

func1 event onStart :: theStart.

The first parameter indicates the action type (func1 is an action with a single generic parameter), the second one - the property name to be used for attaching the handler.

To attach the handler we have to call the property with our action:

    object onStart func1(:x)[ /*...*/ ].

The simple example code is below:

import extensions.

class MyClass
{
    func1 event onStart :: theStart.

    func1 event onEnd   :: theEnd.
        
    start : o
    [
        ($nil != theStart)
            ? [ theStart eval:o ].        
    ]
        
    stop : o
    [
        ($nil != theEnd)
            ? [ theEnd eval:o ].        
    ]
}
      
symbol program =
[
    var o := MyClass new.
    
    o onStart func1(:x) [ console printLine("a:",x) ].
    o onStart func1(:x) [ console printLine("b:",x) ].

    o start:1.
].

Thursday, February 9, 2017

Mixins in ELENA : State machine

In this tutorial we will see how to program a simple state machine using Mixins and message dispatching.

Let's just remember that eval message in ELENA can be qualified (e.g. dispatched with a subject).

   class MyClass
   {
       eval
       [
          console writeLine:"generic method"
       ]                                                    

       state0
       [
          console writeLine:"qualified state0 method"
       ]
   }

   symbol program =
   [
      var o := MyClass new.

      var subj := %state0.  // a subject - message qualifier

      o eval.                // output : generic eval method.

      o~subj eval          // output : qualified state0 method.
   ].

"subj" is a subject class which qualifies the generic message "eval". In the expression "o~subj" we create a temporal mixin object (so called a temporal mutation). As a result "eval[0]" message is turned into "state0[0]" and is sent to the instance of MyClass.

This principle will help us to create our simple state machine.

class Statemachine
{
    object theState.
    
    eval
        => theState.
    
    state0
    [
        console writeLine:"state0".
        
        theState := %state1.
    ]

    state1
    [
        console writeLine:"state1".
        
        theState := %state0.
    ]
        
    constructor new
    [
        theState := %state0.
    ]
}
                                                      
symbol program =
[
    var o := Statemachine new.
    
    o eval. // output : state0
    o eval. // output : state1
    o eval. // output : state0
    o eval. // output : state1
].

The key element is a message dispatching expression:

    eval
        => theState.

This code is equivalent to our mutation expression:

    eval
        = self~theState eval.

As a result we create a state machine without branching operators, using only ELENA dispatching routines.