Category:Elena

From Rosetta Code
Revision as of 09:24, 6 January 2019 by rosettacode>Arakov
Language
Elena
This programming language may be used to instruct a computer to perform a task.
Official website
Execution method: Compiled (bytecode)
Garbage collected: Yes
Type safety: Safe
Type strength: Strong
Type expression: Implicit
Type checking: Dynamic
See Also:
Listed below are all of the tasks on Rosetta Code which have been solved using Elena.


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

The simplest program

To create a simple console program we have to declare the public **program** closure in the project root namespace:

   public program()
   {
   }

Everything in ELENA is an object. To interact with it we have to send a message. The message consists of *an action* and a *parameter list*.

The statement should be terminated by a semicolon.

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

In our example the action is **writeLine** and the parameter list consists of a single string constant. The message target is **console** object (implementing input / output operations with a program console).

Several message operations can be done in a single statement:

   public program()
   {
       console.writeLine("Hello!").writeLine("How are you?");
   }

The result will be:

    Hello!
    How are you?

We may read a user input by sending **readLine** message without parameters:

   public program()
   {
       console.write("What is your name:").writeLine("Hello " + console.readLine())
   }

The result will be:

   What is your name:Alex
   Hello Alex
    • Console::write** method is similar to **writeLine** except that it writes to the output screen without a new line character.

Declaring a variable

A variable can be declared in an assignment statement starting with **var** attribute:

   var myVariable := "A text";

where we declare a variable **myVariable** and initialize it with a string constant value.

The assigning value can be an expression itself:

   public program()
   {
       console.writeLine("Hello!").writeLine("How are you?");
       var s := console.readLine()
   }

ELENA is a dynamic language and in most cases we may not specify the variable type:

   public program()
   {
       var s := "Hello";
       console.writeLine(s);
       s := 2;
       console.writeLine(s);
   }

The output will be:

   Hello
   2

But it is possible to specify the variable expected type:

   String s := "Hello";
   console.writeLine(s);
  • where system'String is a class representing text as a sequence of UTF-8 characters.*

We may use a class alias to simplify the code:

   string s := "Hello";  // string is a String class alias
   console.writeLine(s);

ELENA does not enforce types in compilation-time, so the following code will be successfully compiled:

   string s := "Hello";
   s := 2;

But it will raise an exception in the run-time:

   system'IntNumber : Method #cast[0] not found
   Call stack:
   system'Exception#class.new[1]:exceptions.l(125)
   system'MethodNotFoundException#class.new[2]:exceptions.l(236)
   system'$inlineC.start[0]:win32_app.l(313)
   mytest'program.#invoke[0]:test.l(5)
   system'$inlineC.start[0]:win32_app.l(39)
   system'#startUp:win32_app.l(52)

As you may see, the compiler injects the typecasting code, so the actual code looks like this:

   string s := "Hello";
   s := cast string(2);
  • where* **cast string(2)** *is a construction to typecast the target expression* - **a numeric constant** - *to the expected type* - **System'String**

As a result if the object supports casting method the operation will work. For example, system'IntNumber can be implicitly converted into system'RealNumber so the following code:

   public program()
   {
       real r := 2;
       console.writeLine(r)
   }
  

will be successfully executed with the result:

   2.0

Basic Types

The Boolean Type

Boolean type is used in conditional operations and may accept only two Boolean literals - **true** and **false**.

   import extensions;
   
   public program()
   {
       bool b1 := true;
       bool b2 := false;
       
       console.printLine(b1,"==",b1," is ",b1==b1);
       console.printLine(b2,"==",b2," is ",b2==b2);
       console.printLine(b1,"==",b2," is ",b1==b2);
       console.printLine(b2,"==",b1," is ",b1==b2);
   }
  • Note that implicit extension method - **extensions'outputOp.printLine[]** - was used to simplify the output operations.*

The output is:

   true==true is true
   false==false is true
   true==false is false
   false==true is false

The Numeric types

The most used numeric types in ELENA are 32-bit signed integer number (represented by **IntNumber**), 64-bit signed integer number (represented by **LongNumber**) and 64-bit floating-point number (represented by **RealNumber**):

   import extensions;
   
   public program()
   {
       int  n := -234;
       long l := 1235456765l;
       real r := 2.3456r;
       
       console.printLine("Integer number - ",n);
       console.printLine("Long integer number - ",l);
       console.printLine("Real number - ",r)
   }

The output is:

   Integer number - -234
   Long integer number - 1235456765
   Real number - 2.3456

The String Type

    • String** is used to store the text encoded in UTF-8. String is a read-only collection of **CharValue** classes each representing UTF-32 symbol. *Note that one character may be encoded with more than one byte!*.
   import extensions;
   
   public program()
   {
       var s := "Hello";
       
       console.printLine("The first character of ",s," is ", s[0]);
       console.printLine("The last character of ",s," is ", s[s.Length - 1])
   }

The output is:

   The first character of Hello is H
   The last character of Hello is o

The same code for example with a Russian text will not work. Because every character is encoded with a two bytes and this should be taken into account.

   import extensions;
   public program()
   {
       var s := "Привет";
       
       console.printLine("The first character of ",s," is ", s[0]);
       console.printLine("The last character of ",s," is ", s[s.Length - 1])
   }

The output is:

   The first character of Привет is П
   An index is out of range
   Call stack:
   system'Exception#class.new[1]:exceptions.l(125)
   system'OutOfRangeException#class.new[1]:exceptions.l(156)
   system'OutOfRangeException#class.new[0]:exceptions.l(156)
   system'String.at[1]:memory.l(1243)
   mytest'program.#invoke[0]:test.l(8)
   system'$inlineC.start[0]:win32_app.l(39)
   system'#startUp:win32_app.l(52)

We may use another class representing UTF-16 text (**WideString**) to solve this problem:

   import extensions;
   
   public program()
   {
       var s := "Привет"w. // UTF-16 string
       
       console.printLine("The first character of ",s," is ", s[0]);
       console.printLine("The last character of ",s," is ", s[s.Length - 1]);
   }

The output will be correct this time:

   The first character of Привет is П
   The last character of Привет is т

But this code will not work with Chinese text or any other requiring more than 2 bytes per symbol. So instead we may use enumerators:

   import system'routines;
   import extensions;
   
   public program()
   {
       var s := "Привет";
       
       console.printLine("The first character of ",s," is ", s.FirstMember);
       console.printLine("The last character of ",s," is ", s.LastMember)
   }

The output will be correct for any UTF-8 text:

   The first character of Привет is П
   The last character of Привет is т

Array types

It is possible to declare a generic (_system'Array_) or strong-typed template-based (_system'Array#1_) array.

   import extensions;
   
   public program()
   {
       var strongTypedArray := new int[] {1,2,3};
       
       var genericArray := Array.allocate(3);
       genericArray[0] := 1;
       genericArray[1] := "b";
       genericArray[2] := 2.3r;
   
       console.printLine("strong-typed array ",strongTypedArray.asEnumerable());
       console.printLine("dynamic-typed array ",genericArray.asEnumerable());
   }

The output is:

   strong-typed array 1,2,3
   dynamic-typed array 1,b,2.3

Basic arithmetic operations

ELENA supports basic arithmetic operations with integer and floating-point numbers:

   import extensions;
   
   public program()
   {
       var n1 := 12;
       var n2 := 5;
       var n3 := -3;
       var r1 := 2.3r;
    
       console.printLine(n1, " + ", n2, " = ", n1 + n2);
       console.printLine(n1, " - ", n2, " = ", n1 - n2);
       console.printLine(n1, " * ", n3, " = ", n1 * n3);
       console.printLine(n1, " / ", n2, " = ", n1 / n2);
       console.printLine(n1, " + ", n2, " * ", r1 ," = ", n1 + n2 * r1)
   }

The result is:

   12 + 5 = 17
   12 - 5 = 7
   12 * -3 = -36
   12 / 5 = 2
   12 + 5 * 2.3 = 23.5

?? operator

Operator ?? is used to deal with nil.

_a ?? b_ - will return _a_ if _a_ is not _nil_ or _b_

See the following code:

   import extensions;
   
   public program()
   {
       var a := nil;
       var b := a ?? 0 + 2;
       console.printLine(a ?? "nil", " ?? 0 + 2 = ", b);
               
       a := 1;
       b := a ?? 0 + 2;
       console.printLine(a ?? "nil", " ?? 0 + 2 = ", b);
   }

The output is:

   nil ?? 0 + 2 = 2
   1 ?? 0 + 2 = 3

The operator can be used for typecasting operations as well:

_cast type(a) ?? b_ - will typecast _a_ to _type_ or return _b_ if it is not possible.

See the code:

   import extensions;
   
   public program()
   {
       string s := "a";
       var n := 2;
       
       console.printLine("cast int(",s,") ?? 0 = ", cast int(s) ?? 0);
       console.printLine("cast int(",n,") ?? 0 = ", cast int(n) ?? 0);
   }

The output is:

   cast int(a) ?? 0 = 0
   cast int(2) ?? 0 = 2

Conditions, Multi-select, Loops

Conditional statement in ELENA are defined as follows:

   if(<Boolean expression>)
   { 
      /* doSomething if TRUE*/ 
   }
   else
   {
      /*doSomehting if ELSE*/
   };

We could omit else part

   if(<Boolean expression>)
      { /*doSomehting if TRUE*/ };

Usually Boolean expression is a result of a comparison operation:

   public program()
   {
       console.writeLine("Hello!").writeLine("How are you?");
       var s := console.readLine();
       if(s == "good")
       { 
           console.writeLine("Me too") 
       }
       else
       {
           console.writeLine("What happends?")
       }
   }

Several conditions can be checked:

   public program()
   {
       console.writeLine("Hello!").writeLine("How are you?");
       var s := console.readLine();
       if((s == "good") || (s == "fine"))
       { 
           console.writeLine("Me too") 
       }
       else
       {
           console.writeLine("What happends?")
       }
   }

A switch statement can be implemented using => operator:

   public program()
   {
       console.writeLine("Hello!").writeLine("How are you?");
       var s := console.readLine();
       s =>
         "good"  { console.writeLine("Me too") }
         "fine"  { console.writeLine("Glad to hear") }
         "bad"   { console.writeLine("What's wrong?") }
         "so so" { console.writeLine("It happens") }
         :       { console.writeLine("What happens?") };
   }

We could declare *while* loop which will be repeated until the condition is true:

   public program()
   {
       console.writeLine("Hello!").writeLine("Guess what?");
       var s := console.readLine();
       while (s != "nothing")
       {
           console.writeLine("Guess what?");
           s := console.readLine();
       }
   }

Alternatively *until* loop is executed until the condition is met :

   public program()
   {
       console.writeLine("Hello!").writeLine("Guess what?");
       var s := console.readLine();
       until (s == "nothing")
       {
           console.writeLine("Guess what?");
           s := console.readLine();
       }
   }

ELENA supports C-styled *for* loop as well:

   public program()
   {
       for(int n := 0, n < 5, n += 1)
       {
           console.write("*")
       }            
   }

The output is:

   *****

_Note that comma is used instead of semicolon!_

  • doUntil* loop is similar to *for*, but the loop is executed at least once:
   var text := new StringWriter();
   doUntil(string line, line.isEmpty(), line := console.readLine())
   {
       text.writeLine(line)
   };

Classes, Fields Methods, Constructors

Everything in ELENA is a class. So to implement some tasks we will have to declare our own classes.

Declaring a simple class

Let's create a simple class :

   import extensions;
   
   class MyClass
   {
       // a field
       string myString;
   
       // an implicit constructor
       constructor(string s)
       {
           myString := s
       }
       
       // an explicit constructor
       constructor fromNuber(int n)
       {
           myString := n.toString();
       }
       
       // a method
       printString()
       {
           console.printLine(myString)
       }
   }
   
   public program()
   {
       // creating a class instance by sending new message to the class
       var myClass := new MyClass("This is printed by my class.");
       
       myClass.printString()
   }

The output will be:

   This is printed by my class.
  • Note that in ELENA a class is an object itself and can be used by like any other object*

Class Inheritance

We may inherit our class. When the parent is not explicitly declared - the class inherits *system'Object* super class

   import extensions;
   
   class MyParent
   {
       constructor new()
       {
           console.printLine("Parent Constructor.")
       }
   
       printMe()
       {
           console.printLine("I'm a Parent Class.")
       }    
   }
   
   class MyChild : MyParent
   {
       
       constructor new()
           <= new() // calling the parent constructor
       {
           console.printLine("Child Constructor.")
       }
       
       printMe()
       {
           // calling the parent method
           super.printMe();
           
           console.printLine("I'm a Child Class.")
       }
   }
   
   public program()
   {
       var myClass := MyChild.new();
       
       myClass.printMe()
   }

The output is:

   Parent Constructor.
   Child Constructor.
   I'm a Parent Class.
   I'm a Child Class.

Private methods

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()
   }

The output is:
   Calling from public print - private print.
   mytest'$private'MyClass : Method printPrivate[0] not found
   Call stack:
   system'Exception#class.new[1]:exceptions.l(125)
   system'MethodNotFoundException#class.new[2]:exceptions.l(236)
   system'$inline16.start[0]:win32_app.l(313)
   mytest'program.#invoke[0]:test.l(26)
   system'$inline16.start[0]:win32_app.l(39)
   system'#startUp:win32_app.l(52)

Properties

In normal case the class fields cannot be accessed outside the class. That's why we may declare special methods 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)
   }

The output is:

   MyClass.x=2

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

   import extensions;
   
   class MyClass
   {
       int _x;
       
       prop int x
       {
           get() = _x;
           
           set(int val)
           {
               _x := val;
           }
       }
   }
   
   public program()
   {
       var myClass := new MyClass();
   
       myClass.x := 2;
   
       console.printLine("MyClass.x=", myClass.x)
   } 

Simple accessors can be omitted:

   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")
       }
   }

The output is :

   Method not found

See also

Subcategories

This category has the following 3 subcategories, out of 3 total.

Pages in category "Elena"

The following 200 pages are in this category, out of 240 total.

(previous page) (next page)
(previous page) (next page)