Skip to content

Commit ee29f2e

Browse files
authored
Add sections about reading the code and flow analysis (#4554)
This commit adds two sections to the feature specification about anonymous methods. First, the introduction is extended to give some ideas about how the code can be read aloud, yielding some hints about the semantics. Next, the proposal is extended with a section that briefly describes the flow analysis of an anonymous method invocation expression.
1 parent b659adc commit ee29f2e

File tree

1 file changed

+81
-6
lines changed

1 file changed

+81
-6
lines changed

working/0260-anonymous-methods/feature-specification.md

Lines changed: 81 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ void main() => StringBuffer('Hello').{
7373
};
7474
```
7575

76+
A crucial point in both forms of anonymous method shown above is that they
77+
evaluate the receiver (the expression before the `.`) and make it available
78+
as the value of `this` in the body. As usual, members of `this` can be
79+
accessed with an implicit receiver (for example, `toString()` will call the
80+
`toString` method of the `StringBuffer` which is the value of `this`).
81+
7682
The code has now been reorganized because there is no need to have the
7783
variable `sb` any more: All the work which is done with the string buffer
7884
is now handled in the body of the anonymous method, and the two other
@@ -127,8 +133,8 @@ class A {
127133
}
128134
```
129135

130-
A useful example is where we have an expression whose value is needed
131-
several times:
136+
A useful example is where we have an expression `e` whose value is used
137+
multiple times:
132138

133139
```dart
134140
void main() {
@@ -149,8 +155,7 @@ the value null:
149155
```dart
150156
void main() {
151157
// Current approach:
152-
final x = e;
153-
if (x != null) {
158+
if (e case final x?) {
154159
foo(x);
155160
}
156161
@@ -159,8 +164,62 @@ void main() {
159164
}
160165
```
161166

162-
This rewrite works quite nicely in the case where we aren't using `x` for
163-
anything else.
167+
Consider another example where we use the explicitly named form in order to
168+
have access to more than one captured object in the same expression:
169+
170+
```dart
171+
void main() {
172+
// Using anonymous methods.
173+
e1.foo(e2, e3?.(x) => e4?.(y) => bar(x, 42, y));
174+
175+
// Expressing the same thing today, assuming that
176+
// we can change the evaluation order slightly.
177+
SomeType? arg;
178+
if (e3 case final x?) {
179+
if (e4 case final y?) {
180+
arg = bar(x, 42, y);
181+
}
182+
}
183+
e1.foo(e2, arg);
184+
}
185+
```
186+
187+
### Reading anonymous method invocations
188+
189+
In order to grasp the meaning of an expression that uses an anonymous method,
190+
the following reading technique can be helpful:
191+
192+
To recognize an anonymous method at a glance, note that it has a period
193+
immediately followed by a parameter list (look for `.(`, or a conditional
194+
and/or cascaded form like `?.(`, `..(`, or `?..(`). Otherwise, it has a
195+
period immediately followed by a function body (look for `.{` or `.=>`, or
196+
a conditional/cascaded variant).
197+
198+
For an anonymous method invocation as a whole, it may be helpful to read it
199+
as follows:
200+
201+
```dart
202+
e.=> one && two && three
203+
```
204+
205+
reads as "evaluate `e`; call it `this`; then evaluate `one && two && three`.
206+
207+
```dart
208+
e?.=> foo(this)
209+
210+
```
211+
212+
reads as "evaluate `e`; bail out if null, otherwise call it `this`; then
213+
evaluate `foo(this)`.
214+
215+
```dart
216+
e3?.(x) => e4?.(y) => bar(x, 42, y)
217+
```
218+
219+
reads as "evaluate `e3`; bail out if null, otherwise call it `x`; then
220+
evaluate `e4`; bail out if null, otherwise call it `y`; then evaluate
221+
`bar(x, 42, y)`".
222+
164223

165224
## Proposal
166225

@@ -375,6 +434,19 @@ this.
375434
as `let v = e1, _ = v.{ S } in v`, and `e1?..{ S }` is treated as
376435
`let v = e1 in v != null ? (let _ = v.{ S } in v) : null`.*
377436

437+
#### Flow analysis
438+
439+
The flow analysis of an anonymous method invocation recognizes that the code in
440+
the body of the anonymous method will be executed exactly once for the
441+
unconditional variants, at most once for the conditional variants, and it
442+
is recognized that the execution takes place immediately after the
443+
evaluation of the receiver.
444+
445+
*This implies that an assignment to a local variable `v` in the body of an
446+
anonymous method does not cause `v` to be considered non-promotable, which
447+
makes anonymous methods more convenient to work with than function
448+
literals.*
449+
378450
### Dynamic semantics
379451

380452
Consider an anonymous method invocation of one of the forms
@@ -415,4 +487,7 @@ need to consider breakage management.
415487

416488
### Revisions
417489

490+
- 1.1, 2025-Nov-3: Add a section in the introduction about how to read the
491+
code, and a section in the proposal about flow analysis.
492+
418493
- 1.0, 2025-Oct-31: Initial version of this feature specification.

0 commit comments

Comments
 (0)