In the example below I was hoping sum getter would return 8, but it is a compile error.
Class 'B' has no instance getter 'sum'.
According to the spec:
Using an abstract class instead of an interface has important
advantages. An abstract class can provide default implementations; it
can also provide static methods, obviating the need for service
classes such as Collections or Lists, whose entire purpose is to group
utilities related to a given type.
What is the correct way to provide a default implementation of sum that adds x and y?
abstract class A {
int get x;
int get y;
int get sum => x+y;
}
class B implements A {
int get x => 3;
int get y => 5;
}
main() {
B b = new B();
print(b.x);
print(b.sum); // Not working, why not 8?
}
You have to make B extend A instead of implement.
abstract class A {
int get x;
int get y;
int get sum => x+y;
}
class B extends A {
int get x => 3;
int get y => 5;
}
main() {
B b = new B();
print(b.x);
print(b.sum); // displays 8
}
Alternatively if you don't want to use extends because your class may already extend an other class, you can use mixins :
abstract class M {
int get x;
int get y;
int get sum => x+y;
}
class A {
String s = "s";
}
class B extends A with M {
int get x => 3;
int get y => 5;
}
main() {
B b = new B();
print(b.s);
print(b.x);
print(b.sum); // displays 8
}
Another way around this issue is to just use extensions (depending on your use case). This way all your default method implementations will work regardless if you extend, implement, mixin, ect.
abstract class A {
int get x;
int get y;
}
class B implements A {
int get x => 3;
int get y => 5;
}
extension E on A {
int get sum => x+y;
}
main() {
B b = new B();
print(b.x);
print(b.sum); // 8
}
By choosing to implement A, you have to implement everything A requires even if you have provided default implementations. If you want to use default implementation from A while having the flexibility to provide your own implementations you have to use A as a mixin:
class B with A {
int get x => 3;
int get y => 5;
}
Related
abstract class A {
A(this.x, this.y);
// error: abstract classes cannot be instantiated
//
// another issue: even if you used a base concrete class
// to perform this operation, it would lose type information.
A copy({int? x, int? y}) => A(x ?? this.x, y ?? this.y);
final int x;
final int y;
}
class B extends A {
// Forced to implement copy and similar
// methods on all classes that extend A,
// which is problematic when that number
// is large or changes are necessary.
}
Is there a way to solve this problem or do I have to essentially rewrite the same code for all classes that extend A?
You can, but it requires you to do quite a lot of the work
you are asking to avoid:
class A<T extends A<T>> {
final T Function(int, int) _constructor;
final int x;
final int y;
A._(this._constructor, this.x, this.y);
T copy({int? x, int? y}) => _constructor(x ?? this.x, y ?? this.y);
}
class B extends A<B> {
B(int x, int y) : super._((int x, int y) => B(x, y), x, y);
}
(The code will get shorter when Dart gets constructor tear-offs, then it's just, super._(B, x, y);.)
You cannot, currently, inherit constructors, and you can't create an instance of a type that you don't know yet (because constructors are not inherited, so you don't know if the constructor exists). The only way to abstract over actual behavior (which code to run) is to capture it in a closure and pass it as a function.
My question is very simple, I hope, I have a class and then I wish to create a private property that is the sum of 2 others... how can I achieve it?
class Test {
Test({this.a, this.b});
final int a;
final int b;
int _c = a + b; // errors
}
Errors:
The instance member 'a' can't be accessed in an initializer.
The instance member 'b' can't be accessed in an initializer.
I believe the proper way for you to initialize _c is:
class Test {
Test({this.a, this.b}) : _c = a + b;
final int a;
final int b;
final int _c;
}
interfaces
abstract class Adder<T> {
T add(T a, T b);
}
abstract class Multiplier<T> {
T multiply(T a, T b);
}
abstract class Displayer<T> {
void display(T a);
}
An implementation that just happens to implement all three.
class IntImpl implements Adder<int>, Multiplier<int>, Displayer<int> {
#override
int add(int a, int b) {
return a + b;
}
#override
int multiply(int a, int b) {
return a * b;
}
#override
void display(int a) {
print('printing: ${a}');
}
}
A consumer that needs support for two of the interfaces.
But, I could not find how to declare such a thing.
class DisplayingAdder<T, K extends Adder<T>> {
final K engine;
DisplayingAdder(this.engine);
T addAndDisplay(T a, T b) {
final r = engine.add(a, b);
// How do I change DisplayingAdder class parametrization to make the next line functional?
// engine.display(r);
return r;
}
}
Code to exercise the above
void main() {
final e1 = IntImpl();
final da = DisplayingAdder(e1);
da.addAndDisplay(3,4);
}
Not sure what can be changed to allow the generic parameter to declare support for more than one abstract class.
You can't restrict a generic type to a type that implements multiple supertypes. The best you're going to have to do is separate engine into an object that implements Adder and an object that implements Displayer, then pass the instance of IntImpl to both. (This is more scalable anyway since it also allows you to pass different values to each if you wanted.)
class DisplayingAdder<T, A extends Adder<T>, D extends Displayer<T>> {
final A adder;
final D displayer;
DisplayingAdder(this.adder, this.displayer);
T addAndDisplay(T a, T b) {
final r = adder.add(a, b);
displayer.display(r);
return r;
}
}
void main() {
final e1 = IntImpl();
final da = DisplayingAdder(e1, e1);
da.addAndDisplay(3,4);
}
I know you can specify function types in formal arg list, but how would I do this for instance variables? I would like to do this:
class A<T> {
int compare(T a, T b);
}
where compare is a function variable with the appropriate type. I would like to be able to write:
A a = new A();
a.compare = ...
You can use typedef :
typedef Comparison<T> = int Function(T a, T b);
class A<T> {
Comparison<T> compare;
}
main() {
A a = new A<int>();
a.compare = (int a, int b) => a.compareTo(b);
print(a.compare(1, 2));
}
In addition to the Alexandre Ardhuin's answer, direct declaration, without typedef:
class A<T> {
late int Function(T a, T b) compare;
}
main() {
A<int> a = new A<int>();
a.compare = (int a, int b) => a.compareTo(b);
print(a.compare(1, 2));
}
I have the following variable and getter / setter defined in my data model:
class Actor {
int _x;
int get x => _x;
set x(int value) => _x = value;
}
And there is this generic class that requires a getter / setter function pointer
class PropertyItem {
var getterFunction;
var setterFunction;
PropertyItem(this.getterFunction, this.setterFunction);
}
How do i pass a reference of the getter / setter function of X to the PropertyItem class?
// Something like this
var item = new PropertyItem(x.getter, x.setter);
EDIT: Updated with a more clear question
In short, you don't.
Getters and setters are not extractable - they are indistinguishable from just having a field (if you don't do side-effects, of course).
In your example, you could just do:
class Actor {
int x;
}
and get exactly the same effect.
What you want is, for some Actor "actor", to make the functions yourself:
var item = new PropertyItem(() => actor.x, (v) { actor.x = v; });
This proposal about generalized tear offs is approved and will probably implemented soon and allows to closurize getters and setters like:
var item = new PropertyItem(actor#x, actor#x=);
In Dart, the following:
class Foo {
int _offsetX;
int get offsetX => _offsetX;
set offsetX(int ox) => _offsetX = ox;
}
is equivalent to:
class Foo {
int offsetX;
}