How to get properties of subclass in dart? - flutter

I have a class A with some properties:
abstract class A {
double doubleA;
String stringA;
...
A({this.doubleA = 0, this.stringA = ""});
}
and a class B with some properties, that extends class A:
class B extends A {
int intB;
String stringB;
B({
this.intB = 0,
this.stringB = "",
double doubleA = 0,
String stringA = "",
}) : super(doubleA: doubleA, stringA: stringA);
}
In my code I want to now check if an instance of A has a value that is of type of subclass B:
A a; // Value can be of different subtypes of A including B
if(a is B) {
// here dart should give me access to the properties of a like:
print(a.stringA);
// but it should also be possible to access the type B properties
// since the value of a can also be of subclass type B:
print(a.stringB);
}
This sounds wrong at first but I know that it can work because of examples in flutter.
Example Listener:
Listener(
onPointerSignal: (event) {
// event is of type PointerSignalEvent which has no property 'scrollDelta'.
// So print(event.scrollData); does not work here.
if (event is PointerScrollEvent) {
// if you check if event is of subtype PointerScrollEvent the property 'scrollDelta'
// that is included in the class PointerScrollEvent becomes available.
print(event.scrollDelta); // works without any problem.
}
},
}
However I have not been able to replicate this with my classes A and B and I don't know why it doesn't work. I have also looked into the implementations of these flutter classes and copied the class structure but I can still only access the properties of A after the check if(a is B) which doesn't correspond to the behavior observed with the flutter classes.
What am I doing wrong? Am I am missing something?
Thanks for reading :D <3

If you declare a variable 'a' as being of type 'A', you will not be able to access the properties of classes inheriting from A (like B).
Let's say A is Animal and B is Baboon. Baboon inherits properties from Animal, so all variables instantiated with the Baboon type with have access to properties from both classes. But variables instantiated with the Animal type will only have access to the Animal properties.
Here are some examples: https://medium.com/jay-tillu/inheritance-in-dart-bd0895883265

Related

Why is it necessary to use constructors in dart programming language classes?

I'm a beginner learning dart from the book dart apprentice and I reached where they were discussing constructors in dart classes, the book was implying that constructors create instances of the class which I understood but I needed more info about constructors. So I googled and some results repeated what was already in the book about it being used to create instances of a class while others also showed that it's used to instantiate class properties, but my problem is with the other answer which I found that they are used to instantiate properties of a class, but my question is: I instantiate all class properties when I create the class by declaring the property variables, like this:
class UserClass{
userClassProperty = "";
anotherUserClassProperty = ""; }
why is the constructor also needed to instantiate class properties?
Often, values are unique to every class instance.
Consider the following example:
class Point {
final int x;
final int y;
const Point(this.x, this.y);
double get distanceToOrigin => sqrt(x * x + y * y);
}
If the x and y values were defined inside the class, it would be pretty useless. Instead, different Point objects can be instantiated with different values, which means the same code can be used for different situations.
Ok, so constructors instantiate or start a class by collecting all the data the class needs to start to start working. Constructors are so important that the dart compiler provides one even if you don't explicitly create one. For example, you create a class for mammals like this :
class Mammal{
String name = "cat";
int numberOfLegs = 2;
}
Although you don't explicitly add a constructor the dart compiler adds a default constructor like this :
class Mammal{
Mammal(); //This is added by dart during the class instantiation by default.
String name = "cat";
int numberOfLegs = 2;
}
Yeah, that's how crucial constructors are to the dart compiler.
And on the topic of why are they necessary even when you declare all the properties by yourself in the class, as hacker1024 said it would make the class pretty useless, as the point of the existence of classes is to create variants but with different properties. Not adding a constructor to your class and defining all the properties in the class would mean that your class doesn't take property arguments which in turn also means that different variants of your class can't be created. Again this goes directly against the point of the existence of dart classes. For example, you have a class like this :
class Mammals{
Strig name = "Human";
int numberOfLegs = 2;
bool hasFur = false;
}
final cat = Mammal();
final human = Mammal();
print(cat.numberOfLegs); //Prints 2
//2
print(human.numberOfLegs); //Also prints 2
//2
print(cat.hasFur);
// false
Yeah, this class is problematic. Cats with 2 legs? You would agree with me that that's not how things are in reality. And also the class is pretty useless in the sense that it's not modular, no matter which kind of mammal we create be it a cat, a sheep or even a cow the name property is going to be the default one we set, that is "Human". When we create a class to simulate mammals we want to be able to define what kind of properties it has, not use some fixed values. So you want to create a class which has a constructor like this :
class Mammals{
Mammals(String name,int noOfLegs, bool hasFur){
this.name = name;
this.noOfLegs = noOfLegs;
this.hasFur = hasFur;
}
String name = "";
int noOfLegs = 0;
bool hasFur = False;
}
final cat = Mammal("Cat", 4, True); //Now you can pass in the properties ou want.
final human = Mammal("Human", 2, false);
print(cat.name); //This prints the customized name of the object cat instead of some fixed value
//Cat
print(human.name); //This prints the customized name of the object human
Now we have two instances of the class with separate property values.
Although this adds a little more code, the modularity benefit is worth it.

What does the 'get' keyword do in a dart class? [duplicate]

I am struggling with the concept of getters and setters in Dart, and the more I read, the more I cannot grasp the underlying purpose. Take for example the following code:
main() {
Car car = new Car();
car.doors = 44;
print(car.doors); // 44
}
class Car {
int doors = 4;
}
Later, I decide to make “doors” a private variable, so I do the following:
main() {
Car car = new Car();
car.doors = 44;
print(car.doors); // 44
}
class Car {
int _doors = 4;
int get doors => _doors;
set doors(int numberOfDoors) => _doors = numberOfDoors;
}
According to the code, _doors is now a private variable, and so I cannot access it in main(). However, by manipulating doors, I can indirectly change the value of _doors, which is what I thought I wanted to prevent in the first place by making it a private variable. So what is the purpose of making a previously public variable into a private one, if you can still indirectly manipulate it? And, how are getters and setters even working to change the properties of these variables? I am trying to understand the fundamental concept, because without that, I don't understand how or why getters and setters are used.
Instance variables in Dart have implicit getters and setters. So for your example code, it will operate in exactly the same way, since all you have done is changed from an implicit getter and setter to an explicit getter and setter.
The value of explicit getters and setters is that you don't need to define both if you don't want. For instance we can change your example to only define a getter:
main() {
Car car = new Car();
print(car.doors); // 4
car.doors = 6; // Won't work since no doors setter is defined
}
class Car {
int _doors = 4;
int get doors => _doors;
}
Additionally, you can also add extra logic in a getter or setter that you don't get in an implicit getter or setter:
class Car {
int _doors = 4;
int get doors => _doors;
set doors(int numberOfDoors) {
if(numberOfDoors >= 2 && numberOfDoors <= 6) {
_doors = numberOfDoors;
}
}
}
The getter and setter functions allow us to make the class appear to have a property, without a explicit property being declared (_doors in your case). The property value may be calculated from other properties.
The getters and setters allow us to execute arbitrary code when the property is get or set.
Omitting a setter makes the property immutable.
An abstract class may declare getters and setters without bodies as part of a required class interface.

How to observe field variable of other class in Mobx flutter?

I am using the flutter Mobx for state management.
I have a simple class:-
class A {
int x;
A(this.x);
}
How can I observe if x changes inside the class in another Mobx store:-
class MyStore extends _MyStore with _$MyStore {
Subs(A a) : super(a);
}
abstract class _MyStore with Store {
#observable
A a;
_Subs(this.a)
}
I want MyStore to observe the a.x.
Is it possible, if yes how?
I ran in to the same issue the other day using flutter mobx ^1.2.1+3 (dart) and
flutter_mobx ^1.1.0+2.
The first thing that comes to my mind is to annotate the field in question, I.e x with the #observable attribute. But it doesn't seem to be effective outside a store class.
So you have to observe the field using the Observable class.
To make it work your code should look something like this:
class A {
//replace with less verbose "var"
Observable<int> x = Observable(0);
A(this.x);
}
class MyStore extends _MyStore with _$MyStore {
Subs(A a) : super(a);
}
abstract class _MyStore with Store {
A a;
_Subs(this.a)
//Will be calculated whenever a change to a.x is observed.
#computed
int get xSquare => a.x.value * a.x.value;
}
As you can see I removed the observable attribute from a, since it does not need to be observed if you want to react to changes to a.x in your store. You probably noticed that you have to access the value of the observable using .value.
That should conclude how you observe a field of a class external to the store, inside your store.
I am not sure that this would be helpful since it is Javascript/Typescript, but that's what I would do :
class Foo {
#observable name = 'foo'
}
class Bar {
foo: Foo
constructor(instanceOfFoo) {
this.foo = instanceOfFoo
autorun(() => {
// Logs foo name when it changes
console.log(this.foo.name)
})
reaction(
() => this.foo.name,
() => {
// Logs foo name when it changes
console.log(this.foo.name)
}
)
}
#observable
name = 'bar'
#computed
get fooNamePlusBarName {
// recomputes automatically whenever foo or bar name changes
return this.foo.name + this.name
}
}
Basically you pass Foo instance to the Bar constructor (or just use imported singleton if it fits you), then you have 3 options: computed, reaction and autorun

Typescript : is there a way to distinguish classes with same structures?

For sure this kind of stuff could be implemented in some other way but I'm still curious why TS doesn't warn. Same structures could have different data.
class ComponentContainer<TComponent> extends Array<TComponent> {}
class Context<TComponent> extends Array<ComponentContainer<TComponent>> {}
///////////////////////////////////////////////////////
class Component<T> { constructor(public value: T) {} }
class Movable extends Component<boolean> {
constructor(value: boolean = true) { super(value) }
}
class Static extends Component<boolean> {
constructor(value: boolean = true) { super(value) }
}
///////////////////////////////////////////////////////
const ctx: Context<Movable> = new Context()
ctx[0].push(new Static()) // <-- No error
EDIT
Could be a beginning of an alternative here :https://basarat.gitbooks.io/typescript/docs/tips/nominalTyping.html
Types don't presume that value should be an instance of specified class. Movable class is used as interface here:
const ctx: Context<Movable> = new Context()
If a value should be an instance of Movable class, this check is usually performed at run time with if (value instanceof Movable). It will be tricky to implement in Array subclass, it may be better for Context to implement its own API that allows to validate values instead of extending Array.
Same structures could have different data
But they don't have different data. Static conforms to Movable interface, so it doesn't cause type error. Similarly, this will work, because the object conforms to this interface:
ctx[0].push({ value: true })
And will cause TypeScript type error if it doesn't:
ctx[0].push({ value: 1 })
It's possible to additionally enforce the value to be an instance of Movable through type checks with merged interface:
interface Movable {
constructor: typeof Movable
}
class Movable extends Component<boolean> {
constructor(value: boolean = true) { super(value) }
}
It still will be possible to cheat typing system with:
ctx[0].push({ constructor: Movable, value: 1 });
After playing a bit with your code in TypeScript Playground, it seems like TypeScript is smart enough to detect that Movable and Static are basically the same type besides their name. They are both a Component<boolean> and have no properties, so it allows you to push a new Static instance into a Movable array. Only when I added a property to Movable which didn't exist in Static then TypeScript compiler showed an error, for example:
I guess that's just how TypeScript works. It doesn't necessarily prohibit you from using different types on a generic object unless the type that's given is missing properties which exist on the expected type. That's why the following also works:

Class decorator, how to make sure the class is extending and implementing other classes

Sorry for the weird title, I don't quite know how to describe what I'm trying to do in one sentence.
I have to define a bunch of classes that are all going to extend from this one class and also implement this other class.
class SoulCoughing extends Super implements BonBon { /.../ }
class MoveAside extends Super implements BonBon { /.../ }
class LetTheManGoThru extends Super implements BonBon { /.../ }
I have written a sort of wrapper function that I use as a decorator for these classes.
const Eminem = function(klass: Constructable<????>) {
const instance = new klass();
// Do stuff
}
Constructable is a little interface I'm using because otherwise TypeScript would throw an error about not having a constructor.
interface Constructable<T> {
new(): T;
}
Now here is my problem, I don't know what type to assign to parameter klass in my wrapper function? I have tried doing this:
... function(klass: Contrusctable<Super & BonBon>)
and this:
... function(klass: Contrusctable<Super | BonBon>)
I also tried modifying my constructable interface like this:
interface Constructable<T, U> {
new(): T & U;
}
... function(klass: Contrusctable<Super, BonBon>)
but I keep getting an Argument of type 'typeof SoulCoughing' is not assignable to parameter of type 'Constructable<everythingIveTriedSoFar>' error.
So my question is, what type definition should I use with the parameter klass? I know I can just use any but I'd really like to make sure that the class being passed has extended Super and implemented BonBon.
I'm going to guess that the classes SoulCoughing etc. don't actually have no-arg constructors, and therefore cannot act as Constructable<{}> at all; the most likely culprit is that Super's constructor has a mandatory argument, which would make all subclasses fail to match new() by default. Note that this also implies that your implementation of Eminem probably wants to call new klass(...) with some arguments also.
The right way to fix it is to declare Constructable<T> to be a constructor with the right argument types. Let's say Super looks like this:
class Super {
constructor(elevator: number, mezzanine: string) {
//...
}
}
Then you could define Constructable to match:
interface Constructable<T extends Super & BonBon = Super & BonBon> {
new(chump: number, change: string): T; // same args as Super
}
and Eminem like:
const Eminem = function(klass: Constructable) {
const instance = new klass(2, "rise");
// Do stuff
}
and finally:
Eminem(SoulCoughing); // no error
I only kept Constructable generic in case you wanted TypeScript to preserve the type of the particular subclass, like so:
const SlimShady = function <T extends Super & BonBon>(klass: Constructable<T>): T {
return new klass(2, "fat");
}
// returns same type as passed-in constructor
const cutLean: MoveAside = SlimShady(MoveAside);
Okay, hope that helps; good luck!