-
Notifications
You must be signed in to change notification settings - Fork 213
Post NNBD setter/getter consistency requirements #331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Note the overlap between this issue and dart-lang/sdk#36126, dart-lang/sdk#36127, where we decided to clarify our general approach to warnings and then request implementations of the resulting rules. I think it would make sense to stick to that plan in the following sense: First we clarify (here) what the relevant relation should be. To me it seems like 'assignable' would make sense, such that we preserve the requirement that In any case, we will then have an answer for this issue when we decide whether "getter return type is not |
I think the current getter/setter-with-different-types situation is a little too inconsistent in every case. If we remove implicit downcasts in NNBD by redefining "assignable to", then we either need to change the use of "assignable to" here to include "or vice versa", or change the language. This is not a cast unless you actually do If we change the language, it is a breaking change, whether we require the setter type to be a subtype of the getter type or a supertype. There might be code that does the other thing. (I really want to get to a place where getters/setters are not individual members, but linked accessors of a single "property" which has just one type. Even if we don't introduce a combined syntax, everything should still act as if a property is one single thing). The analyzer warning is just a lint, it can do whatever it wants, but it should probably not let the "is assignable to" relation be affected by "no implicit downcasts" in places where there is no actual cast. |
OK, that makes sense. Here is a concrete example where it is a meaningful design choice that the setter has stronger requirements than the getter: abstract class Foo { /*Useful interface stuff*/ }
class UninitializedFoo implements Foo { /*Dummy implementations*/ }
class RealFoo implements Foo { /*This implementation will do real work*/ }
// Maybe also `class RealFoo2/3/4/... implements RealFoo`, doing real work.
Foo _fooImpl = UninitializedFoo();
Foo get foo => _fooImpl;
set foo(RealFoo newFoo) => _fooImpl = newFoo; The point is that we have a property I think this serves to illustrate that it can be a meaningful design choice to make the setter more constrained than the getter. Do we wish to preclude such designs? |
I do, but that might just be me. It means you can't do I personally wouldn't use a setter at all for a design like that, but probably have a more specialized function like I really want to get to the point where we can have syntax like: Foo foo {
get => _fooImpl;
set(v) { _fooImpl = v; }
} and not have any reason to use the old syntax. |
YES PLEASE. I have a sketch of a proposal for something very similar to that sitting on my laptop, waiting for more time to work on it. |
We propose to leave this unchanged. TODO: specify that the relationship must be subtyping (that is, we do not special case dynamic as we do in assignability) |
This has been specified. |
Re-opening this based on feedback from the migration. From @a14n in the Flutter porting work:
TextSelection? get textSelection => _textSelection;
TextSelection? _textSelection;
set textSelection(TextSelection? value) {
assert(value != null);
_textSelection = value;
_hasBeenAnnotated = true;
} This code is currently rejected, and is not an unreasonable pattern. Should we re-consider relaxing the assignability requirements, either entirely, or to account for nullability? cc @Hixie |
After checking it doesn't seem to happen too frequently. |
Probably worth fixing the API for the cases where it does happen, rather than changing the language. It's very weird to have a getter be able to return a value that its equivalent setter can't set. |
I don't know if it's a bug but with the following code I only see analyzer error for class A {
String get s => '';
set s(String value) {}
}
// nullable getter and non-nullable setter
class B {
String? get s => '';
set s(String value) {}
}
// non-nullable getter and nullable setter
class C {
String get s => '';
set s(String? value) {}
} |
That's correct, the rule is basically that By the way, the bool _hasBeenAnnotated = false;
TextSelection? _textSelection;
TextSelection? get textSelection => _textSelection;
set textSelection(TextSelection value) {
_textSelection = value;
_hasBeenAnnotated = true;
} |
FWIW, we wouldn't to see C in Flutter code either. The domain of a setter should match the range of its getter. |
We discussed this last week in the language meeting, and the general consensus was that we prefer to keep the restriction. Thanks for the input, I'll close this out again. |
With --no-implicit-casts turned on, the analyzer currently makes the following an error:
I believe this is an unintentional result of making
assignable
asymmetric. The specification says that:Turning on --no-implicit-casts essentially re-interprets "$S$ may not be assigned to$T$ " to be "$S$ is not a subtype of $T$ ".
Do we want to treat this as a bug and fix it, or is this the right behavior for the post NNBD world.
In it's defense, this "bug" is enforcing the very sane property that
a.f = a.f
should not be a type error.cc @nshahan @munificent @lrhn @eernstg
The text was updated successfully, but these errors were encountered: