Given an abstract class
"Foo" that has a getter and setter for a "value"
abstract class Foo<T> {
T get value;
set value(T newValue);
}
I'm trying to override getter and setter to make the value final;
with the implementation below
class Bar implements Foo<String> {
@override
final String value;
const Bar(this.value);
}
the linter complains Missing concrete implementation of 'setter Foo.value'.
,
but if we add the implementation
class Bar implements Foo<String> {
@override
final String value;
const Bar(this.value);
@override
set value(String newValue) => value = newValue;
}
when we use the setter
void main() {
const bar = Bar('hello');
bar.value = 'world';
print(bar.value);
}
we don't receive ant warning about using the setter for a final value, but at runtime we incur in this error
Uncaught RangeError: Maximum call stack size exceededError: RangeError: Maximum call stack size exceeded
the problem seems to be only for the setter, therefor\
There is no correct way to disable a setter in the base class because doing so is fundamentally incorrect. A derived class must be substitutable for the base class. If the derived class did not provide a setter, then it would no longer be providing the base class's interface and would violate the substitution principle. Consider:
void updateFoo<T>(Foo<T> foo, T newValue) => foo.value = newValue;
void main() {
var bar = Bar('hello');
updateFoo(bar, 'world');
}
It is not possible to issue any compile-time warnings or errors; the implementation and call of updateFoo
are both legal from static analysis.
Instead consider:
UnmodifiableListView
do).Also, your specific exception occurs because of a different mistake in your implementation. When you do:
@override
set value(String newValue) => value = newValue;
then the value = newValue;
statement will trigger the value
setter again, resulting in infinite recursion as hinted at by the error message. If you instead tried to do:
final String _value;
@override
String get value => _value;
@override
set value(String newValue) => _value = newValue;
then your Bar
implementation would have generated a compile-time error for trying to reassign _value
, which is final
. And if you made _value
non-final
, then the compiler would have generated a compile-time error telling you that Bar
then could not have a const
constructor.