Category:Elena: Difference between revisions

From Rosetta Code
Content added Content deleted
No edit summary
mNo edit summary
 
Line 12: Line 12:
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.
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.


* ELENA on [https://github.com/ELENA-LANG/elena-lang/wiki/ Github]
== 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 ==
* ELENA on [https://github.com/ELENA-LANG/elena-lang/ Github]
* ELENA on [https://www.reddit.com/r/elena_lang/ Reddit]
* ELENA on [https://www.reddit.com/r/elena_lang/ Reddit]

Latest revision as of 07:31, 4 September 2019

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.

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)