class FooBase {
String? name;
FooBase({required this.name});
}
class Foo extends FooBase{
final String name;
Foo({required this.name}) : super(name: name);
}
void main() {
final foo = Foo(name: 'foo');
final fooForm = foo;
fooForm.name = 'bar';
print(fooForm.name);
}
I would expect this code to print "bar" but it prints "foo". Why so?
How to make it print "bar" ?
2
Answers
You have two
name
fields: one inFooBase
that implicitly provides a getter and a setter and afinal
one in the derivedFoo
class that provides only an implicit getter.Therefore when you do
fooForm.name = 'bar';
it invokes theFooBase.name
setter since that is not overridden by the derivedFoo
class. When you later readfooForm.name
, you invoke thename
getter, which is overridden by the derivedFoo
class to return the original'foo'
string.The morals are:
Overriding fields is usually a bad idea. (There is a lint to warn about it.) Override getters and setters instead.
Trying to make a field non-writable in a derived class is a bad idea anyway. Doing so breaks the interface and breaks the Liskov substitutability principle.
when you access fooForm.name, it is referring to the name property in the Foo class rather than the name property in the FooBase class.
To make it print "bar", you can remove the name property from the Foo class and directly use the name property from the FooBase class. Here’s the modified code: