dart-lang / language

Design of the Dart language
Other
2.66k stars 205 forks source link

Proposal: allow field formal parameters in setters #217

Open MichaelRFairhurst opened 5 years ago

MichaelRFairhurst commented 5 years ago

@dmincu had this idea in an AngularDart training and I think it makes perfect sense. Not sure if this has been considered before, it seems like an easy non-breaking change to add.

This would be useful for cases where you override a setter that has a private backing store where the side-effect is not a special assignment of that backing property:

class C {
  int _myInt;

  set myInt(this._myInt) {
    print("set myInt to $_myInt");
  }

  // vs
  set myInt(int myInt) {
    _myInt = myInt;
    print("set myInt to $_myInt");
  }
  ...
}

as well as cases where you override the setter only because you overrode the getter (and still want both for your field):

class C {
  int _myInt;

  set myInt(this._myInt); // nothing special
  int get myInt {
    // ...
  }
}

I wouldn't go so far as to file these as language issues, however, I think the feature is still something that would be useful.

munificent commented 5 years ago

I think this is a great idea. In fact, I'd take it farther and allow any parameter in any method to be an initializing (well, assigning) formal.

andreashaese commented 5 years ago

Looks like a very fitting addition to Dart 👍

On a tangential note, I would expect the following to work too:

get myInt => _myInt;

Interestingly, myInt's type can't be inferred (dynamic in non-strong mode, error in strong mode). Does that justify a separate pitch?

andreashaese commented 5 years ago

dart 2 has only strong mode, nothing else

Sorry, I should have been more clear: I was referring to the analyzer's explicit strong mode that emits errors instead of defaulting to dynamic if a type can't be inferred during static analysis:

analyzer:
  strong-mode:
    implicit-casts: false
    implicit-dynamic: false

if _myInt is declared as int, the type gets inferred correctly

Are you using a secret Dart 3 version of DartPad 😄 Or do you mean the runtime type? If I copy&paste the following code into DartPad

class Test {
  int _myInt;
  get thisIsInt => _myInt;
  get thisIsBool => true;
}

and place the cursor on thisIsInt and thisIsBool, their static types are shown as get thisIsInt → dynamic and get thisIsBool → dynamic.

andreashaese commented 5 years ago

Yes, I know. The motivation for my question is that if we get this shorthand syntax for write-only setters, then read-only getters look a bit unbalanced:

set myInt(this._myInt)
int get myInt => _myInt; // why do I need to repeat the type here?

Of course I wouldn't want to make an exception only for getters, but to me that would seem sensible for any method/function where the available type information is sufficient. I wonder if the current design is deliberate, given that Dart is technically able to infer unambiguous function signatures:

class Test {
  final one = (int a) => '{a}'; // (int) -> String
  two(int a) => '{a}'; // (int) -> dynamic, why?
}

With that said, I don't want to derail the conversation about setters and would be happy to move this over to separate issue.