MAL-Homepage Inhaltsverzeichnis



MAL Dokumentation: Objektorientierte Programmierung




Inhalt:

1. EINFÜHRUNG
2. KLASSEN
2.1. Member-Functions
2.2. Konstruktoren
3. ANWENDUNG EINER KLASSE
4. VERERBUNG
4.1. Vererbund der Variablen
4.2. Vererbung der Funktionen
4.3. Beispiel für Vererbung
5. MENÜGESTEUERTE ENTWICKLUNGSUMGEBUNG
5.1. Einrichten einer Klasse
5.2. Bedienung


1. EINFÜHRUNG

Objekte (Instanzen) werden am Mal-Stack durch den Datentyp 'instancetyp' repräsentiert. Dieser Datentyp ist weitgehend funktionsgleich mit einem Verbund. Er wird auch durch Aufruf des Wortes
>instance direkt aus einem Verbund erzeugt. Die Komponenten des Verbundes sollten sinnvoller Weise mit Namen versehen sein.

Für die Zuordnung des Objekts zu seiner Klasse ist der Klassenname als String mit dem Namen 'class' im Verbund enthalten.

Beispiel eines Objekts einer Klasse für komplexe Zahlen:

[ "complex_class" "class" >name
5 "real" >name
3 "imag" >name ] >instance
Dieses Objekt stellt eine Instanz der Klasse 'complex_class' mit dem Wert der komplexen Zahl 5+3j dar.

Wenn ein Objekt mit dem Wort '.' (Punkt) ausgegeben wird, unterscheidet sich die Ausgabe von der eines Verbundes nur darin, daß bei Instanzen geschwungene Klammern { und } statt eckigen verwendet werden.

MAL-Homepage Inhaltsverzeichnis


2. KLASSEN

Jede Klasse ist eine Doppelpunktdefinition. Das Grundgerüst einer Klasse ohne Member-Functions hat folgenden Aufbau:

: klassenname >> function
  : classname "klassenname" ;
  : interface 
  [
  .
  .
  ] ;
function >code make ;
Der unter : classname ... angegebene Klassenname muß mit dem Namen der der Doppelpunktdefinition ident sein.

Eine Klasse hat also folgende Syntax:

function ->

wobei der Parameter function ein String mit MAL-Code zum Aufruf einer lokalen Doppelpunktdefinition ist.

MAL-Homepage Inhaltsverzeichnis


2.1. Member-Functions

Member-Functions werden in Form von lokalen Doppelpunktdefinitionen in der Klasse definiert. Damit sie auf elegante Weise aufgerufen werden können, muß zusätzlich noch ein String im Verbund des Wortes interface eingebracht werden, der die Aufrufsyntax der Member-Function deklariert.

Ein Deklarations-String hat folgende Parameter:

Externer und interner Name werden duch das Zeichen ':' getrennt. Wird kein interner Name angegeben (auch das Zeichen ':' kann dann weggelassen werden), so ist der interne Name gleich dem externen, erweitert um das Zeichen '_' (Underline).

Syntaxdiagramme entsprechen der in MAL üblichen Schreibweise, jedoch werden die verwendeten Input- und Output-Parameter jeweils in der Form

variablenname:datentyp

dargestellt. Wird kein Datentyp angegeben (der Parameter 'datentyp' und das Zeichen ':' kann weggelassen werden), dann ist die Variable eine Instanz der Klasse.

Folgende Datentypen sind möglich: Beim Implementieren des Codes der Member-Function kann man davon ausgehen, daß die als Input-Parameter angeführten Variablen als Worte im Vokabular zu finden sind. Für das Ablegen der Output-Parameter am Stack hat man jedoch zu sorgen.

Eine Sonderstellung kommt dem Variablennamen this zu: this muß immer eine Instanz der Klasse sein (ist also ein Verbund mit Namenskomponenten). Die Komponenten von this werden bei der Exekution der Member-Function ins Vokabular geladen. Sie können gelesen oder mit den Worten
-> oder >> verändert werden. Mit dem Wort this> kann am Ende der Member-Function der neue Zustand der this-Instanz auf den Stack geholt werden.

Das folgende Beispiel zeigt die Deklaration einer Member- Function für die Addition von komplexen Zahlen:
: interface
[ "+:addition this x -> summe" ] ;


: addition real x \ real + -> real imag x \ imag + -> imag this> ;
Der externe Name der Funktion ist '+', der interne 'addition'. Sie erwartet zwei Input-Paramerer, nämlich 'this' und 'x', die beide Instanzen der eigenen Klasse sind. Als Ergebnis wird ebenfalls eine Instanz der eigenen Klasse am Stack gelegt (die Summe der Komplexen Zahlen 'this' und 'x').

Die erste Zeile des Wortes addition addiert die Realanteile der beiden komplexen Zahlen. Das Wort real enthält den Realanteil der Variablen 'this'. Der Realanteil der Variablen 'x' muss mit dem Code

x \ real

addressiert werden. Anschließend wird die Summe der Realanteile auf das Wort real zurückgespeichert. Nach der Addition der Imaginärteile wird mit dem Wort this> eine neue Instanz der Complex-Klasse, mit den nun veränderten Werten von real und imag, zusammengestellt.

MAL-Homepage Inhaltsverzeichnis


2.2. Konstruktoren

Die Namen von Konstruktor-Funktionen können in MAL frei vergeben werden. Konstruktoren unterscheiden sich von sonstigen Member-Functions nur dadurch, daß sie als Input-Parameter keine Instanzen der eigenen Klasse benötigen, jedoch welche als Output-Parameter erzeugen.

Als Hilfsmitte für das Erzeugen von Instanzen der eigenen Klasse können die Worte
{ und } verwendet werden. Diese sind wie folgt definiert:

: { [ classname "class" >name ;
: } ] >instance ;
Wenn man also zum Beispiel einen Konstruktor für komplexe Zahlen folgendermaßen implementiert:
: >complex
{ cool real cool imag } ;
so entspricht das folgendem Code:
: >complex
[ classname "class" >name cool real cool imag ] >instance ;
Das bewirkt, daß zuerst der Name der Klasse in den Verbund aufgenommen wird, dann der Realteil (das Wort cool bewirkt, daß dem Stackeintrag automatisch der Name des Wortes, also 'real', gegeben wird) und der Imaginärteil, und im Anschluß der Verbund auf eine Instanz umgewandelt wird.

MAL-Homepage Inhaltsverzeichnis


3. ANWENDUNG EINER KLASSE

Mit dem Code

interface_of complex_class >voc
wird das Interface der Klasse complex_class ins Vokabular geladen. Die Worte >complex und + können also direkt aufgerufen werden:
1 2 >complex 3 4 >complex + .
gibt als Ergebnis:
instance-[ 
class=complex_class
real=4
imag=6 ]
Man beachte, daß der MAL-Interpreter das neue Wort + v on dem bereits im Kern definierten unterscheiden kann. Die normale Addition ist nach wie vor möglich:
1 2 + .
3

MAL-Homepage Inhaltsverzeichnis


4. VERERBUNG

Vererbung, also die Konstruktion abgeleiteter Klassen, stellt ein wesentliches Stilmittel der Objektorientierten Programmierung dar.

Zwei Charakteristika zeichnen eine abgeleitete Klasse aus:

  1. Ihre Instanzen sind im Prinzip Instanzen der Oberklasse, erweitert um eigene Variablen.
  2. Sie hat Zugriff auf Funktionen der Oberklasse.

MAL-Homepage Inhaltsverzeichnis


4.1. Vererbund der Variablen

Die Instanzen einer abgeleiteten Klasse unterscheiden sich von denen ihrer Oberklasse primär durch den eingetragenen Klassennamen ( also den String mit dem Namen 'class'). Außerdem können sie zusätzliche Variablen beinhalten.

Die Übernahme der Daten aus der Oberklasse erfolgt im Konstruktor (den Konstruktoren) der abgeleiteten Klasse durch das Wort
inherit.

Das Wort inherit hat folgende Syntax:

d_instanz instanz -> var1 var2 ...

Der Konstruktor einer abgeleiteten Klasse hat also etwa folgenden Aufbau:
: konstruktor
{
.
.
.
}
konstruktor_oberklasse inherit ;

MAL-Homepage Inhaltsverzeichnis


4.2. Vererbung der Funktionen

Wenn nach der Interface-Deklaration einer Klasse der Code

derived_from xxx ( xxx ist die Oberklasse)
aufgerufen wird, so können alle Member-Functions der Oberklasse für die Instanzen der abgeleiteten Klasse verwendet werden. Das Interface der abgeleiteten Klasse wird also um die Funktionen der Oberklasse erweitert.

Beispiel:
[
"create_segment_assignment: -> this "
"get_patterns: this -> patterns:[] "
] derived_from neural_class ;
In MAL hat eine abgeleitete Klasse immer Zugriff auf alle Member-Functions und Variablen ihrer Oberklasse. Es gibt also keine 'private' Direktiven oder ähnliches.

MAL-Homepage Inhaltsverzeichnis


4.3. Beispiel für Vererbung

Als Beispiel für die Vererbung wird hier eine Klasse personen_class (als Oberklasse) mit den Variablen Vorname und Familienname angeführt. Sie ist wie folgt definiert:

: personen_class >> function 
  : classname "Person" ;
  : interface 
  [ ">person vorname:string familienname:string -> this" ] ;
  : >person_ { cool vorname cool familienname } ;
function >code make ;
Von ihr abgeleitet ist die Klasse angestellter_class, mit der zusätzlichen Variable Einstellungsdatum und den zusätzlichen Funktionen >angestellter (Konstruktor) und angestellt_am:
: Angestellter >> function 
  : classname "Angestellter" ;
  : interface 
  [
  ">angestellter: vorname:string familienname:string -> this"
  "angestellt_am: this datum:string -> this" 
  ] derived_from Person ;
  : >angestellter_ 
  { vorname familienname >person inherit 
  "" "Einstellungsdatum" >name } ;
  : angestellt_am_ 
  datum -> Einstellungsdatum this> ;
  function >code make ;
Der Code derived_from Person im Interface wäre in diesem Fall gar nicht erforderlich, da von der Oberklasse keine Funtionen verwendet werden (außer dem Konstruktor >person, der aber direkt von der Klasse Person aufgerufen wird).

MAL-Homepage Inhaltsverzeichnis


5. MENÜGESTEUERTE ENTWICKLUNGSUMGEBUNG

Die menügesteuerte Entwicklungsumgebung für Klassen ist nicht nur für den Aufbau der Klassenstruktur sehr hilfreich, sie unterstützt auch die Dokumentation der Klasse, indem sie die Helpseite automatisch aus den bei den Funktionen und Variablen angegebenen Informationen generiert.

Sie unterstütz aber nur die Entwicklung von Klassen, die in einem
Vokabulars-Folder gespeichert sind.

Hinweis:
Eine Klasse ist eine normale Doppelpunktdefinition. Für die menügesteuerte Entwicklungsumgebung wird aber der Environment-Datensatz dieser Doppelpunktdefinition für das Abspeichern der eingebenen Daten verwendet. Dazu wird der Code im Environment dynamisch verändert (beim Sichern der Änderungen). Die Datensätze code und help der Klasse werden ebenfalls beim Sichern automatisch generiert. Veränderungen der Klasse dürfen daher nur mehr über die Entwicklungsumgebung durchgeführt werden, da sonst Inkonsistenzen entstehen können.

MAL-Homepage Inhaltsverzeichnis


5.1. Einrichten einer Klasse

Die menügesteuerte Entwicklungsumgebung erspart den manuellen Aufbau der Klassenstruktur und der Helptext-Seite.

Eine neue Klasse mit Entwicklungsumgebung wird eingerichtet, indem von einem
Vokabulars-Folder aus der Menüpunkt insert / Class aufgerufen wird.

MAL-Homepage Inhaltsverzeichnis


5.2. Bedienung

Mit dem Menüpunkt go wird die Entwicklungsumgebung gestartet. Daraufhin erscheint ein Menü mit folgenden Menüpunkten:

Help
Der Menüpunkt Help öffnet ein Editorfenster, in das eine allgemeine Beschreibung der Klasse eingegeben werden sollte. Der hier eingegebene Text erscheint zu oberst in der Help-Seite der Klasse. Er braucht keine Syntaxdiagramme enthalten, weil diese automatisch aus den Daten der Funktionen-Tabelle generiert wird.

Functions
Der Menüpunkt Functions öffnet die Liste der Member-Function der Klasse. Neue Funktionen können mit Insert eingerichtet werden.

Inheritance
Der Menüpunkt Inheritance öffnet eine Maske, in die der Name eine Oberklasse eingegeben werden kann. Bei Mehrfachvererbung können auch mehrere Namen durch Blank getrennt eingegeben werden. Die Oberklasse kann zwar auch aus einem anderen Folder stammen, es empfiehlt sich aber aus zwei Gründen, nur von Klassen aus dem selben Folder abzuleiten.

  1. Klassen aus dem eigenen Folder werden automatisch in der Maske beim Menüpunkt Inheritance augelistet.
  2. Funktionen von Oberklassen aus einem anderen Folder scheinen nicht im Helptext auf.

Go
Mit dem Menüpunkt Go wird der Testcode der Klasse gestartet, den man zuvor mit dem Menüpunkt environment editiert hat.

MAL-Homepage Inhaltsverzeichnis