Login
Newsletter
Werbung

Mi, 27. April 2011, 15:00

Eine Einführung in die Programmiersprache Pike

Äpfel und Birnen vergleichen

Pike enthält syntaktische Elemente für die klassenbasierte Objektorientierung, d.h. man schreibt eine Klasse, die selber erst einmal keinen Speicher benötigt. Erst bei Bedarf erstellt man Instanzen, nutzbare Abbilder der Klasse. Diese werden in Pike als Klon bezeichnet.

Um Äpfel und Birnen mit Hilfe von Objekten vergleichen zu können, benötigt man also zuerst einmal zwei Klassen, die man außerhalb von anderen Funktionen im Quelltext ablegt:

class Apfel
{
    private int wert;
    public void create(int neuWert)
    {
        wert = neuWert;
    }
    public void faulen()
    {
        wert -=2;
    }
    public int wertNachsehen()
    {
        return wert;
    }
}

class Birne
{
    private int wert;
    public void create(int neuWert)
    {
        wert = neuWert;
    }
    public void faulen()
    {
        wert -=3;
    }
    public int wertNachsehen()
    {
        return wert;
    }
}

Listing: pike_klassen.pike

Nun verfügt der Quelltext über zwei fast identische Klassen für Äpfel und Birnen. Beide verfügen über ein Attribut wert, welches mit dem Schlüsselwort private gegen einen Zugriff von Funktionen außerhalb der Klasse geschützt ist. Um die Werte vergleichen zu können, verfügen beide Klassen über die Methode wertNachsehen(). Auf diese Methoden kann auch von außerhalb der Klassen zugegriffen werden, da sie als public deklariert sind. Ebenso verhält es sich mit der Methode faulen(), welche den Wert verringert. Der Konstruktor, der in Pike immer create() heißt, dient normalerweise dazu, die Attribute einer Instanz mit Startwerten zu versehen. In diesem Beispiel handelt es sich bei wert um ein solches, initialisiertes Attribut. Theoretisch könnte man zusätzlich einen Destruktor destruct() implementieren.

Normalerweise kümmert sich der Garbage Collector um das automatische Aufräumen des Speichers, es gibt jedoch auch die Möglichkeit, mit destruct(Objekt) eine Instanz manuell aus dem Speicher zu werfen. Außerdem bietet der Garbage Collector selbst bis zur Abschaltung sehr viele andere Einstellungsmöglichkeiten, welche unter Umständen die Geschwindigkeit erhöhen.

Nun kann man in einer anderen Funktion Instanzen der beiden Klassen erstellen und nutzen:

void main()
{
    //Erstellen der Instanzen
    Apfel einApfel = Apfel(7);
    Birne eineBirne = Birne(8);
    //ein Vergleich
    if (einApfel->wertNachsehen() > eineBirne->wertNachsehen())
    {
        write("Haha, unmoeglich!\n");
    }
    else if (eineBirne->wertNachsehen() > einApfel->wertNachsehen())
    {
        write("Natuerlich sind Birnen immer besser.\n");
    }
    //die Fruechte gammeln ein bisschen vor sich hin...
    einApfel->faulen();
    eineBirne->faulen();
   
    if (einApfel->wertNachsehen() < 6 || eineBirne->wertNachsehen() < 6)
        write("Die Fliegen kommen schon! Garbage Collector, schmeiss sie weg!\n");
    //Und das tut er dann auch.
}

Listing: pike_klassen2.pike

Wie man an diesem Beispiel erkennt, wird die Methode create() nie namentlich aufgerufen, stattdessen wird einfach der Name der Klasse verwendet, um eine Instanz zu erstellen. Wie bei einer Deklaration eines anderen Datentypen steht auch hier der Datentyp vor dem Namen.

Vererbung und Polymorphie in Pike

Die beiden in dem vorherigen Beispiel genutzten Klassen sind fast identisch aufgebaut: Nur die Methode faulen() unterscheidet sich von Klasse zu Klasse. Es ließe sich also viel Platz sparen, wenn man eine Klasse Frucht hätte, deren Attribute und Methoden man auf die Klassen Apfel und Birne überträgt:

class Frucht
{
    static int wert;
    public void create(int neuWert)
    {
        wert = neuWert;
    }
    public void faulen()
    {
        wert -= 3;
    }
    public int wertNachsehen()
    {
        return wert;
    }
}

Listing: pike_klasse_frucht.pike

Achtung: Damit wert auch in den beerbten Klassen verwendet werden kann, muss private zu static geändert werden. static hat also in Pike einen anderen Nutzen als static in C++.

Nun gilt es, die Eigenschaften von Frucht auf die Klassen Apfel und Birne zu übertragen. Diese sehen dann folgendermaßen aus:

class Birne
{
    inherit Frucht;
}

class Apfel
{
    inherit Frucht;
    /*Halt, die Methode faulen() muss ueberschrieben werden!*/
    public void faulen()
    {
        wert -=2;
    }
}

Listing: pike_vererbung.pike

Dieses Beispiel funktioniert mit der unveränderten Hauptfunktion.

Mehrfachvererbung

Pike unterstützt Mehrfachvererbung. Es wird zwar oft davon abgeraten, doch in manchen Situation ist es ganz praktisch, eine Klasse mit Attributen und Methoden mehrerer anderer Klassen zu beerben.

class Bipfel
{
    inherit Apfel;
    inherit Birne;
}

Dies ist nun die Klasse Bipfel, die Krone der Schöpfung. Sie unterscheidet sich jedoch nicht von der Klasse Birne. Warum?

Oben wurden die Eigenschaften von Birne und Apfel von der Klasse Frucht abgeleitet. Zwar verfügt Apfel über eine modifizierte Version der Methode faulen(), allerdings steht inherit Apfel über inherit Birne. Die zuvor bereits vererbten Eigenschaften werden also durch die namentlich identische, nächste Vererbung überschrieben.

Module

Da Pike von sich aus wie die meisten Programmiersprachen erstmal wenig kann, gibt es natürlich auch eine Möglichkeit, Softwarebibliotheken von außerhalb zu nutzen: Die sogenannten Module – Dateien, die normalerweise auf .pmod enden.

Module können Anbindungen an C/C++-Bibliotheken, aber auch normale Pike-Routinen enthalten, da sie ebenfalls zur Strukturierung des Programmes gedacht sind.

Will man ein Modul – z.B. Regexp, ein Modul für reguläre Ausdrücke – nutzen, welches im Standardverzeichnis für Module liegt, kann man dieses mit der Zeile import Regexp; in das Programm einbinden.

Um Module einzubinden, welche Teil des Programmes sind und lokal vorliegen, muss man das Modul als Pfadangabe in Anführungszeichen angeben, wobei der Punkt für das aktuelle Verzeichnis steht. Dies könnte dann so aussehen:

import "./Unterordner/meinModul";

Außerdem gibt es die Möglichkeit, ein Verzeichnis zu einem Modul umzufunktionieren, indem man es z.B. von meinOrdnermodul zu meinOrdnermodul.pmod umbenennt. Alle Funktionen, welche sich in den darin befindlichen .pike- oder .pmod-Dateien befinden, können über dieses Modul genutzt werden.

Zu den Modulen im Allgemeinen ist zu sagen, dass sie der schwache Punkt von Pike sind, was sicher dem Bekanntheitsgrad der Sprache zuzuschreiben ist. Obwohl sich die Situation schon deutlich gebessert hat und sogar ein Modul für DVB existiert, gibt es – verglichen mit Perl oder Python – nur wenige Erweiterungen. Webentwickler mit eigenem Server mögen unter Umständen jetzt schon glücklich werden, aber z. B. für Spieleentwickler gibt es laut Dokumentation nur eine halbherzige Anbindung an SDL.

Wer also etwas exotischere Softwarebibliotheken nutzen möchte, wird sein eigenes Modul erstellen müssen. Auf der Homepage gibt es dazu Beispiele; sicherlich ist es einfacher, SWIG zu benutzen, welches nicht nur C-Bibliotheken, sondern auch komplexen C++-Code an verschiedene Programmiersprachen anbinden kann.

Kommentare (Insgesamt: 6 || Alle anzeigen )
gibt doch C-Interpreter? (Kanuba, Mi, 4. Mai 2011)
Re[4]: Warum? (sauer2, Sa, 30. April 2011)
Re[3]: Warum? (eMBee, Fr, 29. April 2011)
Re[2]: Warum? (sauer2, Do, 28. April 2011)
Re: Warum? (eMBee, Do, 28. April 2011)
Pro-Linux
Pro-Linux @Facebook
Neue Nachrichten
Werbung