Dart is an open-source, scalable programming language, with robust libraries and runtimes, for building web, server, and mobile apps.

Tuesday, October 11, 2016

What’s your favorite Dart feature?

Earlier this year we had an ongoing thread where Googlers shared their favorite Dart feature—perhaps a less known one. We wanted to share these insights from some of our most engaged internal users more broadly. Hence this post.

The names have been changed to protect the innocent, but the contents should constitute some fine reading.

Java has loads of these, tricks ranging from the double-paren. init (Map<String,String> {{ put("a", "1"); }};) to "sneaky throwing" ANY exception.
Anything similar in Dart?

Cheers,
Agile Analyzer

As a Java developer, my opinion of both of those is: this is clever, but don't do it in real code under any circumstances.

-Bug Basher

I'm not a fan of tricks, and from what I've seen so far Dart needs very few. There are some features of the language that I feel are underutilized or are very new. Here are a few:

- Null is a type, so if you have a Future and you want to document that it doesn't return anything useful, make it a Future<Null>
- You can throw arbitrary objects in Dart without losing stack traces: throw "This is an error"
- const can be a local variable and it will still be allocated only once (no need to hoist it into a static field or top-level constant)
- You can create custom matchers and use them in your tests (example)
- There exists package:meta that the analyzer understands, and which has @protected, @required (for required named parameters), and others
- You can implement classes as every class also exports its interface.

I see a lot of users coming to Dart from Java or C# and they are in the habit of stuffing every variable or function inside a class either because they think you have to—which you do in those languages—or out of a belief that it makes their code better in some vague "OOP paradigm is best paradigm" sort of way.

Object-orientation is a fantastic paradigm for expressing some kinds of code. It works really well when you have interesting state and interesting operations that are deeply tied to that state. It's also great when you want polymorphism based on kinds of objects.

But a lot of times, you're just trying to express some vanilla data or some imperative behavior. For those, classes don't provide any value. If you just want to define the value of π somewhere, you don't need a class named, like, I dunno "MathematicalConstants" to put it in. You can just do:

const pi = 3.1; // Eh, close enough.

Likewise, sometimes all you need is a procedure, not a method. Say you create and file and write some string to it. You could make a "FileWriter" class or something, but why bother? You can just do:

void writeFile(String path, String contents) { ... }

You might be thinking that you need to put definitions inside classes to avoid name collisions and to "namespace" things, but you don't need to do that in Dart. Libraries in Dart are the unit of namespacing and modularity. With show, hide, and import prefixes, libraries are much better at expressing namespaces and dealing with name collisions.

If you made it this far, I will note one feature that really is rarely used. Did you know that you can define getters and setters at the top level too? You can define something that looks like a top-level variable but is actually doing computation.

Cheers!
--Dart Dogfood

+1 for simple short-hands. When a language is young, there's a tendency to use it like that-other-thing-you-know. These conversations are a really good thing.

Instead of writing:

if (foo == null) { foo = 'bar';}

Just do: foo ??= 'bar';

The "cognitive load" (ahem!) is much lower. It's similar to Ruby's foo ||= 'bar' but better, because it strictly applies to nulls (vs. nil & false).

-Eager Execution

I like ??= for lazy-initialized fields

T _foo; T get foo => _foo ??= _computeValue();

--Failed Function

I wouldn't describe these as "favorite" features, but they do seem to be lesser known:

For some use cases a generator is going to be more readable than the alternatives, in others it's very tempting to write a 'clever' generator.

--Heated Hotspot

One of my favourite features is that the analyzer will tell you if you use a switch statement with an enum and don't list all the enum values.

This means that if you've been careful always to use switches when using enums (rather than if/else chains), you can just add the new value to the switch, run the analyzer, and it'll tell you all the places you need to update.

--Injected Iterator

Thanks everybody!!!

Lots of stuff to try out and/or read about! I've been actually thinking that something like the meta library would be nice (and hey, it's already live!)

I wouldn't call it a feature, but lot of people don't seem to realize (is it something originating from Java?) you can pass any function/method tearoff as an argument, not necessarily an anonymous literal, ie: