Getting value of a class variable through mirroring via getField - dart

I am trying to understand how the Mirrors Api works. Specifically, how to obtain the value of a field from its Symbol, using getField.
For the getField method, it should work for any Symbol which is a getter, and it might be implicit. I therefore understood this that getField could be called directly on fields. In the following code sample, the getters for a and b should be implictly defined.
But the code throws, complainining that it cannot find any getter.
Breaking on exception: object of NoSuchMethodError, and breaking in 'dart:mirrors-patch_mirrors_impl.dart' on native "ClassMirror_invokeGetter";
abstract class CheckInitialized {
bool hasNull() {
var im = reflect(this);
var cm = im.type;
cm.declarations.values.where((dm) => dm is VariableMirror)
.forEach((vm) {
print(cm.getField(vm.simpleName));
});
// If field is null, return true
// If no fields are null, return false
}
}
class Test extends CheckInitialized {
int a;
String b;
}
void main() {
var a = new Test();
print(a.hasNull()); // true
}
It feels wrong to have to explicitly define a getter for this to work, but I can't see why this is not working. Of course, mirrors.dart is still very much changing, so I inlude that this is for v1.2.0.

You are trying to run getField on the class mirror. Since a and b are instance fields the getField fails. If you change a and b to static the getField invocations will work.
Alternatively you need to invoke getField on the instance-mirror (im).

Related

Is it possible to force a Type to be used only in static fields?

I'm working on a library, and I have a implementation pattern users are required to follow:
class MyView extends LibView {
static Foo f = Foo();
#override
void render(){
use(f); // f should be static, otherwise things not work correctly
}
}
I would like to tell the compiler that, if someone ever does this, it's incorrect:
class MyView {
Foo f = Foo(); // Error: Foo can only be used in Static field.
...
}
Anyone know if this is possible? I find it really hard to find good docs on these sorta of language details when it comes to dart.
[EDIT] Since the "why" question always comes up, imagine something like:
class ViewState{
Map<int, Object> props = {};
}
ViewState _state = ViewState();
class View {
View(this.state);
ViewState state;
static int _key1 = getRandomInt();
void render(){
print(state(_key1))
}
}
// These should both print the same value off of state since the 'random' int is cached
View(_state);
View(_state);
If the key's were not static, everything would compile fine, but they would not print the same results.
What you properly need are a singleton which can be created in different ways in Dart. One way is to use a factory constructor like this:
class Foo {
static final Foo _instance = Foo._();
factory Foo() => _instance;
// Private constructor only used internally
Foo._();
}
void main() {
final a = Foo();
final b = Foo();
print(identical(a, b)); // true
}
By doing it like this, there will only be one instance of Foo which are then shared each time an instance are asked for. The instance are also first created the first time it is asked for since static variables in Dart are lazy and only initialized when needed.
I just want to do the functional equivalent of
int someUniqueKey = 0, or MyViewEnums.someUniqueKey but do it with a typed object rather than a int/enym, like: Object<Foo> someUniqueKey = Object<Foo>(). In order for this to work with Objects, it needs to be static. It's similar to how int someUniqueKey = random.nextInt(9999) would have to be static in order to be used as a key that all instances could share. That way keys are auto-managed and unique, and people don't need to assign int's, strings, or whatever. It also has the advantage of letting me use the type later for compile time checks.
bool prop = getPropFromRef(_prop1Ref); //Will throw error prop1Ref is not Ref<bool>
I think I've figured out something that does the trick using darts package-level methods.
class Ref<T> {}
// Re-use existing ref if it already exists
Ref<T> getRef<T>(Ref<T> o) => o ?? Ref<T>();
class RefView {}
// In some other package/file:
class MyView extends RefView {
static Ref<bool> prop1Ref = getRef(prop1Ref);
static Ref<int> prop2Ref = getRef(prop2Ref);
}
This will make sure that prop1 and prop2 have the same values across all instances of MyView and it will throw an error if these are not static (since you can not pass an instance field before Constructor)
This still has the downside of a potential hard to spot error:
class MyView extends RefView {
static Ref<bool> prop1 = getRef(prop1);
static Ref<bool> prop2 = getRef(prop1); // passing prop1 to prop2's getRef, and they have the same<T>, compiler will miss it
}
But I think it might be preferable than having this potential error:
class MyView extends RefView {
//Both of these will fail silently, keys will change for each instance of MyView
Ref<bool> prop1 = getRef(prop1);
Ref<bool> prop2 = getRef(prop2);
}

Dart "upcasting" is not actually upcasting

I am trying to up-cast the subclass object but it is not working.
The following program compiles without any errors.
VideoStreamModel model = VideoStreamModel("");
VideoStream entity = model;
print(model); // prints VideoStreamModel
print(entity); // prints VideoStreamModel
print(entity as VideoStream); // prints VideoStreamModel
print(cast<VideoStream>(model)); // prints VideoStreamModel
I have written a testcase to test the relation of above two classes and it passes.
test('should be a subtype of VideoStream', () async {
expect(model, isA<VideoStream>());
});
What could be the problem here?
EDIT:
[deleted]
EDIT 2:
[deleted]
Edit 3:
Here is the complete code reproducing the error.
import 'package:equatable/equatable.dart';
import 'package:test/test.dart';
class A extends Equatable {
final String x;
A(this.x);
#override
List<Object> get props => [x];
}
class B extends A {
B(String x) : super(x);
A method() {
B b = B(x); // doing A b = A(x) makes the test pass
return b;
}
}
void main() {
B b = B("");
test('test', () async {
final expected = A(b.x);
final actual = b.method();
expect(actual, expected);
});
}
It generates the following assertion error:
Expected: A:<A>
Actual: B:<B>
print is calling the toString() on the object you are pointing at (in this case VideoStreamModel) which knows what type it is. When you are casting, you are not changing anything about the object itself but only how the compiler should see the object when it determines if you are allowed to use a given typed variable to point to the object.
So when you are doing entity as VideoStream you are really just telling the compiler that you "promise" that the entity can be seen as a VideoStream. But on runtime, this cast will be tested to see if it is true.
All of this is really not an issue since you should never test for the specific type of the object when you are programming Dart but instead use the is operator which tests if a given object is compatible with a given interface.
So e,g, (entity is VideoStream) will return true.
Updated part
You problem seems to be a misunderstanding of the use of Equatable. It is important to notice that Equatable are not only using the elements from props to determine if two objects are equal but it also looks at the runtimeType. You can see this from the implementation:
#override
bool operator ==(Object other) =>
identical(this, other) ||
other is Equatable &&
runtimeType == other.runtimeType &&
equals(props, other.props);
https://github.com/felangel/equatable/blob/master/lib/src/equatable.dart#L46
This means that:
A a = A("");
B b = B("");
print(a == b); // false
When you are using expect without any matcher, it will just make an == operation which is stated in the documentation:
matcher can be a value in which case it will be wrapped in an equals matcher
Since we (as stated before) cannot change the runtimeType of an object after its creation you need to implement your own == if you want the two object instances to be seen as equal since equatable does only see two objects as equal if they both is created from the same class and contains the same values defined with props.

How can I use `class` as Map's key?

I use Piece class as Map's key.
But when this code ran, error occured Uncaught exception:
C.JSNull_methods.$indexSet is not a function.
class Piece {
int type;
Piece(this.type);
}
void main() {
Map<Piece, int> hand;
hand[Piece(5)] = 5;
if (hand.containsKey(Piece(5))) {
print("contains");
}
print('${hand[Piece(5)]}');
}
In dart-lang, how can I use class as Map's key?
First, the error you got has nothing to do with using types as keys but are before you never initialize the hand variable. So you need to do this:
Map<Piece, int> hand = {};
Now, you will not get the exception but your code will properly not work as expected since hand.containsKey(Piece(5)) will return false and print('${hand[Piece(5)]}') will return null.
This is because the map Map<Piece, int> are not using the Type as key but instead objects of the type Piece. So if we take your code here:
Map<Piece, int> hand = {};
hand[Piece(5)] = 5;
if (hand.containsKey(Piece(5))) {
print("contains");
}
print('${hand[Piece(5)]}');
You are here creating a new object instance of the Piece type each type you are writing "Piece(5)". Since each of this objects will be a separate instance of a Piece then you will not receive the value 5 you have saved because the value 5 has been saved for a different object than you are requesting.
There are multiple solutions for that and I don't know which one are the best for you. But the simple solution in this case is to either only creating one instance of Piece and reuse that:
void main() {
Map<Piece, int> hand = {};
final piece = Piece(5);
hand[piece] = 5;
if (hand.containsKey(piece)) {
print("contains");
}
print('${hand[piece]}');
}
Or make a const constructor for your Piece class so instances with the same arguments are made into the same object. This solution requires that the int type are final since you cannot edit a const constructed object (since it is constant):
class Piece {
final int type;
const Piece(this.type);
}
void main() {
Map<Piece, int> hand = {};
hand[const Piece(5)] = 5;
if (hand.containsKey(const Piece(5))) {
print("contains");
}
print('${hand[const Piece(5)]}');
}
Note that you need to prefix you object instantiation with const like "const Piece(5)" each time you want a instance where you are sure it will returns the same object for the same arguments.

Does FutureOr<T> have a reified type of Future<T> / <T>?

I have a class in AngularDart as followings:
abstract class Validator {
Map validate(AbstractControl c);
}
Looking closely, this used to be (before we added strong-mode support):
abstract class Validator {
validate(AbstractControl c);
}
The issue that it technically supports returning a Future or Map.
I'd like to refactor this and properly type it using FutureOr:
abstract class Validator {
FutureOr<T> validate(AbstractControl c);
}
Will I be able to use an is check at runtime? (In DDC and dart2js)
void runValidator(Validator v) {
var result = v.validate(...);
if (result is Future) {
// async...
} else {
// sync...
}
}
Am I thinking about this correctly?
EDIT: As mentioned below, I mean
if (result is Future<T>) {
} else if (result is T) {
}
One more question, would validate match these two typedefs:
Future<Map> AsyncValidate(AbstractControl c);
Map SyncValidate(AbstractControl c);
Yes, you can do result is Future<Map>. The actual value returned by the validate method is either a Future or it's not. The static type of the function doesn't affect that, and since FutureOr<Map> isn't an actual class, you can't have an object that is "a FutureOr". It's either a real Future<Map> or it's a Map.
For the second question, that depends on what yo mean by "match".
You can override the method with a method that returns either Map or FutureMap:
abstract class Validator {
FutureOr<Map> validate(abstractControl c);
}
class AsyncValidator extends Validator {
Future<Map> validate(AbstractControl c) {...}
}
class SyncValidator extends Validator {
Map validate(AbstractControl c) {...}
}
That is, you can use one of the function types you mention as a Validator.validate, but not in the other direction.
typedef FutureOr<Map> Validate(AbstractControl c);
typedef Future<Map> AsyncValidate(AbstractControl c);
typedef Map SyncValidate(AbstractControl c);
Validator v = ...;
Validate f0 = v.validate; // Safe.
AsyncValidate f1 = v.validate; // BAD assignment.
SyncValidate f2 = v.validate; // BAD assignment.
Map syncValidate(AbstractControl c) { ... }
Future<Map> asyncValidate(AbstractControl c) { ... }
v = syncValidate; // Good assignment.
v = asyncValidate; // Good assignment.
In practice, the concrete validate method of the validator v will probably be assignable to one of f1 or f2, but its static type doesn't say which one, so both are considered bad assignments.
You should only very rarely have a non-abstract method that is declared as returning FutureOr. In most cases, it's better to just always return a Future or a non-Future, and declare the method as such. Then you can always use the function as returning FutureOr if you need to, but use the more precise type in cases where you need it.

Is there a way to pass a primitive parameter by reference in Dart?

I would like to pass a primitive (int, bool, ...) by reference. I found a discussion about it (paragraph "Passing value types by reference") here: value types in Dart, but I still wonder if there is a way to do it in Dart (except using an object wrapper) ? Any development ?
The Dart language does not support this and I doubt it ever will, but the future will tell.
Primitives will be passed by value, and as already mentioned here, the only way to 'pass primitives by reference' is by wrapping them like:
class PrimitiveWrapper {
var value;
PrimitiveWrapper(this.value);
}
void alter(PrimitiveWrapper data) {
data.value++;
}
main() {
var data = new PrimitiveWrapper(5);
print(data.value); // 5
alter(data);
print(data.value); // 6
}
If you don't want to do that, then you need to find another way around your problem.
One case where I see people needing to pass by reference is that they have some sort of value they want to pass to functions in a class:
class Foo {
void doFoo() {
var i = 0;
...
doBar(i); // We want to alter i in doBar().
...
i++;
}
void doBar(i) {
i++;
}
}
In this case you could just make i a class member instead.
No, wrappers are the only way.
They are passed by reference. It just doesn't matter because the "primitive" types don't have methods to change their internal value.
Correct me if I'm wrong, but maybe you are misunderstanding what "passing by reference" means? I'm assuming you want to do something like param1 = 10 and want this value to still be 10 when you return from your method. But references aren't pointers. When you assign the parameter a new value (with = operator), this change won't be reflected in the calling method. This is still true with non-primitive types (classes).
Example:
class Test {
int val;
Test(this.val);
}
void main() {
Test t = new Test(1);
fn1(t);
print(t.val); // 2
fn2(t);
print(t.val); // still 2, because "t" has been assigned a new instance in fn2()
}
void fn1(Test t) {
print(t.val); // 1
t.val = 2;
}
void fn2(Test t) {
t = new Test(10);
print(t.val); // 10
}
EDIT
I tried to make my answer more clear, based on the comments, but somehow I can't seem to phrase it right without causing more confusion. Basically, when someone coming from Java says "parameters are passed by reference", they mean what a C/C++ developer would mean by saying "parameters are passed as pointers".
As dart is compiled into JavaScript, I tried something that works for JS, and guess what!? It worked for dart!
Basically, what you can do is put your value inside an object, and then any changes made on that field value inside that function will change the value outside that function as well.
Code (You can run this on dartpad.dev)
main() {
var a = {"b": false};
print("Before passing: " + a["b"].toString());
trial(a);
print("After passing: " + a["b"].toString());
}
trial(param) {
param["b"] = true;
}
Output
Before passing: false
After passing: true
One of the way to pass the variables by reference by using the values in List. As arrays or lists are Pass by reference by default.
void main() {
List<String> name=['ali' ,'fana'];
updatename(name);
print(name);
}
updatename(List<String> name){
name[0]='gufran';
}
Try this one, This one of the simplest way to pass by reference.
You can use ValueNotifier
And, you can pass it as ValueListenable to classes or methods that needs to know up-to-date value, but should not edit it:
class Owner {
final theValue = ValueNotifier(true);
final user = User(theValue);
...
}
class User {
final ValueListeneble<bool> theValue;
User(this.theValue);
...
}
It provides more functionality than actually needed, but solves the problem.
If ValueNotifier + ValueListenable do not work for you (you want to make sure the client does not listen to every change of the value, or your package is pure Dart package and thus cannot reference Flutter libraries), use a function:
class Owner {
int _value = 0;
int getValue() => _value;
void increase() => _value++;
}
void main() {
final owner = Owner();
int Function() obtainer = owner.getValue;
print(obtainer());
owner.increase();
print(obtainer());
}
Output will be:
0
1
This approach has memory usage related downside: the obtainer will hold the reference to the owner, and this, even if owner is already not referenced, but obtainer is still reachable, owner will be also reachable
and thus will not be garbage collected.
If you do not want the downside, pass the smaller container than the entire owner:
import 'package:flutter/foundation.dart';
class ListenableAsObtainer<T> implements ValueObtainer<T> {
ListenableAsObtainer(this._listenable);
final ValueListenable<T> _listenable;
#override
T get value => _listenable.value;
}
class FunctionAsObtainer<T> implements ValueObtainer<T> {
FunctionAsObtainer(this._function);
final T Function() _function;
#override
T get value => _function();
}
class ValueAsObtainer<T> implements ValueObtainer<T> {
ValueAsObtainer(this.value);
#override
T value;
}
/// Use this interface when the client needs
/// access to the current value, but does not need the value to be listenable,
/// i.e. [ValueListenable] would be too strong requirement.
abstract class ValueObtainer<T> {
T get value;
}
The usage of FunctionAsObtainer will still result in holding the owner from garbage collection, but two other options will not.
Just to make it clear:
void main() {
var list1 = [0,1,2];
var modifiedList1 = addMutable(list1, 3);
var list2 = [0,1,2];
var modifiedList2 = addImmutable(list2, 3);
print(list1);
print(modifiedList1);
print(list2);
print(modifiedList2);
}
List<int> addMutable(List<int> list, int element){
return list..add(element);
}
List<int> addImmutable(List<int> list, int element){
return [...list, element];
}
Output:
[0, 1, 2, 3]
[0, 1, 2, 3]
[0, 1, 2]
[0, 1, 2, 3]
All variables are passed by value. If a variable contains a primitive (int, bool, etc.), that's it. You got its value. You can do with it whatever you want, it won't affect the source value. If a variable contains an object, what it really contains is a reference to that object.
The reference itself is also passed by value, but the object it references is not passed at all. It just stayed where it was. This means that you can actually make changes to this very object.
Therefore, if you pass a List and if you .add() something to it, you have internally changed it, like it is passed by reference. But if you use the spread operator [...list], you are creating a fresh new copy of it. In most cases that is what you really want to do.
Sounds complicated. Isn't really. Dart is cool.

Resources