Reputation: 4584
I'm trying to use the Dart cascade operator to implement a builder pattern.
I have this (hacked) class:
import 'package:test/test.dart';
class Scope
{
void value<T>(ScopeKey<T> key, T value) {}
R run<R>(R Function() callback) => callback();
}
int use(String key) => 18;
I want to use a cascade to call the 'run' method which should return a value.
What I want to do is:
final ageKey = ScopeKey<int>();
final age = Scope()
..value<int>(ageKey, 18);
.run<int>(() => use(ageKey));
expect(age, equals(18));
Note the single '.' before 'run'.
What I have to do is:
final ageKey = ScopeKey<int>();
final scope = Scope()..value<int>(ageKey, 18);
final age = scope.run<int>(() => use(ageKey));
expect(age, equals(18));
My understanding is that .. discards the result of the value
call and instead returns the Scope
object.
So Scope()..value()
should return a Scope.
As such I'm expecting the call
Scope()..value().run() => 1
to return 1 as the left hand operand to run should be the Scope
object.
Instead it generates a compile error:
This expression has a type of 'void' so its value can't be used. Try checking to see if you're using the correct API; there might be a function or call that returns void you didn't expect. Also check type parameters and variables which might also be
This implies that .run is using the return value of value
.
What am I misunderstanding here?
Upvotes: 1
Views: 619
Reputation: 6736
You can add parenthesis so that .run
is called on your Scope
.
final age = (Scope()..value<int>(ageKey, 18)).run<int>(() => use(ageKey));
With cascades you can currently do things like this:
class Collection<T> {
List<T> items = [];
@override
String toString() => 'Items($items)';
}
void main() {
final items = Collection<int>()
..items.add(1);
print(items);
}
This only works because .add
is called on items
rather than Collection
. The downside is if you wanted to call a method on Collection
after the cascade call you have to wrap the expression in parenthesis.
Upvotes: 1