@@ -42,6 +42,13 @@ class House {
42
42
}
43
43
```
44
44
45
+ Calls to the constructor are unchanged and continue to use the public argument
46
+ names:
47
+
48
+ ``` dart
49
+ House(windows: 5, bedrooms: 3);
50
+ ```
51
+
45
52
This proposal harmonizes with (and in a couple of places mentions) the [ primary
46
53
constructors] [ ] proposal. When combined with that proposal, the above example
47
54
becomes:
@@ -268,6 +275,79 @@ class House({
268
275
});
269
276
```
270
277
278
+ ### Concerns
279
+
280
+ This proposal makes the language implicitly convert a private named parameter
281
+ into the verbose pattern users do today where they declare a public named
282
+ parameter and explicitly initialize the private field from it:
283
+
284
+ ``` dart
285
+ class C {
286
+ int? _variable;
287
+
288
+ C({int? variable}) : _variable = variable;
289
+ }
290
+ ```
291
+
292
+ While verbose, this code has the advantage of being very clear what's going on.
293
+ A reader can see that the argument name they must use at the callsite is
294
+ ` variable ` , the field is named ` _variable ` , and the latter is initialized from
295
+ the former.
296
+
297
+ Discarding the ` _ ` implicitly may be confusing for users. If a user sees a class
298
+ like:
299
+
300
+ ``` dart
301
+ class C({int? _variable}) {}
302
+ ```
303
+
304
+ They may try to call it like ` C(_variable: 123) ` and be confused that it doesn't
305
+ work. There's nothing in the code hinting that the ` _ ` is removed from the
306
+ argument name.
307
+
308
+ In general, we try to design features that are both useful once you know
309
+ them and intuitive to learn in the first place. This feature is helpful for
310
+ brevity once you know the "trick", but it's opaque when it comes to learning.
311
+ This is a real concern with the feature, but I believe the brevity makes it
312
+ worth the learnability cost.
313
+
314
+ We mitigate confusion here in a couple of ways:
315
+
316
+ #### Only allow the syntax where it's meaningful
317
+
318
+ At the language level, this proposal only allows ` _ ` in a named parameter when
319
+ doing so is * useful and meaningful* . It doesn't allow * any* named parameter to
320
+ start with underscore, only a named parameter that declares or initializes a
321
+ private instance field.
322
+
323
+ A private named parameter * looks weird* since privacy makes little sense for an
324
+ argument name and makes even less sense for the local parameter variable. (We
325
+ already have a lint that warns on using ` _ ` for local variable names since it
326
+ accomplishes nothing.)
327
+
328
+ If a user sees ` _ ` on a parameter and is trying to figure out what's going on,
329
+ they will reliably be in a context where that parameter is also referring to a
330
+ field. If we're lucky, that may lead them to intuit that the privacy is for the
331
+ field, not the parameter.
332
+
333
+ #### Provide a teaching error if they use ` _ ` for other named parameters
334
+
335
+ If a user tries to put ` _ ` before a named parameter that * isn't* an initializing
336
+ formal or declaring parameter, it's an error. That error message can explain
337
+ that it's forbidden * here* but that the syntax can be used to declare or
338
+ initialize a private field.
339
+
340
+ #### Provide a teaching error if they use ` _ ` on the argument name
341
+
342
+ If a user sees a named parameter with a private name, they may try to call the
343
+ constructor with that same private argument name, like ` C(_variable: 123) ` .
344
+ When they do, this is always an error.
345
+
346
+ The error message for that can explain that the ` _ ` is only used to make the
347
+ corresponding field private and that the argument should be the public name. The
348
+ first time a user tries to call one of these constructors the wrong way, we can
349
+ teach them the feature.
350
+
271
351
## Static semantics
272
352
273
353
An identifier is a ** private name** if it starts with an underscore (` _ ` ),
@@ -396,8 +476,23 @@ initializing formal with the private name.
396
476
Since there's no reason to * not* prefer using an initialing formal in cases
397
477
like this, it probably makes sense to have a lint encouraging this as well.
398
478
479
+ ### Good error messages when users misuse this feature
480
+
481
+ Since this feature likely isn't as intuitive as we hope to be, error messages
482
+ are even more important to help users understand what the language is doing and
483
+ getting them back on the right path.
484
+
485
+ The [ Concerns] [ ] section suggests two error cases and how good messaging there
486
+ can help users learn the feature.
487
+
488
+ [ concerns ] : #concerns
489
+
399
490
## Changelog
400
491
492
+ ### 0.2
493
+
494
+ - Add section about concerns for learnability and mitigations.
495
+
401
496
### 0.1
402
497
403
498
- Initial draft.
0 commit comments