Dart’s built_value provides powerful, convenient immutable values for Dart. The values might be immutable, but the package hasn’t been standing still! In the six months since I last wrote about built_value there have been ten major improvements to the package.

I also spotted some interesting uses of built_value in the Dart community:

The built_redux package is a redux-inspired package using built_value. It comes with bindings and examples for flutter, angular2 and react-dart.

The built_highcharts package is a highcharts wrapper using built_value. The demo is really rather nice.

And, here’s another way of using built_value with Flutter.

Anyway, without further ado, here are all the great new things in built_value.

1. Generic classes

Sophisticated object models use generics, so of course built_value needs generics. You can now declare your type using generics and the generated builder class will also support them:

abstract class GenericValue<T>

implements Built<GenericValue<T>, GenericValueBuilder<T>> {

T get value;

...

} var value = new GenericValue<String>((b) => b..value = 'string');

Value types using generics are serializable, as usual.

2. Serializer plugins

A new SerializerPlugin API allows you to make cross-cutting modifications to serialization, by running arbitrary code before and after every object is serialized or deserialized.

You could, for example, use this to map between two wire-incompatible versions of a protocol. But a better example is the next improvement…

3. “Standard JSON” serializer plugin

By default, built_value serializes to and from its own list-based JSON format, for performance and flexibility.

But many people need to inter-operate with existing JSON data and APIs. What should they do?

Now, you can install StandardJsonPlugin and switch to a standard map-based JSON format.

final standardSerializers =

(serializers.toBuilder()

..addPlugin(new StandardJsonPlugin())).build();

See the example (towards the end).

4. Getter memoization

Immutable classes are great — but what should you do about derived fields? If a derived field is expensive to compute, then immutable classes give two bad options: computing them upfront and always paying a possibly unnecessary penalty, or recomputing them on demand and potentially paying that same large cost many times.

Enter @memoized getters. Add this annotation to a built_value getter and it will be calculated lazily, but at most once; it’s then stored in a hidden field on the instance.

Since 1.1.2 built_value itself is a great example of @memoized getters. A built_value is used to wrap an Element from the analyzer, and computation is done lazily in getters:

abstract class ValueSourceClass

implements Built<ValueSourceClass, ValueSourceClassBuilder> {

ClassElement get element; @memoized

BuiltList<String> get genericParameters =>

new BuiltList<String>(element.typeParameters

.map((element) => element.computeNode().toString())); @memoized

BuiltList<ValueSourceField> get fields =>

ValueSourceField.fromClassElements(element, builderElement); // And many more @memoized getters.

}

5. Faster code generation

…and as a result of moving to memoized getters, built_value is now significantly faster at generating code.