So I've been looking at the Dart language specification recently published by Google (draft version 0.01). So far, I'm not really enthusiastic. Here's my reading notes.

Class-based OO and Interfaces

main()

At first glance Dart code looks like Java (and nothing's wrong with that, I'm not going to criticize a language based on my idiomatic preferences). The syntax is very similar, with the dot to invoke methods, the curly braces for blocks, the required semicolon to terminate statements, thefunction, the general feeling of verbosity. The familiar classes and interfaces are here. There is only single-inheritance, abstract interfaces being provided instead of full multiple inheritance to solve the diamond inheritance problem.

The spec has even a chapter on factories (static constructors). (Oh my, factories? it's like 1997 and design patterns all over again!) I should note that the integration of popular design patterns at the syntax level is disappointing: design patterns tend to emerge to work around a language design's weaknesses. Embracing them is a bit like admitting a design failure up front.

Let us just regret for the moment that more modern and useful OO paradigms, like roles, are not used here; as we have learned, interfaces are limited, since they do not allow sharing of code, only of method prototypes. But there are much more problems with Dart.

Feeble Typing

The spec says:

Ah; OK. In other words the "static checker" is a lint-type development aid, not a language feature. Worse, that means you can write functioning programs with wrong (and misleading) type declarations, and still run them. Types have no effect whatsoever on your program's semantics.

The lack of type enforcement also implies that the runtime cannot take advantage of the typing information to optimize a running program (for example by pre-resolving method calls). Via some type decoration mechanism, one could have mixed weak and strong typing; instead, it looks like the Dart designers found that type inference was too hard to implement, so they completely gave up on the advantages that typing could have brought to the runtime.

Finally, this weak typing design removes the point of using interfaces at all. Interfaces don't allow to share code; so what's the point in adding them (and having them parsed and compiled in a browser at page loading time) if they are nothing more than a fancy documentation format? Interfaces make sense only in strongly typed languages (like Java), or else you're just doing duck typing like basically every dynamic language, but without the advantages of dynamic languages (runtime addition of new methods, or calling of methods by name, for example).

The design of Dart's OO system is not consistent. I'm calling it feeble typing. It's an unassuming weak typing that can't afford to be strong but does not want to be seen with the weak typing boys.

I understand that Dart is designed to be compiled to fast Javascript. The absence of type checking, in that context, feels like a premature optimisation, and we all know what it is the root of.

I note that Dart also supports function types (describing the whole function prototype, like in C). Their purpose is not clear, since there is apparently no way to manipulate function pointers; the interface Function (apparently used for anonymous functions) does not provide any method at this point. What is the point of function types if they have no runtime existence? Moreover, the fact that named functions and anonymous ("literal") functions are different entities is disturbing.

There are generics, too. Well, I guess that the example of C++ and Java hasn't discouraged the Dart designers. Again I don't see the point of generics without type checking.

Booleans

true

if (1) { ... }

if (1==1)

Here's a strange thing: the one and only true value is the boolean literal boolean. Everything else is false. That means that code inwill never execute, because 1 is a number, not a boolean, and there is no implicit conversion to boolean. You'll need to writeinstead.

The spec hints that it's because the boolean literals true and false can be autoboxed into objects, and as objects, they would be non-null, thus defined, thus true, if any non-zero value could be true. Looks like a lot of trouble imposed on the programmer for a very minor problem that could have been fixed at the language level by allowing boolean coercion overload, or by disallowing boolean autoboxing. (It is notable that Dart allows operator overloading, but not boolean, string or numeric coercion overloading.)

Another word of warning; the operators === (reference equality), != and !== (inequalities) all return a boolean; but == is not required to do so, because it can be overloaded, and (once again) there is no runtime type enforcement on its return value. Which means that the expression (a==a) might be, in some pathological cases, false. In my opinion, this is not something that should be allowed to happen in a well-designed language.

Type conversion

toString()

int foo = 42; String bar = "${foo)";

Math

parseInt

parseDouble

There is no implicit type conversion between numeric, string or boolean types. Integers and floating point numbers are distinct types. Objects that provide amethod (that should return a string!) can be converted into a string by interpolating them, as in. Theclass provides methods to extract numbers from strings (and).

The distinction between string and numbers allows to re-use the addition operator + both for addition and concatenation. However, without strong typing, this will almost certainly prove to be a bad idea. From the specs, it looks like "2" + 2 will be a concatenation, and 2 + "2" a run-time exception (in the absence of implicit conversion from string to number), but experience infirms this: string concatenation happens in both cases (although with a warning in the second one).

Exceptions

NullPointerException

if (a) a.foo();

Speaking about exceptions. If we look at the list of standard exceptions, we see a proliferation of classes encouraging exception-based control flow. The programmers, being lazy, will naturally prefer writing catch-allhandlers instead of testing whether their objects are null -- because the syntax makes it easier for them. (Constructs likewill not work in Dart, see above.)

Another example: Ovid pointed me at the NoMoreElementsException , and added: "didn't Java programmers learn years ago that you throw exceptions for exceptional things and not for expected things?"

Isolates and heavy thread model

From the spec:

Thus, isolates are a heavyweight thread control model very much like Perl 5's ithreads. That means that they are good for data isolation, but heavy to use and hungry in memory, because spawning a new isolate will imply cloning all the objects and data structures of the running libraries. (By the way, there is no word in the spec on cloning. Apparently Dart does not have the equivalent of Perl's CLONE() method.) There are also "light" isolates, which means that they run in the same thread than the object that created them.

(Isolates are probably good for browser-side security, although the spec do not talk much about that point -- disappointing again, security should have been in mind of the designers from the start, for a JS replacement.)

However, running in a browser is not like running in a server thread, and where Perl 5's ithreads might do their job, isolates are not adapted to web-page programming. Controlling the UI of the browser, with its high level of interactivity, requires a good concurrency implementation for event processing, lazy loading of resources, and animations. Dart is weak on that point: if you want to animate multiple widgets at once in the same HTML page, you'll need one isolate for each one, with all the implied overhead. Likewise if you want to do something while an ajax call is completing, etc.

Isolates communicate via message passing. It's not clear if there is some synchronisation method available in the standard libraries, semaphore-based or other. It's not clear either how the browser events are passed to the program. I need to look at the code examples; the spec is very much formal and not practical at all.

Security

Dart provides private names, which are simply those beginning with an underscore; those names are not accessible outside the library where they are declared.

Dart provides library imports and source file includes. Not much more about it, the spec does not mention any kind of restriction about the places where code can be loaded. I suppose it will be in a future version. When importing a library, one can specify a namespace (or prefix) in which the imported names will be found, to avoid name clashes. It is not clear how Dart deals with second-level imports or recursive imports in this case. However the naming rules are clear and the removal of a global namespace was a good idea.

Conclusion

The worst of both worlds: Dart fails to provides the advantages of static languages, without compensating by the flexibility of dynamic languages. Nothing has been learned from the dynamic language renaissance of the last ten years; nothing from the functional world; nothing even from the slick concurrency model of Go and its goroutines, also from Google.

So I think it's a step backwards in language design. With Node.js and Coffeescript around, and the programming paradigms they allow, Dart looks already obsolete and inadapted.