Object Oriented Programming for All

- BOOPSI und OOP4A -

Zitat aus den RKMs :

"Boopsi is an acronym for Basic Object Oriented Programming System for Intuition. Using the Object Oriented Programming (OOP) model, Boopsi represents certain Intuition entities, like "Gadgets" and "Images" , as objects."

Wie man deutlich lesen kann, handelt es sich bei BOOPSI um Objekte für die Amiga Intuition-Library. BOOPSI ist damit ganz klar nur eine Unterklasse im OOP4A System. Das gleiche Schicksal trifft übrigens auch MUI :-)) bzw. jede andere Gui-Library.

OOP4A hat 1. als Ziel Programmiersprachen die keinen direkten OOP Support haben mit eben diesem auszurüsten. 2. ein offenes System für Programmierer zu haben, das sich nur mit einigen Wrapperklassen an ein neues Betriebsystem oder neue CPU anpassen läßt. 3. etwas mehr Sicherheit bietet im Umgang mit Aufrüfen von Funktionen.

1. Dieses Ziel hat OOP4A schon mit der ersten Release erreicht gehabt.
2. Da jeder an diesem freien Projekt mitarbeiten kann und es eine offene Architektur hat, die ohne zusätzliche Informationen wie FD, LVO, LIB Files auskommt, ist es leicht portierbar.
3. OOP4A ist Aufrufsicher , das bedeutet , daß man mit einem Methodenaufruf einer Methode, die nicht in der Klasse vorhanden ist, weil z.B. eine alte Version benutzt wird, das System nicht zum Absturz bringen kann. Das normale Librarysystem vom Amiga geht davon aus, daß ein Compiler weiß, was in der Library enthalten ist und nur solchen Code erzeugt, der auch ausführbar ist ohne das System zugefährden. In der Praxis bedeutet das aber, daß neuere Programme , ohne zu prüfen ob die neuere Lib auch vorliegt, alte Libs mit neuen Funktionen aufrufen können, was nicht selten mit einem Absturz endet.

OOP4A hat dem einen Riegel vorgeschoben, in dem alle Methoden in der Klasse mit Namen gespeichert sind und beim Aufruf der Methode lexikalisch verglichen werden. Damit kann eine Klasse auch die Reihenfolge der Methoden in der Klasse ändern ohne das andere Klassen dies überhaupt bemerken würden.

Programme können allerdings immernoch abstürzen, wenn der Programmierer der Klasse oder aufrufenden Programm schlecht programmiert haben. Die Verantwortlichkeit für Plausibilitätsprüfungen liegen allerdings nun ganz klar bei der Klasse selbst. Da aber nur noch KlassenObjekte benutzt werden und diese einheitliche Zugriffmechanismen haben, minimiert sich die Fehlerhäufigkeit schon beträchtlich.

Anhand der string.class und der mem.class zeigt sich das ganz deutlich.

Interface von mem.class und string.class

Class mem Object com.amiga.system.execwrapper exec Object system.misc tools public getMem(long Len) public getAddr() public getChipMem(long Len) public addMem(long len) public addMemContent(long source,long sourcelen) public clearMem() public getSize() Class string Object com.amiga.system.execwrapper exec Object system.misc tools Object system.mem speicher public getAddr() public getString() public addString(long pointer) public addStringObject(String myString) public getSize() public setSize(long size) public clearString() public chomp() public trim()

Betrachten wir mal den Konstruktor der Klasse String.class:

    public Constructor()
    {
      speicher.getMem(0)
      speicher.clearMem()
    }

Als Vorwort sein noch erwähnt, daß Objekte die mit Klassennamen global erzeugt wurden, automatisch vom Konstruktor erzeugt werden, bevor irgendjemand sie benutzen kann. Eigentlich sieht der Konstruktor nach dem "Vorbehandeln" mit PreassXX so aus:

    public Constructor()
    {
      exec=new("com/amiga/system/execwrapper",0)
      tools=new("system/misc",0)
      speicher=new("system/mem",0)
      if exec&tools&speicher=0
       {
         del(exec)
         del(tools)
         del(speicher)
         return -1
       }
      speicher.getMem(0)
      speicher.clearMem()
    }

Im Konstruktor wird also für jeden String schonmal ein MemoryObjekt mit einer Speicherlänge von NULL erzeugt. Und dessen Speicher gelöscht. Bei NULL Byte Speicher im MemoryObjekt ist das zwar nicht sinnvoll , weil nichts passiert, aber eine zukünftige string.class könnte dort schon 30 Bytes für einen String reservieren, um so nicht immer neuen Speicher anfordern zumüssen, wenn der String mal länger wird, und dann sollte dort ein ClearMem() durchgeführt werden.

    public addString(long pointer)
     {
       long size res
     
       size=tools.strlen(long pointer)
       
       res=speicher.addMemContent(pointer,size)
       return res
     }

    public addStringObject(String myString)
     {
       long size pointer res
       Object myString
     
       size=myString.getSize()
       pointer=myString.getAddr()

       res=speicher.addMemContent(long pointer,long size)
       return res
     }

Die string.class kann echte Nullterminierte Strings oder StringObjekte zusammenfügen. Dazu wird die Adresse und die Länge des Strings an das MemoryObjekt weitergereicht, das dann letztendlich das anfügen durchführt:

    public addMemContent(long source,long sourcelen)
     {
    
       long mem2 len2
        
       len2==memsize+sourcelen
       mem2=exec.AllocMem(len2,#MEMF_FAST!MEMF_CLEAR)
       if mem2#0
        {
          exec.CopyMem(mem_p,mem2,memsize)
          exec.FreeMem(mem_p,memsize)
          exec.CopyMem(source,mem2+memsize,sourcelen)
          mem_p==mem2
          memsize==len2
          return memsize
        }
       return 0
     }

Warum ist das so konstruiert und nicht anders???

Ganz einfach, das Stichwort heißt » Verantwortlichkeit « . Die MemoryKlasse kennt alle Zusammenhänge die Speicherverwaltung betreffen. Die Stringklasse kennt alles was mit Strings und deren Eigenschaften zutun hat. Daher gibt es eine Aufgabenteilung , die Stringklasse übernimmt alle Anfragen die mit Strings zutun haben und verarbeitet diese, wenn etwas am Speicher verändert werden soll, dann übergibt Sie die Aufgabe an das MemoryObjekt. Sie muß nicht mehr wissen wo der Speicherbereich des Strings liegt oder wie lang der String ist, das ist Aufgabe des MemoryObjekts. Dem MemoryObjekt wiederum ist es egal was es da verwaltet, es kümmert sich nur um den Speicher und dessen Verwaltung. Damit kann die Klasse mem von jeder anderen Klasse als das benutzt werden was sie ist, ein SpeicherverwaltungsObjekt.

Diese Verantwortlichkeit zieht sich durch die ganze OOP und ist nicht auf OOP4A beschränkt.

Wer jetzt immernoch der Meinung ist, das BOOPSI = OOP4A ist, der sollte sich dringend mal ein OOP Buch besorgen.

OOP4A