Reputation: 2965
In Dart 2.6.0, when I use is
to test the type of a class member variable, the conditional code block does not inference the type.
In the following code, the method show1()
produces the error, "The getter 's2' isn't defined for the class 'C1'." Meanwhile, the method show2()
compiles just fine.
class C1 {
C1(this.s1);
String s1;
}
class C2 extends C1 {
C2(String s1, this.s2) : super(s1);
String s2;
}
class InferenceTest {
InferenceTest(this.c);
C1 c;
void show1() {
print(c.s1);
if (c is C2) print(c.s2); // error
}
void show2(C1 c) {
print(c.s1);
if (c is C2) print(c.s2); // no error
}
}
This seems like a bug, but it also seems like I shouldn't be the first to notice this. I encountered the problem trying to use inferencing on widget.myValue
from a widget State.
Have I found a bug, or is there something I'm not understanding?
(I'd find this reasonable in a multi-threaded environment like Java, because the value of c
could change between the is
test and the use of c
. But I understand that Dart largely assumes a single thread.)
Upvotes: 1
Views: 94
Reputation: 71653
Dart does not type-promote instance variables, only local variables.
When you test that a local variable has a specific type, then the program can use the variable as if it had the tested type ... with some caveats because the language needs to be absolutely sure that the value doesn't change between the test and the use. For example, there must be no assignments to the variable in the scope guarded by the test, and there must be no assignments to the variable captured in a closure. Because the variable is local, the compiler can assure itself that this is sufficient to ensure that the variable value doesn't change.
The instance variable c
of the class InferenceTest
has type C1
. There are valid programs where the value of c
can change between the test c is C2
and the use c.s2
, and it can be changed by code in a completely different library, so the language does not dare to do type promotion in that case. Therefore the type of c
is still C1
at the c.s2
access, and you can't access s2
.
If you want the promotion, try moving the value into a local variable:
var c = this.c;
if (c is C2) print(c.s2);
This works, which is also what you see in your show2
method because function parameters are local variables and therefore subject to type promotion.
Upvotes: 3