Ein Jahr JavaScript-Konkurrent Dart

Seite 3: Kleine Änderungen

Inhaltsverzeichnis

Neben den größeren Blöcken umfasst der erste Milestone eine Reihe kleinerer Sprachänderungen. Durften bisher benannte Konstruktoren und Methoden den gleichen Namen haben, ist das nun nicht mehr gestattet. Ebenso wurde as als ein Infix-Operator für Castings eingeführt. Sollte bisher Wissen über den erwarteten Typ als Ergebnis eines query()-Aufrufs dokumentiert werden, war die Deklaration einer typisierten Variable notwendig.

InputElement firstName = query('#firstname'); 
firstName.value = 'Frank';

Mit dem neuen Operator kann das auch direkt erfolgen.

(query('#firstname') as InputElement).value = 'Frank'; 

Auch die Ausführung des switch-Statements hat Veränderungen erfahren. Bisher hat es sich mehr wie JavaScript verhalten, also eine andere Schreibweise für eine Reihe von if-else-Statements. Die hierin
durchgeführten Vergleiche, die eventuell auf benutzerdefinierten Methoden beruhen, lassen sich nicht vom Compiler optimieren. Dafür wurde switch auf Zahlen, Strings und konstante Objekte beschränkt. Hierdurch kann der Compiler bessere Verfahren zur Steuerung der Verzweigungen nutzen.

Weniger wichtig für die Programmausführung als für die Arbeit im Team und die spätere Wartung ist eine gute Kommentierung des Codes. Zum Erzeugen extern lesbarer Dokumentation verwendet Dart mit dartdoc ein Werkzeug ähnlich zu Javadoc. Auch die Kommentarform ist entsprechend. Das kann für einen Einzeiler schon etwas unverhältnismäßig wirken. Für diese Fälle hat das Dart-Team den einzeiligen Dokumentations-Kommentar eingeführt.

/// Connects to the backend with the configuration [cfg]. 
connect(Configuration cfg) { ... }

Diese Kommentare dürfen Entwickler auch mehrzeilig einsetzen, wenn sie ihnen besser als die regulären /** ... */ gefallen. Schön ist zudem, dass anstelle von HTML Markdown als Auszeichnungssprache in den Kommentaren genutzt wird. Das wirkt sich in der Regel weniger negativ auf die Lesbarkeit im Quelltext aus.

Neben sprachlichen Änderungen haben sich die Bibliotheken weiterentwickelt. Basis für ihre Nutzung ist der Import mit der Direktive #import. Bisher wirkte sie in der Form, dass sie die referenzierte Bibliothek komplett importierte. Bei gleichen Namen von Bezeichnern in zwei Bibliotheken konnte das zu Konflikten führen, die sich nur durch einen Präfix beim Import beheben ließen. Nun gibt es in der Direktive zusätzlich eine optionale Erweiterung für die selektive Aus- oder Abwahl von Namen.

#import('firstlib.dart', show: ['foo', 'bar']); 
#import('secondlib.dart', hide: ['foo', 'bar']);

In dem Fall werden von firstlib.dart nur die Namen foo und bar importiert, während von secondlib.dart alles außer diesen Namen herangezogen wird. Ebenso kann man mehrere einzelne Bibliotheken zu einer großen zusammenfassen. Hierfür kennt #import den export:-Parameter.

// mylib.dart // mylib.dart 
#import('foo.dart', export: true);
#import('bar.dart', export: true);

So werden von mylib.dart neben den eigenen Exporten alle von foo.dart und bar.dart exportiert. Auf dem Weg lassen sich auch große Bibliotheken in kleinere refaktorisieren, ohne dass importierende Programme etwas ändern müssen. Eine Kombination mit show: oder hide: ist ebenfalls möglich. So lassen sich Importe bei Bedarf präzise steuern. Jedoch bestand noch das Problem der Namenskonflikte zwischen Importen und lokalen Definitionen, beispielsweise nach Updates importierter Bibliotheken. Das wurde inzwischen zugunsten der lokalen Definitionen spezifiziert, die immer gegenüber Importen gewinnen.

Nun wollen Entwickler nicht alles von Grund auf neu programmieren, sondern gerne auf eine leistungsstarke Bibliothek zurückgreifen. Jav SE/EE und .NET haben gezeigt, wie wichtig das ist. Daher statten die Dart-Entwickler ihr System mit der Dart API aus. Sie hat inzwischen um einiges zugelegt. Basis ist weiterhin dart:core, das immer automatisch geladen wird. Wichtigste Bestandteile sind die Basis-Datentypen inklusive Date und Duration sowie einige Collection-Klassen wie List, Set, Queue oder Map.

Auch Future für Funktionsaufrufe mit einem Ergebnis in der Zukunft ist in der Bibliothek enthalten. Eine ähnliche Bedeutung hat die Bibliothek dart:io. Neben Klassen rund um lokale Verzeichnisse und Dateien enthält sie Typen für die Netzwerkprogrammierung. Das reicht von einfachen Sockets über HTTP als Client und Server bis hin zu WebSockets. Abgerundet wird es von Klassen zum Start externer Prozesse. Sollen hingegen Aufgaben intern nebenläufig verarbeitet werden, kommt die dart:isolate-Bibliothek zum Einsatz.

Der Name dart:crypto lässt schon vermuten, was Inhalt dieser Library ist. Sie bietet Typen wie HMAC, MD5, SHA1 und SHA256. Auch dart:math erschwert es einem mit seinen Funktionen und Konstanten nicht. Ein Zufallsgenerator ist hierin ebenfalls enthalten. Der Name dart:scalarlist ist weniger eindeutig. Die Bibliothek bietet dynamische Arrays für skalare Werte vom Byte bis zum Unsigned Integer mit 64 Bit. Sie steht jedoch nur für Server-Applikationen in der eigenständigen Dart VM zur Verfügung. Universeller für die Arbeit mit unterschiedlichen Unicode Encodings ist hingegen dart:utf. Sie bietet Decoder für UTF-8, UTF-16 und UTF-32.

Die für die Entwicklung von Internet-Anwendungen wichtigste Bibliothek ist dart:html. Sie bietet eine immense Anzahl an Klassen, die die Elemente des DOM und CSS repräsentieren. Hinzu kommen Schnittstellen für Mediadaten, SVG und WebGL, in das Dateisystem, zu integrierten Datenbanken, dem Clipboard und dem Batterieladezustand. Außerdem gibt es Klassen für XML-Serialisierung, XPath und XSLT. Die sich zunehmender Beliebtheit erfreuende Alternative JSON ist Inhalt der Bibliothek dart:json. Leider unterscheidet sich das Interface der Serialisierung von Objekten in XML und JSON. Hier würde eine Nachbesserung gut tun. Dafür bietet die Bibliothek das Parsing eines XML-Strings in eine Dart-Datenstruktur. Mit der Bibliothek dart:uri lassen sich URIs kodieren, dekodieren und analysieren.

Eine Zeit lang kämpften die Entwickler noch mit dem Problem unterschiedlicher Implementierungen von dart:core und der hiermit verbundenen dart:coreimpl für den dart2js-Übersetzer und die Dart VM. Inzwischen wurde das jedoch angeglichen.