Identifier definitions

Einen Identifier kann man auf verschiedene Weise erzeugen. Zu unterscheiden sind vier Typen

  • Gleichsetzung (alias, typedef, static const, enum, flag)
  • Definition einer Variablen/Member
  • Definition eines Typs mit Variablendefinition

Konstanten

Konstanten werden einfach mit '=' gesetzt:

a = 4;
b = int(4);
p = Point(1, 2, 3);

Point contains
{
  x, y, z is double;                 // Variablen
  
  construct( as x, as y, as z );
  
  Origin = Point( 0, 0, 0 );         // Konstante
}

statische Funktionen

…sind im Prinzip wie Konstanten, nur dass die Identifier von Parametern abhängig sind:

add( a, b is int ) = a+b;

Funktionszeiger

add( a, b is int ) = a+b;              // Konstante
addref is code( a, b is int ) (add);   // Variable

Typedefs

Typedefs entsprechen im Prinzip Konstanten, da sie statisch sind und nicht verändert werden können.

MyInt = int;
funcType = code( int a, int b) as int;

enums und flags

sind konstante Werte und werden direkt zugewiesen:

enum Color
{
  Rot   = 0xFF0000,
  Gruen = 0x00FF00,
  Blau  = 0x0000FF
};

Definitionen einer Variablen

Definitionen werden mit 'is' beschrieben Variabeln können im Gegensatz zu Konstanten überschrieben werden.

a is int;
t is type;
i is 0; // int
j is int(0); // int
p is Point( 1, 2, 3 );

alias

Aliase sind funktionsinterne Namen, bzw. Abkürzungen.

Auto contains
{
  Farbe, Hersteller;
  
  construct( f = .Farbe, h = .Hersteller ) :=
    print "Das neue Auto ist %s und wird von %s gebaut\n" % ( f%, h$ );
}

add( summand1 = s1, summand2 = s2 as int ) = s1+s2;

Typedef mit automatischer Variablendeklaration

Count is discrete int(4711);
int integer = 7328;

User contains
{
  Id   is discrete int;     // erzeugt den Typ User::Id, der von int erbt.
  Name is          string;  // einfache String-Variable
  
  staticValue = 0;
  
  construct( construct .Id, .Name ); // String wird 1:1 durchgeschleift, 
                                     // Id darf konstruiert werden, es dürfen also auch explizite
                                     // Konstruktoren von Id gerufen werden, z.B. Id( int )
                                     // Der erste Parameter muss auf einen Konstruktor von Id passen (also Id oder int)
                                     // Hat der Konstruktor mehrere Parameter, darf geklappert werden. Der Aufruf muss nicht Id( 1, 2) sein, 
                                     // sondern (1, 2) reicht, wenn er erste Parameter - eben (1,2) - auf einen Id-Construktor passt.
  {
    // nothing to do
    // Aufruf User( User::Id( 1 ), "Peter" )
    // Aber auch User( 2 /* da construct id */, "Gustav" );
    // auch User( integer /* da construct id */, , "Heinrich" )
    // NICHT User( Count, "Markus" ) // da Count discrete ist und Id keinen Konstruktor für Count hat
    
  }

  construct( .Id )
  {
    .Name : Id$;
    
    // Aufruf User( User::Id(2) ) ok
    // Aufruf User( cast 2 ), User( cast integer )
    // Aufruf User( cast Count ) // nicht ok, cast Count wäre z.B. int, aber es steht ist kein Cast für User::Id definiert. (müsste man erklären)
    // Aufruf User( 2 ) geht nicht, da Id kein int mehr ist und explizit konstruiert werden muss
    // Aufruf User( integer ), User( Count ) geht beides nicht
    // Aufruf User( User::Id( cast Count ) ) ok  // User::Id verlangt int, cast Count kann int liefern
  }
  
  construct( a is Id )  // Variable vom Typ Id
  {
    .Id   : a;     // Eventuell erst Standard-Konstruktor, dann operator =
    .Name : a$;
    
    // Aufruf User( User::Id(2) ) ok
    // Aufruf User( 2 ) nopes
    // Aufruf User( staticValue ) // nopes
    // Aufruf User( cast integer ),  // ok
    // Aufruf User( cast Count ) nopes
  }                            
  
  construct( a is Id )  // Variable vom Typ Id
  {
    .Id = a;     // Eventuell erst Standard-Konstruktor, dann operator =
    .Name = a$;
    
    // Aufruf User( User::Id(2) ) ok
    // Aufruf User( 2 ) nopes
    // Aufruf User( staticValue ) // nopes
    // Aufruf User( cast integer ),  // ok
    // Aufruf User( cast Count ) nopes
  }                            
  
};

Initialisierung

Der = Operator ersetzt die Initialisierungsliste. Das ermöglicht einen Programmablauf, bevor Membervariblen initialisiert sind.

User contains
{
  Id   is discrete int;     // erzeugt den Typ User::Id, der von int erbt.
  Name is          string;  // einfache String-Variable
  
  construct( id is Id, name is Name )
  {
    .Id   = id;            // Standardkonstruktor für .Id wird nicht aufgerufen, sondern Copy-Construktor
    .Id   = User::Id( 1 ); // Fehler: Initialisiert wird nur einmal
    .Name : name;          // Standardkonstruktor, dann Zuweisung. Hint: Könnte auch über Initialisierung laufen
    .Name = "Name";        // Fehler: .Name wurde schon per Standardkonstruktor initialisiert.
  }
  
  // besser
  construct( .Id, .Name );
};