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;
}
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.
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);
}
A little clearer than the question. I want to get the same instance of a class everywhere the class is used inside of an object. I'm using google guice through out the project. Here's an example to better explain.
#Singleton class A {
C c;
D d;
#Inject public A(C c, D d){
this.c = c;
this.d = d;
}
}
class B {
Map<Integer,String> hashmap = new Hashmap<>();
public String getInfo(Integer number){
return hashmap.get(number);
}
}
#Singleton class C {
Class B;
#Inject public C( B b){
this.b = b;
}
}
#Singleton class D {
Class B;
#Inject public D(B b){
this.b = b;
}
}
So each time a new A is created. I want that A's C and D to share the same B , but I don't want all A 's to share one B . Also C and D are being injected into the constructor and A is a Singleton.
You have to define your own scope.
To do that, read the Custom Scopes page on Guice's wiki.
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;
}
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));
}