Tuesday, September 25, 2012

ELENA 2012: Interaction with Objects - External roles

Being a dynamic language ELENA allows to override the object methods in run-time. This feature is called a dynamic mutation (both permanent and temporal). It is done with a help of a generic handler. The generic handler is a special type of the class which handles all incoming messages (physically it is a special VMT with the single entry) and may modify the incoming message or its target. Let's consider a group handler. The group handler is a an array of objects which may be considered as a single one, i.e. they share a common instance reference (SELF variable). Actually we override SELF variable dynamically. As a result SELF variable may no longer always point to the current class instance. That's why in ELENA there are two instance reference: SELF (a "virtual" reference to the current object) and $SELF (a "static" reference to the current object). In normal case both SELF and $SELF are equal. But if the object becomes a part of the group, SELF points to the group and $SELF to the object itself. This feature is actively used in external roles.

An external role is a set of additional methods which can extend existing classes without inheriting them (roughly similar to C# extension methods). They are actively used in LIB27 to implement additional functionality which is not considered to be essential to the class (the concept of "poor" interface). For example std'patterns'ForEach is used to enumerate a collection:

#var aList := List += 1 += 2 += 3.
__group(ForEach, aList enumerator) run: 
 anItem = ('program'output << anItem << "%n")

where we dynamically extends an enumerator with ForEach functionality - ability to execute a code for each member of the collection.

Note that we actually do not need to make this mutation permanent. After all in different part of the code the different functionality may be required. So to follow "just in time functionality" concept we could rewrite this code using a wrap group:

__wrap(ForEach, aList enumerator) run: #symbol PrintingLn.

Let's examine this code. __wrap is a group handler which combines the interface (ForEach role) with a content (a collection enumerator) in such a way that incoming messages are redirected to the interface while SELF variable points to the content. Actually we create (just in time when we need it) a new temporal object (so it can be called a temporal mutation) which hides the content object behind the interface (wrap the content in the interface). Instead of nested symbol we could reuse already existing symbol (ext'patterns'PrintingLn).

The code above could be simplified by using extension operator:

aList enumerator ~ForEach  run:#symbol PrintingLn.

Lety's use a factory-symbol NewEnumerator to make it more generic:

NewEnumerator::aList ~ForEach  run:#symbol PrintingLn.

Note that this code will work for an array as well:

aList := (1,2,3).
NewEnumerator::aList ~ForEach  run:#symbol PrintingLn.

External roles can be used both stand-alone or with an argument list:

'program'output write &numeric:9000 &radix:2 &:eintformatter << "%n".

This code is equivalent to the following one:

'program'output write:
   __group(eintformatter, { numeric = 9000. radix = 2. }).

Note that in this could we actually parameterize EIntFormatter, i.e. dynamically extend it with "just-in-time" defined parameters.

Thursday, September 20, 2012

ELENA 2012: Interaction with Objects

As in the most of dynamic object-oriented languages the main way to interact with objects in ELENA is sending a message. Unlike others there are only limited set of possible message names (verbs, e.g. add, set, get, run, seek and so on). Though it is possible to provide the message namespace (subject). The message may contain a parameter (otherwise nil symbol is passed). When several parameters should be passed an argument list can be declared. If the object want to handle the message it has to contain the method with the same name. If no method mapping was found the flow is considered to be broken and the control goes to the next alternative flow or the program is stopped. Some generic messages (verbs without subjects) have alternative names (operators) which have a different parsing order.

The simple code to send a generic method looks like this:

'program'output write:"Hello World".

Note: "write" is a generic message, a literal constant is a parameter.

Several messages can be send in one statement, the parameter itself may be result of object interactions:

'program'output write "2 + 2 =" write:(2 add:2).

We could use operators to have the shorter code:

'program'output << "2+2=" << 2 + 2.

Note: "<<" is a synonym to "write" and "+" to "add".

Generic messages is used if we apply the operation to the whole object, if we need to work with a part of the object (roughly similar to a class property) we have to use qualified message.

'program'output << """Hello world"" contains " 
   << "Hello world" std'dictionary'length'get << " characters".

This code can be simplified. If the subject module is already defined at the source code beginning, its namespace may be skipped. Secondly in "get" messages (if the parameter is not provided) the verb part can be omitted:

#define std'dictionary'*.


'program'output << """Hello world"" contains " 
   << "Hello world" length << " characters".

In all examples above we use only a single parameter. But what to do if we need to pass several ones? The simple solution would be to create a special objects which will aggregate these parameters - argument list:

aDictionary append: { dictionary_key = "foo". content = "bar". }.

Note that the target object should interact with the parameter to get required data, hence the parameter becomes an active part of the interaction (this feature can be used in method multiple dispatching for example).

We could use a stack allocated argument list and simplify the code:

aDictionary append &dictionary_key:"foo" &content:"bar"

To be continued...

Wednesday, September 12, 2012

New Release ELENA 1.7.16: Language Reloaded

For the past several months I was busy with refactoring the language. Now the work is practically done (except several GUI samples) and in the next several posts I will describe the latest language specification.

The most significant changes were made for the language messaging system. Old style dispatching (which was applicable only for the small number of cases), argument signature were discarded, syntax was changed and several new features were added.

Another point of changes is a dynamic programming. It was completely overwritten.

Actions symbols were discarded. The symbol reference (both nested and explicit) should be used.

Stack allocated objects were introduced for nested symbols and argument lists.

Changes were made for control flow statements (new #until loop statement).

The code was moved to a new library: LIB27.

Wednesday, August 15, 2012

Work In Progress: ELENA 2012

Since my last post there were several significant changes in both the code and the language that upcoming version (1.7.16) may be called ELENA 2012. First of all I made a deep redesign of ELENA VM bytecodes to make them more generic. Efforts were made to reduce the number of VMTs (in the previous versions practically every argument list or action symbol has its own VMT). Multi-dispatching mechanism was changed (though some efforts should be applied to optimize the current implementation). Another significant language change was in the argument list syntax. As a result the whole code base should be rewritten (the process is not over yet) so the new language API will be called LIB27. There will be significant changes in dynamic programming as well (the work still in progress)

To name few changes:
  • multi-dispatching (subj hint is obsolete, argument list dispatcher should be used )
  • argument list extender and dispatcher
  • it is no longer possible to auto determine the message subject by an argument list
  • embedded symbols
  • constructor (new verb is no longer supported)
  • #role keyword is no longer supported - #class should be used instead
  • #try keyword is no longer supported - #if should be used instead
  • stack allocated objects (argument lists and action symbols)
Because of the amount of the work I made a decision to release a current version as 1.7.15b (which is still unstable, some key features is missing, not all the code migrated). As a result a first Linux alpha version will be release probably in a new year.

To be continued...

Wednesday, June 20, 2012

ELENA: work in progress

Some time has passed since my last record so I decided to post on the current work status.

Finally I started efforts to migrate the compiler to Linux platform in hope that it may ignite some interests in the project (though I don't hold my breath, people are conservative). I was asked when Linux version will be available. Though it has a low level priority I do hope to release an alpha version till the end of this year (compiler + console samples). Currently I struggle with finding a right balance between UTF8 (which is Linux default encoding) and UTF16 (which is ELENA engine standard). So it may take some time. Another point of concern is a lack of documentations (I found the same questions more often than the answers) comparing to Windows platform.

I'm in the middle of major changes in ELENA script engine. ELENASM is rewritten and now supports two parsing methods - CF (non-deterministic context-free parser) and LALR. It will be possible to provide the middle layer.

Some changes were made in group objects as well. __action is gone (new group object - __symbol should be used instead) and __batch routine was modified (I will post on it after 1.7.12 release).

I'm finishing the migration from LIB25 to LIB26.

There were some syntax change (#while should be used instead of #loop) and a new #sync statement (to be used in multi-threading programming, though it is still an early alpha). Some IDE debugger bugs are fixed (step over the symbol with a parameter issue).

After a while I decided to stop making "weekly" release and switched back to "monthly" ones (sometimes there were nothing actually to release).

So in general the work is in progress and to be continued :)

Friday, March 30, 2012

Getting Started: ELENA DSA Script, part 2

In the previous post I showed how to create a pure dynamic code combining different group objects with each other without actually writing the code. So Hello world program will look like this:

&eval &nil sys'dynamics'castvariable 
  &nil sys'dynamics'batch
     &sys'vm'routines'ereturnprop "Hello World" &wrap 
        ~sys'dynamics'group_member ^append
     &write &nil 'program'output &wrap 
       ~sys'dynamics'group_member ^append
     ~sys'dynamics'group_member ^append 
  &get &nil 'program'input &wrap
  ~sys'dynamics'group_member ^append 
&wrap &nil ^eval

which is equivalent to the following ELENA code:

__wrap(__eval, __cast(
         __batch(__wrap(sys'vm'routines'ereturnprop, "Hello World"), 
                 __wrap(__write, 'program'output)),
         __wrap(__get, 'program'input))) eval.

In this example we use another group object - cast. A cast collection repeats a received message for every its member.

Inline script is not intended for direct usage so we should use a grammar. We could use a grammar script provided in the language - default.vl2

Let's start VM terminal


Now we may load existing grammar scripts with a command - c


Now let's start a VM


Our program consists of two actions - printing a message and waiting for any key. So let's assign a variable output and input to these actions

output = [ sys'vm'routines'ereturnprop->"Hello world" 
            write->'program'output ]
input = get -> program'input

And combine them into the program

action = < output input >
program = eval->action

So now we could execute our program


As you see with a help of the grammar our program becomes much simpler. The grammar is quite simple

a -> b 

creates a wrap,

[ ... ] 

creates a batch,

< ... > 

create a cast

variable =  

assigns the expression to the variable, and


sends a message verb to obj

Monday, March 19, 2012

Getting Started: ELENA DSA Script

In the previous tutorial I showed the usage of experimental VM script engine. The main purpose of the script is to create a dynamic code without recompiling the application. But there is a disadvantage: the script is imperative rather than object-oriented. Now I will show how could we create a new code by combining different group objects with each other - actually assembling the object.

But before we start I will shortly describe the group / role types we will use:

As you may remember a message consists of a subject and a verb. The subject should be declared explicitly. Every time a new subject is declared the appropriate symbol is declared as well (it is used to invoke this subject). On the other hand the verb is built-in. Starting from 1.6.13 for every verb there is a special role (e.g. for get - __get) which can be used to convert this verb to "invoke" one and vice versa.

Wrap is a special group which uses the first member of the collection as a wrapper around the second one (content). It means that only the wrapper methods are invoked but "self" variable is assigned to the wrap content (so it could be called as a temporal mutation). We will use wraps with subject symbols and verb roles.

Let's practice with wraps. First of all we will need to start VM terminal. As I told in the previous tutorial VM should be start so we could use a simple script to do so - newconsole. Let's go to BIN folder and type the following command:

elt.exe -Ninlinescripts\newconsole.vl

Now I will show how to use wrap to invoke subject - for example a string length (std'dictionary'length):

-Ninline &nil 'program'output 
   &std'dictionary'length  "abc" &wrap &nil ^get ^write

This is similar to the following "traditional" code:

'program'output << __wrap(std'dictionary'length, "abc") get.

Let's try to understand how the code is working.

The wrap group object redirects the message (GET in our case) to its first member (std'dictionary'length) while assigning SELF variable with its second member ("abc") - actually wraps a literal constant in a subject role. The subject role in its turn appends the appropriate subject (std'dictionary'length) to the sent message (GET) and redirects it to SELF ("abc"). As a result

__wrap(std'dictionary'length, "abc") get

is translated into

"abc" std'dictionary'length'get

Now let's use a verb role to make our code completely dynamic

-Ninline &nil 'program'output 
    &get &std'dictionary'length "abc" &wrap &wrap &nil ^invoke 

which is similar to

'program'output << 
   __wrap(__get , __wrap(std'dictionary'length, "abc")) invoke.

In this code we add an additional wrap with GET verb role and use a generic verb - invoke. When a verb role receives INVOKE message it converts it to GET and redirects to SELF - the second wrap. As a result we have a previous case.

Now let's look at another group object - BATCH. Batch a is collection which redirects sent message to every its member, passing the result of the previous operation as a parameter of the next one.

Let's once again modify our sample:

-i &nil sys'dynamics'batch 
   &get &std'dictionary'length  "abc" &wrap &wrap 
      ~sys'dynamics'group_member ^append 
   &write &nil 'program'output &wrap 
      ~sys'dynamics'group_member ^append 
&nil ^invoke

which is similar to

__batch(__wrap(__get , 
    __wrap(std'dictionary'length, "abc"), 
    __wrap(__write, 'program'output)
) invoke

Unlike the wrap, a batch does not have a script engine built-in identifier so we have to use sys'dynamics'Batch class to create a collection. ~sys'dynamics'group_member ^append is used to append the created wrap to the batch.

Our batch collection consisting of two wraps: the one we use to get the literal length and a new one, which is used to send the parameter to the console output. So let's look into our code once again. We send INVOKE message with NIL as a parameter to the batch. The batch redirects the message to its first member which returns the literal length and then sends INVOKE again to the next member but this time the parameter is a literal length. The wrap converts INVOKE into WRITE and redirects it to the console output as a result we prints the literal length.

Monday, March 12, 2012

Getting Started: ELENA Script

Now let's try to write a simple script.
First of all let's discuss what is ELENAVM script. Any ELENA source code is compiled into bytes codes (ecodes) and interpreted by a virtual machine (ELENAVM). It is the case even for a stand-alone application. So ecodes could be considered as a low level code and objects written in ELENA as a high level one. But above them there is another layer - ELENAVM inline script. It is in fact set of instructions how to assemble the objects in the virtual machine memory. With it help we could interact with ELENAVM directly. And finally we could add another layer which we could call ELENA script - it is a grammar rules how to generate ELENAVM inline script basing on a user defined syntax (DSA rules).
+    ELENA    +
+    script   +
+   ELENAVM   +
+    inline   +
+    script   +
+    ELENA    +
+ source code +
+   ecodes    +
+ native code +
The simplest way to work with ELENAVM is to call a VM terminal - ELT.
First of all let's start VM:
-Ninline @config win32_vm_console2 @start
(command "-Ninline" executes ELENAVM inline script directly without using any grammar; @config loads the project template; @start starts VM)
Now we could directly print the welcome message:
-Ninline &nil 'program'output "Hello World" ^write
Let's try to understand how it works. To print the message we have to load 'program'output symbol and a string constant into the stack and then send a message (the similar we did in the previous tutorial). A symbol call expects a parameter in the stack (or nil if it is not required), that's why we put &nil symbol first (note: "&" symbol indicates a constant and therefore it is not a call but writing into the stack). Then the literal constant follows (writing into the stack as well). Now we have a two objects in VM stack - 'program'output (actually sys'io'consoleoutput) and std'basic'wideliteral - and can invoke a message (the message is sent to the previous stack item with the current one as a parameter) with a command ^ write. After the message is executed the parameter is removed from the stack.
Alternatively we could provide a grammar rules to parse a user defined script (ELENA script). Let's start with defining a simple context free grammar rules (only aA, a, A, AB and $eps rules are allowed).
start ::= "?" print;
print ::= $literal;
(Note: $literal is a terminal mask accepting any literal constant)
Then we need a DSA rule to build proper inline script.
print => &nil 'program'output $terminal $body ^write;
(Note: $body is place holder where appropriate rule content is inserted - in our case it is a literal constant, $terminal defines the place where the parsed value should be inserted ).
Now let's end the CF grammar definition mode
Now try simple expression:
? "Hello World!!"
To see how script is translated into the VM instructions let's turn on tracking mode
And repeat the command:
? "Hello World!!"
We will see the code similar to our previous one:
@push $elena'nil
@call 'program'output
@push "Hello World!!"
@send write
Let's turn the tracking off
The script engine can be used to execute programs as well.
First let's provide the path to our module:
-Ninline @use "..\examples\helloworld"
And now let's execute it:
-Ninline &nil helloworld'program &nil ^eval
(Note: the program should be already compiled)
Our inline script is the same as a previous one except that we do not need a parameter that's why nil is used second time as well.

Friday, March 9, 2012

Getting Started: Hello World

This tutorial will discuss how to write a simple program.

First of all we have to create a new project - File - New - Project.

The project setting dialog will be displayed. Let's fill the form:

  • Type - win32console (it is a console application)
  • Target file name - helloworld (it is a name of the executable file)
  • Debug mode - Enabled (if we would like to have a possibility to debug the code)

The rest can be leaved blank.

Now let's create a program file - File - New -Source File.

And finally let's save all changes - File - Save All.

IDE will ask to include the file into the project.

Our program will be simple:

Program =>
 'program'output << "Hello word!!%n".

But we still have to tell the compiler which symbol should be used as a program body. To do so we have to provide the forward reference - Project - Forwards.

In open forward dialog we have to type the entry mapping:

'program'action = helloworld'program

And press Add and Save.

Now let's compile the project - Project - Compile.

We could run the program - Debug - Run.

After the program is finished the console window is closed so we do not see actually the program output. So let's add the code to wait until any key is pressed:

Program =>
 'program'output << "Hello word!!%n".
 'program'input get.

Now let's take a look at our code. 'program'output symbol is a console text writer supporting basic standard types: literal and numeric values. Leading apostrophe indicates that this a forward declaration. The forward symbol should be resolved during the program linkage. This reference is resolved in win32_console project template and is mapped to sys'io'consoleoutput. 'program'input is a console text reader.

Wednesday, February 1, 2012

Dynamic Programming in ELENA

Last year I demonstrated how to create BF interpreter without writing any program. But to implement a loop I still had to create a new class (in runtime). After a while I realize that it is possible to get rid of auto code generation completely, using only special group types (except for dynamic subjects).
Let's start with general overview of dynamic programming paradigm in ELENA. Instead of writing a code (with the help of run-time compilation or some built-in functionality) we could build (assemble) a new object reusing existing functionality. Subjects and built-in verb roles will allow us to create new methods and invoke them (without any kind of reflection mechanisms), different group objects (wrap, echo, cast, prop and action) will combine them to implement the program logic.
Presume we would like to create a dynamic code which will execute the following bf code: , [ . , ]
First of all we have to create a tape:
anIndexer := factory'NewArray::{ 
} @ 0.
Now we have to add a new dynamic method to the indexer which executes the loop until the current item is zero. So we create a group and add the indexer into it:
#var aGroup := sys'dynamics'GroupVariable 
                append &sys'dynamics'group_member: anIndexer
Our dynamic method will need its own subject:
#subject bfloop.
Let's create the method:
aGroup append &sys'dynamics'group_member:
   __prop(bfloop, __run, __wrap(EWhileNotZero, aGroup)).
In this code we use two types of group objects:__prop and __wrap. __prop is a property collection which consists of a subject symbol (bfloop), a wrapper (verb external role) and a content - another wrapper. The property converts a qualified message (bfloop'invoke) into a generic one (invoke) and sends it to a verb role. A verb role in its turn sends the appropriate message (run) to the property content (__wrap(EWhileNotZero, aGroup)). The created group is equivalent to the following code:
aGroup append &sys'dynamics'group_member: 
    bfloop'invoke : anAction = self~EWhileNotZero run:anAction. 
To implement input / output operations we will use the following actions:
#var anOutputAction := __wrap(__write, 'program'output).
#var anInputAction := __wrap(__save, __action(__get, 'program'input, nil)).
The "traditional" code looks like this:
#var anOutputAction :={ invoke : aGroup = 'program'output write:aGroup. }.
#var anInputAction :={ invoke : aGroup = 'program'input get save:aGroup. }.
Note that once again we use verb roles to translate invoke into write and save respectively. anInputAction is a bit more complicated. We need to implement the action before invoking save message. That's why another special group - __action - is used.
And finally we combine these actions:
         __wrap(__eval, __cast(anOutputAction, anInputAction)))
) invoke:aGroup.
Which could be translated into the following code:
   invoke : aGroup =  
      aGroup invoke &bfloop:__cast(anOutputAction, anInputAction) 
}) invoke:aGroup.
As you can see we were able to create an object with a custom method without actually declaring a new class. Of course this approach is not suited for programmers but it could be used for automatic code assembling inside the program in run-time, for example in ELENAVM script:
tape       =>
              // 1: append
              // 2: goto
              // 3: loop
              // 4: inc action
              &1 1 &echo
              // 5: dec action
              &1 -1 &echo
              // 6: next action
              &2 1 &echo
              // 7: prev action
              &2 -1 &echo
              // 8: output action
              &__write &nil 'program'output &wrap
              // 9: group
              &std'basic'factory'array_size &sys'vm'routines'egetprop 1024 &prop
              &std'basic'factory'pattern &sys'vm'routines'egetprop 0 std'basic'widecharvar &prop
              0 ^refer 
              ~ sys'dynamics'group_member ^append
              // :: append method
              &1 &__append &9 &prop
              ~ sys'dynamics'group_member ^append
              // :: goto method
              &2 &__append &std'dictionary'index &9 &wrap &prop
              ~ sys'dynamics'group_member ^append
              // :: loop method
              &3 &__run &std'patterns'ewhilenotzero &9 &wrap &prop
              ~ sys'dynamics'group_member ^append
              // 10: in action
              &__save &__get &nil 'program'input &nil &action &wrap
              // build command batch
              ^ invoke;
inc        => &4 |= $body;
dec        => &5 |= $body;
next       => &6 |= $body;
prev       => &7 |= $body;
out        => &8 |= $body;
in         => &10 |= $body;
while      => &3 &__eval &cast $body &wrap &echo |=;

Thursday, January 5, 2012

New Group Types

The latest 1.6.12 release contains several critical changes in the way how the language works with group objects and subjects. In this article I will cover some of these changes.

First of all I made several cosmetic changes: the class extension keywords - #annex and #union were renamed to #join and #outer respectively. Group keywords #group, #union and #cast are no longer supported, built-in classes should be used instead. And a generic handler (#generic) was added.

Detailed discussion we will start with class extensions: #join expression. #join extension can be used both inside the class declaration and as a part of the inline (nested) class expression.

#class MyClass

    #join EMyExtension.

If the keyword is followed by an external role (or a stateless class) it is used for "horizontal" inheritance. It is roughly similar to the multiply interface inheritance (note that the class "parents" should not have their own fields).

#class MyIndexer
    #field theItem.


    #join theItem.

But the joining expression can be a normal object (e.g class field) as well. In this case it is similar to the group object and is used for run-time extension (permanent dynamic mutation). For example it is used in ELENA indexers to extend the collection item with navigating functionality. Note that in both cases "self" built-in variable refers to the extended class instance (so it is similar to a group object).

'program'output << #join(anObject) { literal = "object:" + anObject literal. }.

In this case the inline class declaration can be used as well.

Now let's go to #outer (join) extension.

#class Variable
    #field theValue.

    #method content = theValue.

    #method content'set : aValue
        theValue := aValue.

    #outer theValue.

Outer join extension can be used only inside the class declaration and in most cases is used with objects. The main difference with join extension is that "self" variable is not overridden. This type of extension is used mostly in containers (a dynamic variable).

#class MyClass

        'program'output << "My class does not support this method".
        $self fail.

#generic extension is a special method which is called for any unhandled message.

Now let's go to the main topic of this article: group objects. We will start an implicit group object. Before I will continue let me remind you what is ELENA group object: a collection of the objects accessible through the common instance reference (see here).

#var aSecond := aList~EItem @ 1.

A group object is used to dynamically extend the existing object with a new functionality (some kind of mutation). For example in this case we extends the collection with an ability to return the collection member by index. A group can be temporal if the group is immediately followed by a message and the mutator is an external role or a stateless class.

The group can be created explicitly with a help of built-in class - __group.

#var anExtendedList := __group(EItem, aList).

Note that in this case the group is always permanent.

Another way to temporal extend the object is a wrap group (__wrap built-in class)

#var aStr := WideStrValue::__wrap(EInt32Variant, aNumber).

A wrap is a special group which uses the first member of the collection as a wrapper around the second one (content). It means that only the wrapper methods are invoked but "self" variable is assigned to the wrap content. In most cases the wrapper object should be a role or a stateless class. Note that a wrap should have only two members.

Before we will continue with other group types, let me say a few words about subjects. As you may probably know in ELENA language the message consists of message subject (actually a message namespace) and a message verb (built in list of names such as get, set, add, append and so on). A subject should be declared before use. Simultaneously a special symbol (named expression) with the same name is declared. Due to this the program could handle a subject like any other program element (without any kind reflection).

#var aProp1 := aObject subject'get.
#var aProp2 := anObject~subject get.
#var aSubj := subject. #var aProp3 := __wrap(aSubj, anObject) get.

Both these expressions are equivalent but in the third case actually a variable referring to the subject symbol is used.

A special case of the wrap group is a property collection (__prop built-in class)

Compare these two equivalent expressions:

#class egetadapter
    #method get = self.


#var anArray1 := NewArray::{ &array_size:1024 }.

#var anArray2 := NewArray::__prop(array_size, egetadapter, 1024).

The property collection consists of a subject symbol, a wrapper and a content. When a message is sent to the collection the property handler checks its subject and if it is equal to the property subjects the generic message (only the message verb) is sent to the wrapper with "self" variable assigned to the wrap content. As you may see the property collection is similar to the "traditional" class property. Note that in this case no new class is declared and the subject could be dynamic.

And our final group type is a union (__union). Union (similar to outer class extension) could be considered as a collection of dynamic variables.

#var anArray1 := NewArray::{ &array_size:1024 &pattern:integer::0 }.

#var anArray2 := NewArray::__union(__prop(array_size, egetadapter, 1024), __prop(pattern, egetadapter, integer::0)).