dart-lang / language

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

Add variable observers willSet didSet #1136

Open dagba opened 4 years ago

dagba commented 4 years ago

Please add willset didset feature like in Swift :)

lrhn commented 4 years ago

If we consider a different syntax for getters and setters, say:

int foo {
  get => 42;
  set(v) { }
}

then we could consider also adding, say:

int foo {
  beforeSet(currentValue, newValue) { ... }
  afterSet(previousValue, newValue) { ... }
}

as interceptors. It's not particularly useful if you declare an actual setter, because you can just put that code into the setter itself, but it would make good sense as overrides in a subclass, or if we have a way to allow these interceptors for instance fields too (with their implicit setter). It would effectively still just declare one setter, it would just be automatically delegating to the super-setter between the before/after blocks.

There is some kind of aspect oriented feel to this. We could equally well add beforeCall and afterCall on instance methods, which would be just shorthand for a method which flanks the implicit super-method propagation with the before/after code.

So, nothing here which cannot be done today, but potentially more convenient. Rather than:

class C {
  int _foo;
  int get foo => _foo;
  set foo(int value) { 
    _beforeCode(); 
    _foo = foo; 
    afterCode(); 
  }
}

you'd write

class C {
  int foo : {  // The `:` could signify that it's an `int foo` field with interceptors.
    beforeSet => _beforeCode();
    afterSet => _afterCode();
  }
}

Alternatively, we could allow explicit setter/getter override on a field declaration:

class C {
  int foo : {
    set(newValue) {
      _beforeCode();
      foo = newValue;  // doesn't call setter, sets underlying cell directly, like the implicit setter would.
      _afterCode();
    }
  }
}

(In that case, int foo; would be shorthand for

 int foo :  {
   get => foo;
   set(value) { foo = value; }
 }

where the implicit getter/setters would be expressible as explicit getters or setters. It's only inside getters/setters for foo that you can assign directly to the underlying storage, everything else goes through the getter/setter).