Flutter can you "send" objects as a message with compute()? - flutter

So I basically have a simple class with a update() method. But because that update() method makes some math, I wanted to use compute() to make it run in another Isolate. The plan was to run the update() method in the Isolate and return the updated object like this:
compute(updateAsset, asset).then((value) => asset = value);
Asset updateAsset(Asset asset) {
asset.update();
return asset;
}
But then I get this error:
ArgumentError (Invalid argument(s): Illegal argument in isolate message : (object extends NativeWrapper - Library:'dart:ui' Class: Path))
Is there any possible way to send an object to an Isolate or do I have to send every single Value of that Asset as an Integer, create a new Object and return that?

According to the docs:
The content of message can be: primitive values (null, num, bool, double, String), instances of SendPort, and lists and maps whose elements are any of these. List and maps are also allowed to be cyclic.
So I see a 2 options that you can use.
You can send every value as an integer or other primitive in a Map or List if it's possible for your object to be deconstructed like that.
If that method is too difficult for any reason, you can instead convert you object to a primitive type, the easiest being String with JSON encoding. You can encode your object with the jsonEncode function and send the String that it returns over to your isolate where you would then decode it back to your object if necessary.

Related

Can I pass a type of enum as an argument in Dart?

I want to have a method that takes a parameter of type enum as a parameter and then operates on it to get all possible values of the enum type, and do some work with each of those values.
I'd be hoping for something like:
Widget foo (EnumType enumType) {
for(var value in enumType.values) {
print(value.name);
}
}
I've looked for solutions but the only ones I can find are addressed by passing a list of the values as a parm, however this doesn't solve my problem as, even with the list of objects, I can't know that they are enum values so if I try do the .name operation on them, dart throws an error Error: The getter 'name' isn't defined for the class 'Object'.
Maybe my only problem is that I don't know how to specify a variable as an EnumType but I haven't been able to find a correct type for this.
EnumType.values is the equivalent of an automatically generated static method on EnumType and as such is not part of any object's interface. You therefore will not be able to directly call .values dynamically.
I've looked for solutions but the only ones I can find are addressed by passing a list of the values as a [parameter], however this doesn't solve my problem as, even with the list of objects, I can't know that they are enum values so if I try do the .name operation on them, dart throws an error
You can use a generic function that restricts its type parameter to be an Enum:
enum Direction {
north,
east,
south,
west,
}
List<String> getNames<T extends Enum>(List<T> enumValues) =>
[for (var e in enumValues) e.name];
void main() {
print(getNames(Direction.values)); // Prints: [north, east, south, west]
}
The problem with enums is that they can't be passed as a parameter, what you can do instead is that pass all the values and then extract the name from the toString method.
void printEnumValues<T>(List<T> values){
for(var value in values){
final name = value.toString().split('.')[1];
print(name);
}
}
Also I would recommend you look into freezed union classes as that might allow you an alternative approach towards the problem you're trying to solve.

A way to read a String as dart code inside flutter?

I want to build a method to dynamically save attributes on a specific object
given the attribute name and the value to save I call the "save()" function to update the global targetObj
var targetObj = targetClass();
save(String attribute, String value){
targetObj.attribute = value;
print(targetObj.attribute);
}
But I'm getting the following error:
Class 'targetClass' has no instance setter 'attribute='.
Receiver: Instance of 'targetClass'
Tried calling: attribute="Foo"
The only thing that I can think of is that "attribute" due to being type String results in an error.
That lead me to think if there is a way to read a String as code, something like eval for php.
As #Randal mentioned, you cannot create class..method at runtime. Still, you can try something like this.
A certain class
class Foo {
dynamic bar1;
dynamic bar2;
// ...
}
Your save method
save(Foo fooObject, String attribute, dynamic value) {
if ("bar1" == attribute) fooObject.bar1 = value;
else if ("bar2" == attribute) fooObject.bar2 == value;
// ...
}
Dart (and thus flutter) does not have a way to compile and execute code at runtime (other than dart:mirrors, which is deprecated). You can build additional code that derives from other code using the various builder mechanisms, although it can be rather complicated to implement (and use!).

Updating instance of class after being pushed to a List

Consider this dart code:
T t = T() // id field defaults to null
List<T> list = List()..add(t);
t.id = '123';
print('${list.first.id}') // What's output?
My question is about whether passed items to List are copied over to List or it's a reference.
I've encountered this ambiguity because I'm using flutter_redux where an action contains an instance of class T. on reducer, I add this T instance to my state. later on, in the middleware, I update this t's id. But surprisingly id field on the state(in this case List) changes too! So my only guess is that objects are passed by reference. Is this assumption correct?
Everything in Dart is an Object, so anything you are passing is passed by reference.
From the Dart Language Tour:
Everything you can place in a variable is an object, and every object
is an instance of a class. Even numbers, functions, and null are
objects. All objects inherit from the Object class.
mutable/immutable objects
There is a difference however between mutable and immutable objects. Some objects are immutable, and therefore cannot be modified, while mutable objects can be modified.
An example of immutable objects is String objects.
An example of mutable object is List just like you observed in your example.
constness
Dart has another interesting type of object, and if you are familiar with C++ or C, you would have encountered these. These are compile-time constants (const), and carry with them an attribute of immutability. Any object can be declared as const at the point of creation, provided the constructor being called has been declared as const.
Watch out with const objects if you are passing them to functions that expect mutable objects because attempting to mutate the constant, will result in a runtime error.
void modl(final List<int> l) {
l.add(90);
print(l);
}
void main() {
List<int> l = const [1,2,3,4];
modl(l); // Uncaught Error
print (l);
}
Running the above program will result in an Uncaught Error because l is a compile-time constant.
See Detecting when a const object is passed to a function that mutates it, in Dart

Is Dart pass by reference? [duplicate]

This question already has answers here:
What is the true meaning of pass-by-reference in modern languages like Dart?
(3 answers)
Closed 1 year ago.
In this post: Flutter video_player dispose
I asked how to dispose something so I can re-use it again. The answer provided works correctly but it left me with this question:
why does this code work as intended? eg it disposes the old instance from videoController using oldController
final oldController = videoController;
WidgetsBinding.instance.addPostFrameCallback((_) async {
await oldController.dispose();
_initController(link); //contains reassignment of videoController = VideoController.network(...)
});
in C or similar languages, a use of pointer is needed (or should I say my preferred way). To pass the reference, assign a new value to it and then take care of the old one.
Sorry that my answer left you with a confusion. Yes, in Dart you work with references to objects, just like in Java. I'll give a short example that should make it clear for you why this code works as intended:
void main() {
final t = Test(Test());
t.removeField();
}
class Test {
Test t;
Future<void> removeField() async {
print('current field: $t');
Future.delayed(Duration(seconds: 2)).then((_) => print('delayed value: $t'));
t = null;
}
Test([this.t]);
}
prints:
current field: Instance of 'Test'
delayed value: null
In this case, field's value is set to null first and then 2 seconds later callback executes. It accesses object's field, but it's already null. But if we make it like this:
final old = t;
Future.delayed(Duration(seconds: 2)).then((_) => print('delayed value: $old'));
it prints:
current field: Instance of 'Test'
delayed value: Instance of 'Test'
We stored previous value of the field and passed it to the callback, so it won't access nulled field.
Dart does not support passing by reference. Dart is only passed by value, just like Java. Java also does not support reference passing.
Is Java “pass-by-reference” or “pass-by-value”?
https://stackoverflow.com/a/40523/1737201
Below is a little proof.
void main() {
// The variable "myVar" is a "lvalue" (storage of value)
// Now we assign the value to "myVar" via "rvalue" "Object()"
final myVar = Object();
// Remember the old value
final oldObject = myVar;
// Now we will try to pass by reference.
// We assume that we will pass the reference of storage ("lvalue")
// ("myVar" im our case) because we cannot reference the value (pure data)
// because the value does not contain storage location information.
tryChangeMyVarByRef(myVar);
// Check the result passing by reference
// If storage of value was passed by its reference then changing
// the value in this storage should have effect.
assert(!identical(myVar, oldObject));
// Epic fail because Dart does not support pass by refernce.
print('WOW, it works!');
}
void tryChangeMyVarByRef(Object referencedStorgeOfValue) {
// Try change the value stored in referenced storage of value
referencedStorgeOfValue = Object();
}
EDIT:
The value (or more correct rvalue which means a data whitout any storage) cannot have an address because the value is just a data. In programming impossible to reference the data (because there are no any way to do that) but possible to reference the storage of data (eg. address of variable) because the storage are always has some location rather than data (data only can be stored at some location but not referenced because data can be replaced at any time at this location and thus this cannot be called as reference to data because this can be incorrect after data reassigment would be perfomed but should be only called as reference of some storage of some data).
In the programming the term "pass by reference" means: pass the reference (address of the location) of the value storage (that is, the address of some varibale with any data but not the address of this data).
This allows to replace (but not just change) stored data at some location becuase the storage was referenced (address of laocation was known).
Which means only one thing: you pass reference of the variable where some value are stored.
And this does not means the reference of some value as many newbie wrongly think (who never used C or C++ language).
Another important thing is that the in Dart the object (or instances) itself are references because they are boxed (the values was stored in the heap).
This creates illusion that you pass by reference but at the same time you pass by value the reference (where reference as value is passed by value). Pass by value the reference is not the same as pass by reference the reference.
Free advice to newbie: Learn the C or C++ programming languages to find out the difference between the following things:
Pass by value the reference
Pass by reference the reference
In both cases the value itself is a reference but in first case you pass the value (reference) by value but in second case you pass the value (reference) by reference.
Enjoy!

Is this C# casting useless?

I have two methods like so:
Foo[] GetFoos(Type t) { //do some stuff and return an array of things of type T }
T[] GetFoos<T>()
where T : Foo
{
return GetFoos(typeof(T)) as T[];
}
However, this always seems to return null. Am I doing things wrong or is this just a shortfall of C#?
Nb:
I know I could solve this problem with:
GetFoos(typeof(T)).Cast<T>().ToArray();
However, I would prefer to do this wothout any allocations (working in an environment very sensitive to garbage collections).
Nb++:
Bonus points if you suggest an alternative non allocating solution
Edit:
This raises an interesting question. The MSDN docs here: http://msdn.microsoft.com/en-us/library/aa664572%28v=vs.71%29.aspx say that the cast will succeed if there is an implicit or explicit cast. In this case there is an explicit cast, and so the cast should succeed. Are the MSDN docs wrong?
No, C# casting isn't useless - you simply can't cast a Foo[] to a T[] where T is a more derived type, as the Foo[] could contain other elements different to T. Why don't you adjust your GetFoos method to GetFoos<T>()? A method only taking a Type object can easily be converted into a generic method, where you could create the array directly via new T[].
If this is not possible: Do you need the abilities an array offers (ie. indexing and things like Count)? If not, you can work with an IEnumerable<T> without having much of a problem. If not: you won't get around going the Cast<T>.ToArray() way.
Edit:
There is no possible cast from Foo[] to T[], the description in your link is the other way round - you could cast a T[] to a Foo[] as all T are Foo, but not all Foo are T.
If you can arrange for GetFoos to create the return array using new T[], then you win. If you used new Foo[], then the array's type is fixed at that, regardless of the types of the objects it actually holds.
I haven't tried this, but it should work:
T[] array = Array.ConvertAll<Foo, T>(input,
delegate(Foo obj)
{
return (T)obj;
});
You can find more at http://msdn.microsoft.com/en-us/library/exc45z53(v=VS.85).aspx
I think this converts in-place, so it won't be doing any re-allocations.
From what I understand from your situation, using System.Array in place of a more specific array can help you. Remember, Array is the base class for all strongly typed arrays so an Array reference can essentially store any array. You should make your (generic?) dictionary map Type -> Array so you may store any strongly typed array also while not having to worry about needing to convert one array to another, now it's just type casting.
i.e.,
Dictionary<Type, Array> myDict = ...;
Array GetFoos(Type t)
{
// do checks, blah blah blah
return myDict[t];
}
// and a generic helper
T[] GetFoos<T>() where T: Foo
{
return (T[])GetFoos(typeof(T));
}
// then accesses all need casts to the specific type
Foo[] f = (Foo[])GetFoos(typeof(Foo));
DerivedFoo[] df = (DerivedFoo[])GetFoos(typeof(DerivedFoo));
// or with the generic helper
AnotherDerivedFoo[] adf = GetFoos<AnotherDerivedFoo>();
// etc...
p.s., The MSDN link that you provide shows how arrays are covariant. That is, you may store an array of a more derived type in a reference to an array of a base type. What you're trying to achieve here is contravariance (i.e., using an array of a base type in place of an array of a more derived type) which is the other way around and what arrays can't do without doing a conversion.