Click here to Skip to main content
13,866,642 members
Click here to Skip to main content
Add your own
alternative version

Stats

104.4K views
888 downloads
59 bookmarked
Posted 12 Sep 2016
Licenced Apache

Introduction to ELENA Programming Language

, , 14 Feb 2019
Rate this:
Please Sign up or sign in to vote.
ELENA is a general-purpose, object-oriented, polymorphic language with late binding

Introduction

ELENA is a general-purpose, object-oriented, polymorphic language with late binding. It features message dispatching/manipulation, dynamic object mutation, a script engine / interpreter and group object support.

 In this article I will present the basic concepts of how to code in ELENA and also will present the basic concepts of purely object-oriented programming.

Features of ELENA language

  • Pure polymorphic object oriented language
  • Dynamic "class mutation"
  • Message dispatching
  • Virtual machine
  • Command line 32-bit compiler
  • GUI IDE & Debugger
  • Unicode support (utf-8)
  • Complete source code
  • Number of samples
  • Script Engine / Interpreter
  • Virtual Machine Terminal

Where can I get the executable of compiler and source code?

ELENA development community

Build the ELENA compiler

The ELENA compiler was fully implemented in C++ to compile the compiler is not required external dependencies, such as Flex, Bison... you just need Visual Studio 2015/2017.

Alex implemented its own syntax generator, assembler and the tools he needed.

To build the compiler you can open the CMD, go to root elena folder and type:

  • for VS2015 : recompile.bat / for VS2017 : recompile15.bat

or, to generate release files

  • for VS2015 : vs_release.bat %cd% / for VS2017 : vs_release15.bat %cd%

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. " - http://elenalang.blogspot.com.br/2010/07/yet-another-programming-language.html

First steps

It is extremely important before beginning the program in a 100% object-oriented language, know the basic concepts of a truly object-oriented language.

Basic OOP Concepts and Terminology

What are the basic conceps of ELENA ? As Smalltalk, the basic concepts are:

  • Objects
  • Classes
  • Fields
  • References
  • Methods
  • Messages
  • Inheritance
  • Receiver
  • Dynamic Binding

Objects

The ELENA "object" is very similar to the .Net or C++ object, in particular, each object is stored in memory and has several fields or methods, which can point to other objects. Each object is an instance of a class.

Classes

An object is lika a C 'struct' or a Ada record, the only difference between a record and a object is that the objects contains a field that identifies which class the object belongs to. In C++, C#, ELENA or Smalltalk, there is a single hidden field in every object. In ELENA this field is called the "dispatch table reference" and, inside of "dispatch table" have the informations about class. In other languages, this hidden field is called the "V-table pointer" or "dispatch table pointer".

Fields

Fields, also known as the instance variables, are the variables declared within a class. These variables can only be read with the use of methods to assign or read the contents of the field.

References

In C++, we talk about "pointers" to objects while in C# we talk about "references" to objects. Both concepts basically the same and references are implemented by straight pointers, which are just memory address. In ELENA, we use references.

Method

Method is like a function, except that it is applied to a specific object. We also say that the method is "invoked" on an object or "sent to" an object. The object in question is called the "receiver". Every method is invoked on receiving object. In C++ or C#, the receiver is called "this", in ELENA - "self".

Methods in ELENA are similar to methods in C# and C++, where they are called "member functions". Methods may take arguments and always return a result (if no result provided "self" reference is returned). The method body is a sequence of executable statements. Methods are invoked from expression, just as in other languages.

Messages

There is an important distinction between "methods" and "messages". A method is a body of code while a message is something that is sent. A method is similar to a function. in this analogy, sending a message is similar to calling a function. An expression which invokes a method is called a "message sending expression".

ELENA terminology makes a clear distinction between "message" and "method". A message-sending expression will send a message to the object. How the object responds to the message depends on the class of the object. Objects of differents classes will respond to the same message differently, since they will invoke different methods.

Grammar

ELENA uses LL(1) grammar. It is an analytical grammar, meaning that the role of the terminal token is defined by its position in the statement. As a result the grammar lacks the keywords ( instead user-defined attributes are used ) and there are no reserved words. For example, it is possible to write the code without attributes at all:

class
{
   field;

   method(param)
   {
   }
}

where a class with a name class is declared. It has one field with a name field and one method - method[1]

But in most cases it is required to provide additional info. So the token role is defined by its position.

class class;

singleton Tester
{
    do(var class class)
    {       
    }
}

public program()
{
    var class class := new class();

    Tester.do(class);
}

where class is used as an attribute to declare a new class, as a identifier type and as an identifier.

The "Hello World!" application

A great start for when we are studying or just knowing any new programming language, is always the famous program "Hello world!".

In order to create our first program, we have to get the ELENA compiler, for this, you just need to download the compiler in this link.

After download and extracted all the content to the folder of your choice, 

Important: You need to put the "bin" folder in your system path.

With the bin folder in your path system, this is necessary to able the generate executable to access the elena runtime than is used for example, when a exception throws to show in what class & method the exception happens.

Let's start, first of all, we need to open the ELENA IDE, for this, you can type in CMD "elide" or, just open the executable called "elide".

After open the elide IDE, we will create a new project, for this, we just need to go to menu "File->New->Project", when you click in the project menu, will open a dialog like this:

What every field means:

  • Type: Is the type of application than you will create, like GUI, Console, Console App running over VM ....
  • The namespace of application
  • The checkbox to warning about unresolved references
  • Additional options for the compiler
  • Target file name: the output file name
  • Output path: output of ELENA objects
  • Enable or disable the debugger
  • Command line arguments to test the application

For this article we will use these specific settings:

After you click in "ok" we need to create a new source file, for this, just go to menu "File->Source file" or use the shortcut "Ctrl+N".

Now, we can start to code... this is the code for Hello World

public program()
{
    system'console.writeLine("Hello World!");
}

After you write this code, you need to save the project and the source code in some directory and you just need to build it.

Understanding the code

public program()

Here we declare a public singleton closure (a static class containging one message). By default, the "program" is the entry point of the program, but, it's possible to change this.

system'console.writeLine("Hello World!");

In this line of code, we have a very intresting informations to look at:

  1. "system": It is a namespace, the namespace itself may contain sub elements separated by apostrophes
  2. "console": Is a class
  3. "writeLine": Is a message
  4. "Hello World!": Is the parameter of the message
  5. ";": Terminator

What this mean for us ?
That means than we send a message to method writeLine of class console in namespace system with parameter "Hello World!".

Like in other languages, like C#, C++, Python we can add a special keyword to "import" some namespace, with this we can 'reduce' code.

So, the hello world example with "import" keyword will be like:

import system;

public program()
{
    console.writeLine("Hello World!")
}

The unique problem than we have with this program is than we can't read the output..., so, to fix this we just need to use one more method, and, we can use this method in two ways.

First:

import system;

public program()
{
    console.writeLine("Hello World!");
    console.readChar();
}

Second:

import system;

public program()
{
    console.writeLine("Hello World!").readChar()
}

The last semicolon can be omitted.

This second way to write the same program works well because in ELENA every method returns an object.

Creating variables

Like in Smalltalk, in ELENA everything is a object, so, to create variables we just need to use a special 'keyword'

var

The syntax of this keyword is, basically:

var <variable name> := <Class instance>;

So, as example, let's write a simple program to read something from the keybord.

If you preffer, you can create a new console project for this example.

import system;
import extensions;

public program()
{
    var aNumber := console.print("Type a number: ").loadLineTo(new Integer());
    console.printLine("You typed " + aNumber);
    console.readChar()
 }

Really simple, right ?
So, in this example we need to import a one more namespace, the namespace extensions contains the definition for the "loadLineTo(<type>)".

A variable can contains any object types, for example:

var x := new IntNumber();
var y := 0;
var k := new system'calendar'Date();
var n := k.Year;
var s := "Hello World";
var u := 0fffffh;
var l := 3.1415r;
var m := new RealNumber(3.14r);
var j := true;
var h := false;

Just-in-place variable assignment is supported, as well as assigning several variables in a row:

import extensions;
    
singleton Tester
{
    printMe(s)
    {
        console.printLine(s)
    }
}

public program()
{
    var a;
    var b := a := 2;
    
    Tester.printMe(a);
    Tester.printMe(b);
    Tester.printMe(b := 3);
}

The output is:

2
2
3

It is possible to declare and pass by ref parameter directly in the expression:

import extensions;

singleton Tester
{
    printMe(s)
    {
        console.printLine(s)
    }
    
    assignMe(ref retVal, val)
    {
        retVal := val
    }
}

public program()
{
    Tester.assignMe(ref var i, 2);
    Tester.printMe(i);
}

The output will be:

2

Conditional operator, if and else

Conditional operations in ELENA are defined as follows:

(<myCondition>)
   ? { doSomething in case TRUE } : { doSomehting in ELSE }

It's more simple to see this, in this simple example:

import system;
import extensions;

public program()
{
    var aTrue := true;
    var aFalse := false;
    
    (aTrue && aFalse)?
        { console.printLine("aTrue && aFalse is: ",aTrue && aFalse) }
        : { console.printLine("aTrue && aFalse is: ",aTrue && aFalse) };
        
    (aTrue || aFalse)?
        { console.printLine("aTrue || aFalse is: ",aTrue || aFalse) }
        : { console.printLine("aTrue || aFalse is: ",aTrue || aFalse) };
    
    console.readChar()
}

Template based if-else condition

To simplify the code, we may use a code template - if. Let's take a look:

    var a1 := true;
    
    if(a1 == true)
    {
         console.printLine("a1 == true").
    }
    else 
    { 
        console.printLine("a1 != true").
    }
Let's implement an example program containing many conditions and variable statements.
import extensions;

public program()
{
  console.writeLine:"Hi!! :)";
  var yourName := console.writeLine("Whats your name ?").readLine();
  console.writeLine:"How old are you ?";
  var yourAge := console.loadLineTo(new Integer());
 
  var numberOfChildrens := 0;
  if(yourAge >= 0 && yourAge <= 10)
  {
    console.writeLine:"You're still very young!!"
  }
  else if(yourAge >= 11 && yourAge <= 20)
  {
    console.writeLine:"Adolescence, come a lot of people angry?"
  }
  else if(yourAge >= 21 && yourAge <= 30)
  {
    console.writeLine:"Do you already have children ? ( yes/no )";
    string haveChildren := console.readLine();
    if(haveChildren.lowerCase() == "yes")
    {
      numberOfChildrens := console.writeLine("Cool!! how many kids do you have ?")
                                     .loadLineTo(new Integer())
    }
  }
  else if(yourAge >= 31 && yourAge <= 40)
  {
    console.writeLine:"The first 40 years of childhood are the most difficult !!!"
  }
  else if(yourAge >= 41 && yourAge <= 50)
  {
    console.writeLine:"Life begins at 40!"
  }
  else if(yourAge >= 51 && yourAge <= 60)
  {
    console.writeLine:"Enjoy your LIFE !!!"
  }
  else if(yourAge >= 61)
  {
    console.writeLine:"You are at the age to enjoy and relax !!"
  };
  console.readChar()
}

Loops

Like in other programming languages, ELENA have a support for loops, let's take a look at the while loop, this loop is implemented using templates while and for.

while(<condition>)
{ /* ... loop code... */ };
for(<init>,<conditon>,<step>)
{ /* ... loop code... */ };

So, to make clear the usage of loop, let's write a simple program to:

import system;
import extensions; 

public program()
{
    var array := Array.allocate:200;
        
    var i := 0;
    while(i < array.Length)
    {
       array[i] := i * 10;
       i += 1
    };
      
    for(int i := 0, i < array.Length, i += 1)
    {
      console.printLine("At index ", i, " has the value:", array[i]);
    };
    
    console.readChar()
}

Classes and Methods and Fields

"ELENA is an object-oriented language. To create a program we have to declare new classes.

A class encapsulates data (fields) with code (methods) to access it. In most cases it is not possible to get a direct access to the class content. Usually the field refers to another class and so on until we reach "primitive" ones which content are considered as raw data (e.g. numeric or literal values).

Classes form the inheritance tree. There is the common super class - system'Object. ELENA does not support multiple inheritance, though it is possible to inherit the code using a dispatch handler (mixins / group objects). When the parent is not provided the class inherits directly system'Object (the super class).

A class instance can be created with the help of the special methods - constructors. A constructor is used mostly to initialize the class fields. There are special types of classes which do not have constructors and can be used directly (nested classes, extensions, closures). A class itself is considered as a stateless object." - https://github.com/ELENA-LANG/elena-lang/wiki/ELENA-Programming-Language#13-classes-symbols-nested-classes-and-closures

To understand this information, we will write some classes, to make clearer its implementation and use.

You can create a new project to create the classes that will create as example.

For the first example, we will create a simple class.

import system;
import extensions;

class MyFirstClass
{
    constructor()
    {
        console.printLine("MyFirstClass instancied!!! ehhhhhhh!!")
    }
}

public program()
{
    var myFirstClass := new MyFirstClass();
    console.readChar()
}

So, when you execute the program you will see the message on console:

MyFirstClass instancied!!! ehhhhhhh!!

Really simple, right ? (:

So, now that we know how to create a class, we will add methods in this class and we will create another constructor for this class, passing two arguments, those two parameters will be saved in two different fields...

First of all, we will create the new constructor with the new parameters, the class will look like:

import system;
import extensions;

class MyFirstClass
{
    int field1;
    int field2;
    
    constructor()
    {
        console printLine("MyFirstClass instancied!!! ehhhhhhh!!")
    }
    
    constructor new(int parameter1, int parameter2)
    {
        console.printLine("MyFirstClass instancied!!! with 2 parameters!!");
        console.printLine("My first parameter.: ", parameter1);
        console.printLine("My second parameter: ", parameter2);
        
        field1 := parameter1;
        field2 := parameter2;
    }
}

public program()
{
    var myFirstClass := new MyFirstClass();
    var myFirstClassWith2Parameters := MyFirstClass.new(500, 300);
    console.readChar()
}

Notice that in program, we created a new variable to store the new instance of the class, which is initialized with two parameters.

Now let's implement some methods to work with these two values that were passed by parameter.

class MyFirstClass
{
    int field1;
    int field2;
    
    constructor()
    {
        console.printLine("MyFirstClass instancied!!! ehhhhhhh!!");
        
        field1 := 0;
        field2 := 0;
    }
    
    constructor new(int parameter1, int parameter2)
    {
        console.printLine("MyFirstClass instancied!!! with 2 parameters!!");
        console.printLine("My first parameter.: ", aParameter1);
        console.printLine("My second parameter: ", aParameter2);
        
        field1 := parameter1;
        field2 := parameter2;
    }
    
    addTwoNumbers()
        field1 + field2;
    
    addTwoNumbers(int number1, int number2)
    {
        ^ aNumber1 + aNumber2
    }
    
    addTwoNumbersAndPrintIt()
    {
        var addResult := self.addTwoNumbers();
        console.printLine("Result of ", field1, "+", field2, "=", addResult)
    }
    
    addTwoNumbersAndPrintIt(int number1Argument, int number2Argument)
    {
        var addResult := self.addTwoNumbers(number1Argument, number2Argument);
        console.printLine(Result of ", number1Argument,"+",number2Argument,"=",addResult)
    }
}

Ok, now we have 4 methods, and we want to use this methods. Using the methods have no secret, we are using methods and classes that begin to write the codes in Elena for this article!! (:

So, the usage sample of this class is:

public program()
{
    var myFirstClass := new MyFirstClass();
    var myFirstClassWith2Parameters := MyFirstClass.new(500, 200);
    
    // Working just with the myFirstClassInstance
    myFirstClass.addTwoNumbersAndPrintIt();
    myFirstClass.addTwoNumbersAndPrintIt(20, 20);
    
    console.writeLine:"---------------------------------------";
    
    // Working just with the myFirstClassWith2Parameters
    myFirstClassWith2Parameters.addTwoNumbersAndPrintIt();
    myFirstClassWith2Parameters.addTwoNumbersAndPrintIt(15, 320);
    
    console.readChar()
}

One of the basic principles of object-oriented programming is inheritance between classes, so let's implement two classes, a base class and a derived class.

import system;
import extensions;

class MyFirstBaseClass
{
    string theField1;
    string theField2;
    
    constructor new()
    {
        theField1 := "";
        theField2 := ""
    }
    
    constructor new(string field1)
    {
        console.printLine("fieldBaseClass1 = ", field1);
        
        theField1 := field1;
        theField2 := "";
    }
    
    constructor new(string field1, string field2)
    {
        console.printLine("fieldBaseClass1 = ", field1);
        console.printLine("fieldBaseClass2 = ", field2);
        
        theField1 := field1;
        theField2 := field2
    }
    
    printFields()
    {
        console.printLine(self.Field1);
        console.printLine(self.Field2)
    }
    
    Field1 = theField1;
    Field2 = theField2;
}

class MyFirstDerivedClass : MyFirstBaseClass
{
    constructor new()
    {
        console.writeLine:"Constructor of MyFirstDerivedClass called with no parameters".
    }
    
    constructor new(string field1)
        <= new(field1 + " -- Called from DerivedClass")
    {
        console.printLine("Constructor of MyFirstDerivedClass called with 1 parameters")
        console.printLine("field1 = ", field1)
    }
    
    constructor new(string field1, string field2)
        <= new(field1 + " -- Called from DerivedClass", 
               field2 + " -- Called from DerivedClass")
    {
        console.printLine("Constructor of MyFirstDerivedClass called with 2 parameters");
        console.printLine("field1 = ", field1);
        console.printLine("field2 = ", field2)
    }
}

public program()
[
    var myFirstDerivedClassInstance := nil;
    
    var numberOfArgsToInitInInstance := 0;
    var continueLoop := true;
    while(continueLoop)
    {
        numberOfArgsToInitInInstance :=
            console.printLine("Enter with how much variables you want to use in instance init ? (0/1/2)") 
                   .loadLineTo(new Integer());
            
        if(numberOfArgsToInitInInstance >= 0 && numberOfArgsToInitInInstance <= 2)
           { continueLoop := false }
    };
    
    // This is a 'switch'...
    numberOfArgsToInitInInstance =>
        0 { myFirstDerivedClassInstance := MyFirstDerivedClass.new() }
        1 { myFirstDerivedClassInstance := MyFirstDerivedClass.new("Argument1 from program") }
        2 { myFirstDerivedClassInstance := MyFirstDerivedClass.new("Argument1 from program", 
                                                                     "Argument2 from program") }
        : { console.writeLine:"invalid option..." };
          
    myFirstDerivedClassInstance.printFields();
    
    console.readChar()
]

It is possible to declare the private methods which cannot be called outside the class.

import extensions;

class MyClass
{
    private printPrivate()
    {
        console.printLine("private print.")
    }
    
    printPublic()
    {
        console.print("Calling from public print - ");

        // self is a reference to the current object
        self.printPrivate()
    }
}

public program()
{
    // Note that if the constructor explicitly is not declared 
    // the system'Object one (without input parameters) is inherited
    var myClass := new MyClass();
    
    myClass.printPublic();
    myClass.printPrivate()
}

In normal case the class fields cannot be accessed outside the class. That's why we may declare a special method to access it:

import extensions;

class MyClass
{
    int _x;

    get int x() = _x;  // get accessor

    set x(int o)       // set accessor 
    {
       _x := o
    }
}

public program()
{
    var myClass := new MyClass();

    myClass.x := 2;

    console.printLine("MyClass.x=", myClass.x)
}

We may simplify our code if we will use prop field template:

import extensions;

class MyClass
{
    prop int x;
}

public program()
{
    var myClass := new MyClass();

    myClass.x := 2;

    console.printLine("MyClass.x=", myClass.x)
}

Exception Handling

We may use try-catch statement to handle the possible exceptions:

import extensions;

public program()
{
    try
    {
        new Object().nonExistingMethod();
    }
    catch(MethodNotFoundException e)
    {
        console.printLine("Method not found")
    }
    catch(Exception e)
    {
        console.printLine("Unknown error")
    }
}

 

Working with enumerable objects

ELENA supports several different types of enumerable objects : arrays, lists, dictionaries, ranges and so on.

To be used as enumerable one, object should handle enumerator message.

Let's consider a simple example:

import extensions;

public program()
{
    var list := new object[]{1,2.3r,"String",3l};
    
    var it := list.enumerator();
    while (it.next())
    {
        console.printLine(it.get())
    }
}

In the output every member of collection will be printed:

1
2.3
String
3

In this code we declare a static array - list. We send enumerator message to it and assign the returned enumerator to the variable it. Then we repeat the code until next message returns false value. get message returns a current enumeration member.

The same pattern can be applied for any enumerable object:

import extensions;
import system'routines;

public program()
{
    var range := new Range(1, 9);
    
    var it := range.enumerator();
    while (it.next())
    {
        console.printLine(it.get())
    }
}

Here we generate and print a range of natural numbers from 1 till 10. The result is:

1
2
3
4
5
6
7
8
9

Similar to C# there are a lot of extension methods which can be used for searching, counting, filtering and so on.

Let's start with a simple one - forEach - executes a code for each enumeration member. The code above can be rewritten using forEach extension method (declared in system'routines module) and a closure:

import extensions;
import system'routines;

public program()
{
   new Range(1, 9).forEach:(item){ console.printLine(item) }
}

where (item){ <...> } is a general closure with a single parameter.

We may further simplify our code using existing closure extensions'routines'printingLn

import extensions;
import system'routines;
import extensions'routines;

public program()
{        
    new object[]{1,2.3r,"String",3l}.forEach:printingLn
}

In both cases the output will be similar to our first two examples.

We may combine several extension methods in a row. For example filterBy is used to filter an enumeration based on the parameter output. Only the members for which filter function returns true will be passed further. It may be used in combination with other extension methods like forEach.

import system'routines;
import extensions'routines;
import system'math;

public program()
{
    new Range(1, 9).filterBy:(i => i.mod:2 == 0).forEach:printingLn
}

filterBy will return only even numbers. The output will be:

2
4
6
8

Note that (:item)( <...> ) is a lambda closure which is shortcut form of (:item)[ ^<...> ]

summarize extension is used to summarize all the members of the collection:

import extensions;
import system'routines;
import extensions'routines;
import system'math;

public program()
{
    console.printLine(new Range(1, 9).filterBy:(i => i.mod:2 == 0).summarize())
}

The result will be a sum of first 10 even natural numbers:

20

Using toArray extension we may save our enumeration as an array:

import extensions;
import system'routines;
import extensions'routines;
import system'math;

public program()
{
    var evens := new Range(1, 9).filterBy:(i => i.mod:2 == 0).toArray();

    console.printLine("sum(",evens,")=", evens.summarize())
}

toArray will collect the enumeration member into the array. And the output is:

sum(2,4,6,8)=20

We may limit our output using top extension:

import system'routines;
import extensions'routines;
import system'math;

public program()
{
    new Range(1,100).filterBy:(i => i.mod:2 == 0).top:10.forEach:printingLn
}

The result will be first 10 even numbers:

2
4
6
8
10
12
14
16
18
20

We may combine several enumerable objects into a single collection using zip:by extension:

import extensions;
import system'routines;
import extensions'routines;

symbol list = new string[] {"a","b","c","d"};

public program()
{
    list
       .zipBy(new Range(1, list.Length), (ch,i => i.Printable + " - " + ch.Printable))
       .forEach:printingLn
}

And the output is:

1 - a
2 - b
3 - c
4 - d

where (ch,i => <...>) is a lambda closure with two parameters

selectBy extension can be used generate a new collection based on previous one. orderBy extension will sort a collection:

import extensions;
import system'routines;
import extensions'routines;

public program()
{
    var list := new Range(1,5).selectBy:(n => randomGenerator.nextInt(100)).toArray();
    
    console.printLine("sort(",list,")=",list.orderBy:(p,n => p < n))
}

The result will be a randomly generated list of numbers, ordered in assenting order:

sort(50,94,40,78,93)=40,50,78,93,94

groupBy may be used to group the enumeration members into a sub collections:

import extensions;
import system'routines;
import extensions'routines;

public program()
{
    var list := new Range(1,20).selectBy:(n => randomGenerator.nextInt(10)).toArray();
    
    list
        .groupBy:(x => x)
        .selectBy:(sub_list => 
                      sub_list.Key.Printable + ":" 
                      + sub_list.countMembers().Printable + " times")
        .orderBy:ifOrdered
        .forEach:printingLn
}

The code will count how many times a random number is encountered:

0:2 times
1:4 times
2:6 times
3:2 times
4:2 times
5:4 times
6:10 times
7:6 times
8:2 times
9:2 times

Dynamic dispatching, Generic handlers and Mixins

Let's start with a multi-methods. We may declare a several methods with the same name but with different signatures. It is also possible to declare an explicit multi-method dispatcher.

class MyClass
{
    // accepts the integer
    testMe(int n)
    {
        console.writeLine:"It is a number"
    }

    // accepts the string
    testMe(string s)
    {
        console.writeLine:"It is a string"
    }

    // default handler
    testMe(o)
    {
        console.writeLine:"Unsupported parameter"
    }
}

public program()
{
    object o := new MyClass();

    o.testMe(2);
    o.testMe("s");
    o.testMe(3l)
}

The output is:

It is a number
It is a literal
Unsupported parameter

In some cases opposite can be done as well, we may declare generic handlers which will accept any incoming messages:

import extensions;
 
class Example
{
    generic()
    {
        // __received is an built-in variable containing the incoming message name
        console.printLine(__received," was invoked")
    }
 
    generic(x)
    {
        console.printLine(__received,"(",x,") was invoked")
    }
 
    generic(x,y)
    {
        console.printLine(__received,"(",x,",",y,") was invoked")
    }
}
 
public program()
{
    var o := new Example();
 
    o.foo();
    o.bar(1);
    o.someMethod(1,2)
}

Output:

foo was invoked
bar(1) was invoked
someMethod(1,2) was invoked

We may declare a custom dispatcher which will redirect all unmapped incoming messages to another object effectively overriding it (some kind of dynamic mutation / code injection).

import extensions;

class Extender
{
    object theObject;
    
    // the injected property
    prop object Foo;
    
    constructor extend(o)
    {
        theObject := o
    }
    
    // redirect Object.Printable method to foo one
    get string Printable() => theObject;

    // custom dispatcher
    dispatch() => theObject;
}

public program()
{
    var o := 234;
  
    // adding a field
    o := Extender.extend(o);

    // setting a field value
    o.Foo := "bar";

    console.printLine(o,".foo=",o.Foo)
}

The output is:

234.foo=bar

The message may be dynamically dispatched.

class MyClass
{
    eval()
    {
       console.writeLine:"eval method"
    }                                                    

    state0()
    {
       console.writeLine:"state0 method"
    }
}  

public program()
{
   var o := new MyClass();

   var subj := __subj state0;  // a message name constant

   o.eval();

   mixin subj(o).eval()        // dynamically dispatching the message
}

The output is:

eval method
state0 method

Though ELENA does not support multiple inheritance, using custom dispatcher we may simulate it:

singleton CameraFeature
{
    cameraMsg
        = "camera";
}
 
class MobilePhone
{
    mobileMsg
        = "phone";
}
 
class CameraPhone : MobilePhone
{
    dispatch() => CameraFeature;
}
 
public program()
{
   var cp := new CameraPhone();
 
   console.writeLine(cp.cameraMsg);
   console.writeLine(cp.mobileMsg)
}

The output is:

camera
phone

Now let's create a mixin object:

import system'dynamic;
import extensions;
 
class Member1
{
    string theField := "member1 content";

    field = theField;
}

class Member2
{
    eval()
    {
        // NOTE : target is built-in variable referring to the mixin
        console.printLine(
           "printing the content of the group object:",
           __target.field)
    }
}

public program()
{
    var g := Group.load(new Member1(), new Member2());
    g.eval();
}

Output is:

printing the content of the group object:member1 content

 

More examples

You can get more examples and learn more about ELENA language in Rosseta Code:

http://rosettacode.org/wiki/Category:Elena

More articles about Elena programming language

Any question ?

Feel free to ask!

Who uses ELENA language and for what?

That is a question that has been on everyone's mind, when they see something about a new language .

Well, I use the language, and develop business programs in ELENA language

The programs that I developed in ELENA control all payments received by automakers banks such as Ford, GM, (Mercedes) Fundo Estrela, (Citroën and Peugeot) PSA Bank, (Fiat, Chrysler and used cars by Fiat) FIDIS Bank, this means that if you live in Brazil and bought a car from one of these manufacturers, their payment has been processed by a program written in ELENA.

And I wrote some prograns to Bradesco Bank and HSBC bank to process and generate payment data.

Open source projects in Elena

History

  • 9-Jan.19
    - Updated to be compatible with ELENA 4.0
  • 6-Aug-18
    - Adding new topics : working with enumerable objects, mixins
  • 13-Jun-18
    - Updated to be compatible with ELENA 3.4
    - fixing spelling
  • 26-Jun-17
    - Added community group
  • 19-Jun-17
    - Added new version of compiler to download
  • 09-Jun-17
    - Updated all the article to the new version of Elena language
    - Added the new release of elena langauge to download
    - Added section "if-else template"
    - Added section "Open source projects in Elena"
  • 17-Jan-17
    - Added link to the new Elena article in Code Project
  • 12-Dec-16
    - Updated elena compiler to the last version
  • 22-Sep-16:
    - Added link to rosseta code
  • 12-Sep-16:
    - Article created

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0

Share

About the Authors

No Biography provided

Alex Rakov
Software Developer (Senior)
Russian Federation Russian Federation
No Biography provided

You may also be interested in...

Comments and Discussions

 
QuestionCreado para mayor seguridad Pin
Agustín Cordero15-Feb-19 2:14
memberAgustín Cordero15-Feb-19 2:14 
QuestionWith the opportunity to create a new language, why did you make it so C like? Pin
Member 1414149815-Feb-19 0:29
memberMember 1414149815-Feb-19 0:29 
AnswerRe: With the opportunity to create a new language, why did you make it so C like? Pin
Alex Rakov15-Feb-19 2:28
memberAlex Rakov15-Feb-19 2:28 
GeneralRe: With the opportunity to create a new language, why did you make it so C like? Pin
Member 1414149815-Feb-19 16:26
memberMember 1414149815-Feb-19 16:26 
SuggestionArticle is still written as if the language is just created Pin
City17Citizen14-Jan-19 1:05
professionalCity17Citizen14-Jan-19 1:05 
GeneralRe: Article is still written as if the language is just created Pin
Alex Rakov14-Jan-19 1:23
memberAlex Rakov14-Jan-19 1:23 
GeneralRe: Article is still written as if the language is just created Pin
Agustín Cordero15-Feb-19 2:32
memberAgustín Cordero15-Feb-19 2:32 
QuestionI enjoy reading this article. Pin
Member 1361276610-Jan-19 7:22
memberMember 1361276610-Jan-19 7:22 
QuestionA bit busy for new languages Pin
Michael Breeden7-Aug-18 8:28
memberMichael Breeden7-Aug-18 8:28 
AnswerRe: A bit busy for new languages Pin
Alex Rakov7-Aug-18 10:23
memberAlex Rakov7-Aug-18 10:23 
AnswerRe: A bit busy for new languages Pin
Member 1414149815-Feb-19 16:18
memberMember 1414149815-Feb-19 16:18 
QuestionSyntactical Mutt Pin
Richard Eng15-Jun-18 12:32
memberRichard Eng15-Jun-18 12:32 
AnswerRe: Syntactical Mutt Pin
Alexandre Bencz12-Jul-18 1:08
memberAlexandre Bencz12-Jul-18 1:08 
GeneralRe: Syntactical Mutt Pin
foo210010-Jan-19 1:51
memberfoo210010-Jan-19 1:51 
QuestionThere's another Elena language Pin
Richard Eng15-Jun-18 5:45
memberRichard Eng15-Jun-18 5:45 
AnswerRe: There's another Elena language Pin
Alexandre Bencz12-Jul-18 1:09
memberAlexandre Bencz12-Jul-18 1:09 
GeneralRe: There's another Elena language Pin
Richard Eng13-Jul-18 8:43
memberRichard Eng13-Jul-18 8:43 
QuestionElena is not the better Smalltalk; Pharo is Pin
Nathan James14-Jun-18 20:03
memberNathan James14-Jun-18 20:03 
AnswerRe: Elena is not the better Smalltalk; Pharo is Pin
Alex Rakov14-Jun-18 21:31
memberAlex Rakov14-Jun-18 21:31 
GeneralRe: Elena is not the better Smalltalk; Pharo is Pin
Nathan James15-Jun-18 5:29
memberNathan James15-Jun-18 5:29 
QuestionYet another programming language?? Pin
joreyesm14-Jun-18 17:14
memberjoreyesm14-Jun-18 17:14 
QuestionSo what are the advantages? Pin
Galatei14-Jun-18 11:26
memberGalatei14-Jun-18 11:26 
AnswerRe: So what are the advantages? Pin
Alex Rakov14-Jun-18 21:26
memberAlex Rakov14-Jun-18 21:26 
GeneralRe: So what are the advantages? Pin
Galatei14-Jun-18 21:55
memberGalatei14-Jun-18 21:55 
AnswerRe: So what are the advantages? Pin
Alex Rakov14-Jun-18 22:17
memberAlex Rakov14-Jun-18 22:17 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web02 | 2.8.190214.1 | Last Updated 14 Feb 2019
Article Copyright 2016 by Alexandre Bencz, Alex Rakov
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid