Foreword

In the early spring of 2006, I wrote a short blog post called “Gilad is Right” where, as a recovering typaholic, I admitted that Gilad’s idea of optional and layered type systems, where static types cannot change the runtime behavior of the program and do not prevent an otherwise legal program from compiling or executing, was a necessary design trade-off for programming languages aimed at millions of developers. At that time I was working on Visual Basic, which already supported a form of optional typing by means of the Option Strict Off statement, but that feature was under heavy fire from static typing proponents. Type systems are often highly non-linear and after a certain point their complexity explodes while adding very little value to the developer and making life miserable for the language implementors. Optional and layered type systems enable a much more gradual approach by allowing strong static typing to coexist peacefully with dynamic typing. Now nearly a decade later, the vision Gilad pioneered has become mainstream under the name gradual typing. Many programming languages that have been created in the last few years, such as Hack, TypeScript, Flow, Racket, and of course Dart, are gradually typed. Even academics have embraced the idea and write papers about it with frivolous titles that include words such as “threesomes” and “blame.”

Another pragmatic aspect of Dart, but one that language purists have not yet accepted, is the fact that the Dart type system is deliberately unsound. In normal English this means that the Dart type checker will not flag certain type errors at compile time, but relies on runtime checking instead to ensure type safety. The main source of type unsoundness in Dart is covariant generics. To explain what variance is, let’s first look at a vending machine from which we can only take drinks. If a cafeteria requires a vending machine with soda pop, we can legally install a vending machine that dispenses root beer since root beer is a type of soda pop (but it is illegal to install a vending machine for soda pop where a vending machine for root beer is required). In programming language speak we say that vending machines are covariant. Next let’s take a look at garbage cans into which we can throw only garbage. If a cafeteria requires a garbage can for recyclables, we can legally install a garbage can for trash since recyclable garbage is a type of trash (but it is illegal to install a garbage can for recyclables where a garbage can for trash is required). In programming language speak we say that garbage cans are contravariant. If you are a little puzzled about contravariance you are not the only one, and you will appreciate Dart’s decision to make all generic types covariant. The consequence of that choice is that if you need a garbage can for trash, you can legally install a garbage can for recyclables, but that garbage can will reject all non-recyclable trash that people are trying to dump in it. While theoretically unsound, unsafe variance actually feels rather natural for most developers, and I applaud the choice the Dart designers made here. As anyone that has struggled with ? super and ? extends can attest, languages that have chosen in favor of static type safety for generics do so at the expense of their users.

The Dart language designers made additional pragmatic choices that make coding in Dart a smooth experience. For example Dart has no interfaces, abstract base classes, or “normal” classes. Instead Dart only has classes that can be used as interfaces by implementing them, or used as base classes by extending them, or have their implementation reused by mixing them in. Every type in Dart is an object, so there is no difference between primitive (e.g., numeric) types and regular object types. Even though everything in Dart is an object, it is possible to define top-level functions and variables, so one no longer needs the dreaded public static void main incantation inside a top-level class to get going. Dart allows user-defined arithmetic operators, but does not support type-based overloading of methods. This significantly simplifies the language. In other programming languages that do support type-based overloading, the exact semantics of that feature often take up an unjustifiably large fraction of the language specification. Null-aware operators (even null is a normal object) and cascades give more power to the dot and make every API fluent for the user with little effort from the API writer.

While Dart is essentially a dynamic language because all types are optional, you will encounter far fewer “wat” moments than with most other dynamic languages. There is null but no undefined, and hence only == but no ===. Only true is true, so no more (foo && foo.bar()) to check for null. Dart has regular integer and floating point numeric types, without the mind-blowing runtime type conversions around + and == that make great exam questions, entertaining conference presentations, but frustrating bugs.

In my opinion, though obviously I am biased, what puts Dart right at the top of my favorite programming languages is that it is the only language that I know of that supports all four essential effects of programming:

Image

That is, Dart has deep support for producing and consuming synchronous data streams (Iterable<T>) using generators and for loops inside sync* blocks, producing and consuming futures (Future<T>) using await expressions inside async blocks, and last but not least support for producing and consuming asynchronous data streams (Stream<T>) using asynchronous generators and for loops inside async* blocks. Builtin support for asynchronous programming is essential in any modern programming language, where even data in memory, let alone data across the network, is “far away” and imposes such high latency that synchronous access is prohibitively expensive. Like JavaScript, but unlike other languages that support generators, Dart has so-called delegating generators that avoid quadratic blowup of nested and recursively generated streams.

Despite all these nice touches, Dart is essentially a rather boring language by design. Thanks to support for getters, setters, lambdas, enums, reified generics, modules, an extensive well-crafted standard library, and a snappy package manager, Dart will feel comfortable, like well-worn shoes, if you are a developer coming from Java or C#, and feel like a breath of fresh air when coming from Javascript. This book will help you to understand the why, how, and what of all of Dart’s features in Gilad’s signature painstaking detail and inimitable style and get you productive in Dart in no time.

Erik Meijer
Palo Alto, California
October 2015

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.60.63