Description
Many languages have the ability to declare named values inline, in an expression context. In Haskell, you have two options -- where
and let...in...
:
https://wiki.haskell.org/Let_vs._Where
(Sorry, I know there's an issue about this somewhere, but I looked hard and couldn't find it.)
Dart really needs this, because in Flutter, you end up building these massive expression trees when building a UI. If you need a named value in the middle of the tree, you have to precompute it in a separate statement before the expression tree that you're building.
If, however, in your expression tree, you're using an inline list-builder for
statement, then you have no way to declare the value derived from the thing you're iterating over, before using it.
This is particularly problematic when calculating the value is very computationally expensive, and you need to use it twice.
For example, I am building a UI that calculates a number (which is a costly operation), for each item in a list, and then if and only if the value is greater than zero, it adds the number in a bubble to the end of the item's derived UI.
Right now I have to do something like the following:
Iterable<T> conditionalYield<T, V>({
required V Function() calcValue,
required bool Function(V value) ifTrue,
required T Function(V value) thenYield,
}) sync* {
final value = calcValue();
if (ifTrue(value)) {
yield thenYield(value);
}
}
then I can use it like this:
Column(
children: [
for (final item in items)
Row(
children: [
ItemLabelWidget(item),
...conditionalYield(
calcValue: () => item.calcExpensiveValue(),
ifTrue: (value) => value > 0,
thenYield: (value) => ValueBubble(value),
),
],
),
],
),
But I wish I could do something like
Column(
children: [
for (final item in items)
Row(
children: [
ItemLabelWidget(item),
let value = item.calcExpensiveValue()
in if (value > 0)
ValueBubble(value),
],
),
],
),
(Yes, I know build
is not supposed to be doing a lot of computational work, but the general principle here is "Don't Repeat Yourself" (DRY), and let...in...
is useful in many other situations and for many other reasons too..)
I should add that I far prefer let...in...
over where
, because where
is not as readable (values are used before they appear in the source).