I get the error, when declaring a _disposers variable.
The instance member 'name' can't be accessed in an initializer.
class FormStore = _FormStore with _$FormStore;
abstract class _FormStore with Store {
#observable
String name = '';
List<ReactionDisposer> _disposers = [
reaction((_) => name, validateUsername), // error on name and on validateUsername
];
// ...
It prompts
Try replacing the reference to the instance member with a different
expression
Why there is the error and why this error disapears if put late before List<ReactionDisposer> _disposers?
You can't initialize an instance member like _disposers using other instance members (like name) because dart doesn't let you use a reference to "this" in initializers.
https://dart.dev/tools/diagnostic-messages#implicit_this_reference_in_initializer
When you use late it becomes lazy, which means it will get initialized/evaluated only when needed (usually when you call it).
Related
I've recently found myself in a situation where I wanted to check if a Type is a subtype of another Type this is what I've tried
abstract class Record{}
class TimeRecord extends Record{}
void test(){
print(TimeRecord is Record); // return false but why ??
}
The only time it makes sense to check if one type is a subtype of another type is when at least one of the types is a type variable. (Otherwise, you can just look at the source and write a constant true or false into the code).
There is a way to check whether one type is a subtype of another, and it does use the is operator, but you need to have an instance as the first operand and a type as the second. You can't just create an instance of an unknown type, so we instead rely in Dart's covariant generics:
bool isSubtype<S, T>() => <S>[] is List<T>;
(You can use any generic class, or even create your own, instead of using List. All it needs is a way to create the object.)
Then you can write:
print(isSubtype<TimeRecord, Record>()); // true!
The is keyword is used to check if an object instance is an object of type T, and not if a type is another type:
abstract class Record{}
class TimeRecord extends Record{}
void test(){
print(TimeRecord() is Record); // returns true!
}
Just to add up to #lrn answer.
You could also do something like:
extension NullableObjectsExtensions<T> on T {
bool isSubtypeOf<S>() => <T>[] is List<S>;
bool isSupertypeOf<S>() => <S>[] is List<T>;
}
So this way you can test any variable anywhere.
I found something strange in dart. If there is a list that contains instances of a base class (in this example Super), the list can be set with a list of inherited instances. It seems that this changes the list type at runtime.
Is this intended behavior or is this a bug in Dart?
abstract class Super {}
class A extends Super {}
class B extends Super {}
class Container {
List<Super> mylist = [];
Container(this.mylist);
}
void main() {
// 1. dont't works
final container = Container(<A>[A(), A()]);
// 2. works
final container = Container([A(), A()]);
print(container.mylist.runtimeType);
container.mylist.add(B());
print(container.mylist);
}
If case 1 is used in the code above I get the following error:
JSArray<A>
Uncaught Error: TypeError: Instance of 'B': type 'B' is not a subtype of type 'A'
The error is at the line where I try to add an instance of B:
container.mylist.add(B());
Dart has a system called type promotion, where it can promote the type of a variable, similar to type inference.
It works as a cast. On the first example you've explicit promoted the type of your list to be of type A, so there's nothing strange about this.
Take a look at the first article that explains this mechanism.
When you do:
final container = Container(<A>[A(), A()]);
you explicitly create a List<A> object. Although Container's constructor expects a List<Super>, it accepts a List<A> argument because Dart considers Generic<Derived> to be a subtype of Generic<Base> if Derived is a subtype of Base. Your later attempt to do container.mylist.add(B()); will fail because container.mylist is actually a List<A> and therefore cannot legally store any B elements.
When you instead do:
final container = Container([A(), A()]);
then, because the List literal is not given an explicit type, its type is inferred to be List<Super> from Container's expected construction parameter. container.mylist.add(B()); will succeed since container.mylist is actually a List<Super> and therefore can legally store B elements.
I have an abstract class ImageUpdate. Two classes, NewImage and ExistingImage implement ImageUpdate.
I have a variable imageUpdates of type List<ImageUpdate>.
When I try adding a variable of type NewImage to the List, I get this error:
Unhandled Exception: type 'NewImage' is not a subtype of type 'ExistingImage' of 'value'
I am pretty stumped, since the list is of ImageUpdate and not ExistingImage, so I have no idea how to debug it, especially since Dart is type safe (nowhere am I using dynamic).
I suspect that you have code similar to:
class Base {}
class Derived1 extends Base {}
class Derived2 extends Base {}
List<Base> makeList() {
var list = [Derived1()];
return list;
}
void main() {
var list = makeList();
list.add(Derived2()); // TypeError
}
What happens is that the List object is originally created as a List<Derived1>. (That is, list.runtimeType will be something like List<Derived1>, not its static (declared) type of List<Base>.) Then, when you try to add a Derived2 object to list, it will fail at runtime because list's actual, runtime type is List<Derived1>, which does not allow Derived2 elements.
This ultimately stems from Dart allowing implicit type conversions from GenericClass<Derived> to GenericClass<Base> if Derived derives from Base. This is useful in many cases, but it also can lead to situations like this one that fail at runtime.
You can fix this by explicitly stating that you want a List<Base> object:
List<Base> makeList() {
var list = <Base>[Derived1()]; // Note the explicit type.
return list;
}
or, if that's not possible, by creating a new List<Base> object:
var list = <Base>[...makeList()];
var list = List<Base>.from(makeList());
(In this particular situation, List.of(makeList()) also would work since it would create a new List object with the static type, but I wouldn't use that since being explicit about the type conversion would be more readable.)
I have made a member function in a class. Afterwards I want to make a member value that is set to the result of this member function.
type MyType() =
member this.drawFilledPlanet(xCoord:int, yCoord:int, pWidth:int, pHeight:int, color) =
let brush = new System.Drawing.SolidBrush(color)
this.window.Paint.Add(fun e ->
e.Graphics.FillEllipse(brush, xCoord, yCoord, pWidth, pHeight))
member val theSun = drawFilledPlanet(350,350,100,100, this.yellow)
I am getting the error that drawFilledPlanet is not defined.
Can someone tell me what is up?
Because drawFilledPlanet is a member function, it needs a class instance on which it's to be called. If you're calling it from another member function, you would use that member's definition to name the current instance:
member this.f() = this.drawFilledPlanet ...
In your case, however, since you're defining a member val, you don't have that opportunity. In this situation, you can name the current instance at the very top of the class declaration:
type MyType() as this =
...
member val theSun = this.drawFilledPlanet ...
One thing I'd like to point out is that this definition may not have the effect that you expect. If you define theSun this way, the drawFilledPlanet method will only get executed once at class initialization, not every time theSun is accessed. Did you intend that? If no, then you need to change the definition. If yes, then why do you need this definition at all?
I wish to have the sub-classes of a super-class "registered" by an arbitrary name - whenever I declare a sub-class I wish to also have it entered into the super-class.sub Map.
Is there any way to accomplish this outside of main()?
// base class
class Mineral{
final String formula;
static Map<String,Mineral> sub = {}
Mineral( this.formula );
}
// sub class - declare and register
class Mica extends Mineral{
Mica( String formula ) : super( formula );
}
Mineral.sub['mica'] = Mica; // oops!
when I run this, I get
Error: line 10 pos 1: unexpected token 'Mineral' Mineral.sub['mica'] = Mica;
assuming that executable code is not allowed outside main().
cannot put within the super-class since other sub-classes may declared later, outside the library.
Dart has no way to run code as part of a library being loaded.
Executable code can only be put inside methods, or in field initializers, and static field initializers are lazy so they won't execute any code until you try to read them.
This is done to ensure quick startup - a Dart program doesn't have to execute any code before starting the main library's "main" method.
So, no, there is no way to initialize something that isn't constant before main is called.
Either
Mineral.sub['mica'] = new Mica();
or
static Map<String,Type> sub = {};
When you assign Mica you assign the Type Mica. new Mica() is an instance of Mica that is of the kind Mineral and can be assigned to the map you declared.
edit
Maybe you want to initialize the sub map:
static Map<String,Mineral> sub = {'mica': new Mica()};
hint: the semicolon is missing in this line in your question.