Ge erische Date type „Ge erics“

Object Pascal im Detail - Ge e is he Date t pe „Ge e i s www.delphi-treff.de 136

4.13. Ge erische Date type „Ge erics“

Delphi unterstützt seit Version 2009 generische Datentypen. Diese werden gebraucht, um Datentypen sehr allgemein programmieren zu können, ohne dass sie dadurch in der Anwendung kompliziert werden. Ein gutes Beispiel dafür sind Listen. In Delphi gibt es dafür schon seit langer Zeit die Klasse TList. TList sollte in jeder Lebenslage einsetzbar sein, weshalb alle enthaltenen Elemente als Pointer aufgefasst werden. Ein Pointer zeigt auf eine Adresse im Arbeitsspeicher. Was dort zu finden ist, muss der Programmierer selbst wissen. D.h. beim Auslesen muss das Element in einen bestimmten Typ umgewandelt werden. Das ermöglicht es einem Programmierer nun tatsächlich, Objekte beliebigen Typs in eine Liste zu stecken. Allerdings gibt es nun zwei Probleme: Üblicherweise enthalten Listen nur Elemente des gleichen Typs, z.B. eine Liste von Strings. Das kann TList aber nicht sicherstellen. Dadurch ist es möglich, Objekte völlig unterschiedlicher Typen absichtlich oder unabsichtlich in dieselbe Liste zu stecken. Auf das andere Problem stößt man beim Auslesen der Liste: TList gibt alles als Pointer zurück. Der Programmierer muss das Objekt also selbst in das casten, was er eigentlich erwartet, was umständlich und fehleranfällig ist. Wie wäre es also, wenn man der Liste schon beim Erzeugen sagen könnte, dass sie nur Strings aufnehmen und zurückgeben soll? Und in einer anderen Instanz nur Integers? Genau das ist der Einsatzzweck für Generics. Wer auch die vorhergehenden Kapitel gelesen hat, kennt das Vorgehen schon. Hier trotzdem noch einmal das Beispiel: var MyList: TListInteger; MyList ist nun eine Liste, die ausschließlich Integer-Werte aufnehmen kann. Beim Auslesen der Liste kommen direkt Integer-Werte zurück, die nicht gecastet werden müssen. Selbstverständlich sind auch weitere Verwendungen möglich: MyStringList: TListstring; TList ist also eine generische Klasse. Doch wie macht sie das? Die Klasse TList weiß vor ihrer Instanziierung nicht, für welchen Datentyp sie zuständig sein soll. Deshalb können die Methoden in TList nicht mit einem bestimmten Typ arbeiten, auch nicht mit TObject. Stattdessen wird ein Platzhalter verwendet, üblicherweise kommt hier der Großbuchstabe T zum Einsatz. Allerdings können auch beliebige andere Pascal-Bezeichner verwendet werden. Die Klassendefinition von TList könnte also so aussehen beispielhafte Implementierung, nicht an der Original-TList-Klasse orientiert: Object Pascal im Detail - Ge e is he Date t pe „Ge e i s www.delphi-treff.de 137 type TListT = class public procedure addelement: T; function get: T; end; Man sieht an diesem Code: Alles läuft im Prinzip so, wie man es kennt. Nur dass eben kein konkreter Datentyp als Rückgabewert oder Parameter verwendet wird, sondern das ominöse T. Dieses wird erst bei der Instanziierung der Klasse durch einen konkreten Typ ersetzt wie in obigen Beispielen mit Integer- und String- Listen zu sehen. Fehlerbehandlung - Die Vorbereitung www.delphi-treff.de 138

5. FEHLERBEHANDLUNG

Fehler können wir generell in drei Gruppen einteilen:  Syntaxfehler werden bereits beim Kompilieren gefunden und angezeigt. Der Compiler prüft dabei den Quelltext auf seine syntaktischen und semantischen Eigenschaften. Die syntaktische Analyse bezieht sich auf die Grammatik von Object Pascal, z.B. auf ein falsch geschriebenes Schlüsselwort. Nicht deklarierte Bezeichner werden hingegen erst in der darauffolgenden semantischen Analyse festgestellt, da dort die Zusatzbedingungen im jeweiligen Zusammenhang überprüft werden. Tritt ein Syntaxfehler auf, dann wird das Programm nicht übersetzt und ist somit nicht lauffähig. Allerdings wissen wir, wo der Fehler auftritt, und können ihn somit schnell beheben.  Laufzeitfehler entstehen erst beim Ausführen des Programms – die Syntaxprüfung war also erfolgreich. Typische Fehler wären z.B. eine Division durch Null oder der Zugriff auf eine noch nicht erzeugte Instanz einer Klasse. Im günstigsten Fall erhalten wir bei einem Laufzeitfehler sofort eine Meldung und kennen somit die Fundstelle. Möglich ist allerdings auch, dass irgendein Speicherbereich überschrieben wird und der Fehler erst sehr viel später auftritt.  Bei Logikfehlern, welche nicht zu einem Laufzeitfehler führen, treten überhaupt keine Fehlermeldungen auf. Das Programm verhält sich lediglich anders als erwartet. Solche Fehler sind mitunter schwer zu finden, da wir unter Umständen von einer falschen Annahme ausgehen und uns deswegen selbst im Weg stehen. Syntaxfehler können wir direkt im Quelltext beheben. Für Laufzeit- und Logikfehler benötigen wir jedoch ein Instrument, welches uns erlaubt, den Zustand des Programms auszuwerten. Erst durch den Einblick in aktuelle Variableninhalte, die Aufrufreihenfolge von Funktionen oder das Durchschreiten des Quelltextes in Einzelschritten, können wir uns der Fehlerstelle nähern. Das alles gehört zur Grundfunktionalität des Debuggers.

5.1. Die Vorbereitung

Wird ein Programm erfolgreich kompiliert, so werden die symbolischen Namen der Bezeichner entfernt. Erweiterte Compiler-Optimierungen können dazu führen, dass der Programmablauf für uns nicht mehr wirklich nachvollziehbar wird. Darum weisen wir den Compiler an, zusätzliche Debug-Informationen in die ausführbare Nachdem nun Details von Object Pascal bekannt sind, wollen wir uns ansehen, wie man Fehler in eigenen Programmen findet und wie man vorgehen kann, um sie zu vermeiden.