VOICE-Homepage: http://de.os2voice.org | Mai 2004 Inhaltsverzeichnis < Vorherige Seite | Nächste Seite > Artikelverzeichnis editor@os2voice.org

## Leserbriefe, Addenda, Errata

Übersetzung: Christian Hennecke

Wenn Sie irgendwelche Kommentare bezüglich Artikeln oder Tips in dieser oder eine älteren Ausgabe des VOICE Newsletter abgeben wollen, senden Sie sie bitte an editor@os2voice.org. Uns interessiert stets, was unsere Leser zu sagen haben.

April 24, 2004 - Diesen Monat erhielten wir nur einen Leserbrief, aber dieser ist ein eingehender Kommentar von Chris Wohlgemuth zu dem Artikel von Thomas Klein Dr.Dialog, oder: Wie ich lernte, REXX zu lieben - Teil 12:

> Als erstes fiel mir etwas in der Beschreibung zur Funktion `DATE()` auf:

> > Beachten Sie, daß bereits die Angabe des ersten Buchstaben einer Option genügt und die Groß- / Kleinschreibung keine Rolle spielt (man kann also 'Sorted', 'S', 's', 'sORted' usw. verwenden). Außerdem muß man die Option auch nicht in Anführungszeichen angeben.

> Obwohl dies völlig in Ordnung ist, ist es dennoch wert zu erwähnen, daß es ohne die Anführungszeichen eigentlich nur per Zufall funktioniert, nämlich wegen einer Sprachbesonderheit in REXX. Jeder Variablen, der nicht ausdrücklich ein Wert zugewiesen wird, wird automatisch der Variablenname (in Großbuchstaben) als Wert zugewiesen.

> Dieses Skript als Beispiel dazu:

>     /* -- Beispiel Skript -- */

>     SAY "First: "||hello
>     hello="Good bye!"
>     SAY "Second: "||hello
>     SAY "Third: "||"hello"

>     /* -- Beispiel Ende -- */

> erzeugt folgende Ausgabe:

>        First: HELLO
>        Second: Good bye!
>        Third: hello

> Wird die Optionszeichenfolge bei der Verwendung von `DATE()` nicht in Anführungszeichen gesetzt, kann dies zu sehr merkwürdigen Fehler führen, die sich nur schwer auffinden lassen. Angenommen, es gäbe eine Datenbankanwendung mit einem Programmcode wie folgt:

>     /* Beispiel: ACME Spezialdatenbanksortierer */

>     [...]
>     /* Sortiere meine Daten nach Monat */
>       rc=sort_my_Data_using_the_month_field()

>     /* Speichere das letzte Sortierkriterium */
>     sorted="month"

>     /* Mach hier irgendetwas */
>     [...]

>     /* Nun versuche, das aktuelle Datum aus REXX für die Sortierung geeignet aufzubereiten */
>     currentDate=DATE(sorted)

>     /* Beispielende */

> Der letzte Ausdruck wird nicht das Datum im "JJJJMMTT"-Format ausgeben, sondern den aktuellen Monat!

> In der Beschreibung zu `RxFuncAdd()` steht folgendes:

> >     [...]
> >           ergebnis = RXFUNCADD(<mein-funktionsname>,<dll-name>,<dll-funktionsname>)
> >     [...]

> > Der erste Parameter `<mein-funktionsname>` teilt REXX mit, unter welchem Namen Sie diese Funktion in Ihrem Programm einsetzen wollen (quasi den Namen, den Sie in der entsprechenden CALL-Anweisung angeben). Prinzipiell sollten Sie auch hier den Namen angeben, der für `<dll-funktionsname>` verwendet wird, um die Sache übersichtlich zu halten. Zwar ist es gut zu wissen, daß man eine Funktion auch unter einem anderen als dem bibliotheksinternen Namen laden kann, aber es verkompliziert die Sache. Der Nachteil dabei ist nämlich, daß Sie es anderen Programmen damit erheblich erschweren zu prüfen, ob eine bestimmte Funktion bereits geladen wurde. Verwenden Sie also besser `<dll-funktionsname>` auch im Parameter `<mein-funktionsname>`.

> Ich tendiere dazu, dem letzten Satz zu widersprechen. Obwohl es in der Tat üblich ist, identische Namen für `<dll-funktionsname>` und `<mein-funktionsname>` zu verwenden, ist es nicht notwendigerweise auch richtig. Es funktioniert eigentlich nur deshalb, weil die meisten Programmierer die rexxutil-Funktionen nach Gebrauch nicht wieder "entladen" (und man sollte dies auch nie machen, siehe weiter unten). REXX hat keinen Referenzschalter für externe Funktionen, weshalb es möglich ist, jede REXX-Funktion zu "entladen", selbst wenn auf sie noch von einem anderen Skript zugegriffen wird. Die folgenden zwei Skripte sollen dies verdeutlichen.

>     /* Entladen-Funktion Beispiel Teil 1 */
>     call RxFuncAdd 'SysTextscreensize', 'RexxUtil', 'SysTextscreensize'

>     SAY ""

>     SAY SysTextscreensize()

>     'pause'

>     SAY SysTextScreenSize()

>     /* Beispiel Teil 1 Ende */

>     /* Entladen-Funktion Beispiel Teil 2 */

>     call RxFuncAdd 'SysTextScreenSize', 'RexxUtil', 'SysTextScreenSize'

>     SAY "SysTextScreenSize geladen"

>     SAY RxFuncDrop("SysTextScreenSize")

>     SAY "SysTextScreenSize entladen"

>     /* Beispiel Teil 2 Ende */

> Das erste Skript lädt eine Funktion aus der `REXXUTIL.DLL`, die die Größe des Bildschirms abfragt (Sie benötigen wahrscheinlich eine neueres Fixpak für diese Funktion. Es läuft zumindest mit eCS 1.01), gibt diese Information auf den Bildschirm aus und wartet dann auf einen Tastendruck. Wenn man nun das zweite Skript startet, während Skript 1 noch auf den Tastendruck wartet, wird die Funktion `SysTextScreenSize()` entladen. Nach dem Tastendruck im Fenster des Skripts 1 wird das Skript weiterlaufen, aber sofort beim Aufruf der `SysTextScreenSize()` mit dem REX0043-Fehlercode "Routine not found" scheitern. Dies ist kein generelles Problem, weil die Autoren im Regelfall keine Funktionen der `REXXUTIL.DLL` entladen und auch Sie sollten sich im Falle der `REXXUTIL.DLL` davor hüten.

> Der `<mein-funktionsname>` Parameter vermeidet das Problem (der `RxFuncQuery()`-Teil des Artikels gibt Hinweise auf ein paar andere Probleme damit). Wenn man die Funktion mit einem anderen Namen, der nur dem eigenen Skript bekannt ist, lädt, kann kein anderes Skript diese Funktion hinterrücks entladen und zu schwer auffindbaren Laufzeitfehlern führen. Dies kann insbesondere dann wichtig sein, wenn man externe Funktions-DLLs einsetzt, die auch von anderen Anwendungen verwendet werden, und diese Anwendungen die benutzten Funktionen beim Beenden wieder entladen, um Systemspeicher freizugeben.

> Der Parameter ist auch notwendig, wenn man verschiedene REXX-DLLs zur gleichen Zeit verwenden muß und das mit gleichen Namen. Normalerweise sieht REXX in einer internen Funktionenliste nach, ob die Funktion schon verfügbar ist. Wenn die Funktion `foo()` in der `bar.dll` bereits geladen ist, wird eine Anfrage, die Funktion `foo()` in der `newbar.dll` zu verwenden, fehlschlagen, selbst wenn die Anfrage aus einer anderen Anwendung stammt. Externe Funktions-DLLs, die in verschiedenen Revisionen verfügbar sind (zum Beispiel die User-Control-DLL für DrDialog), machen die Sache kompliziert, weil man zwei verschiedene Anwendungen haben kann, die gleichzeitig verschiedene Revisionen der DLL erfordern.

> Fazit ist, das Laden und Entladen von externen Funktionen kann Nebenwirkungen verursachen, derer man sich bewußt sein sollte. Aber man braucht sich keine allzu große Sorgen darum machen, weil man in der überwältigenden Mehrzahl der Programme damit nicht belästigt wird. Die INF-Datei "Rexx Tips und Tricks" (`rxtt32.zip` auf Hobbes) enthält noch mehr Informationen.

> Gut, nach der ganzen Erbsenzählerei ;-) möchte ich sagen, daß die gesamte REXX-Serie ein tolles Stück Arbeit ist und daß ich hoffe, daß noch ein paar mehr Leute anfangen, Programme mit DrDialog zu schreiben. Dieses Paket sieht zwar auf den ersten Blick etwas altbacken aus, aber mit ein paar kleinen Tricks kann man damit wirklich moderne Programme erstellen. Das prominenteste Beispiel dafür ist sicherlich die Scanneranwendung Tame/2, die mit DrDialog erstellt wurde.

Artikelverzeichnis
editor@os2voice.org
< Vorherige Seite | Inhaltsverzeichnis | Nächste Seite >
VOICE-Homepage: http://de.os2voice.org