Is Dart pass by reference? [duplicate] - flutter

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!

Related

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

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

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.

Can an object be assigned to a list without instancing that object?

This is an optimisation question.
I have a class with ~500 named constructors that i need to access through a list - the different constructors have to be picked at random based on specific criteria at runtime.
The constructors have the form:
stuff.s0 (){
<data>
<generating code>
}
The list is initialised with:
var stuffList = [stuff.s0(), stuff.s1(), ...., stuff.s500()];*
Is this creating 500 instances of 'stuff', or is an instance of 'stuff' only created when I use currentStuff = stuffList[42]? If it's the former, is there a better way to do this since only a small fraction of the 500 will be used during any one use of the application?
The data elements are declared as static const so they can be accessed without creating an instance, something similar would be good.
Also, is Dart good at garbage collection? So currentStuff = stuffList[14] would 'replace' stuff.s42 with stuff.s14 in memory, or does that instance of stuff.s42 need flagging as finished with somehow?
Thanks
The objects are created immediately.
All Dart objects are reference values, so assigning currentValue = something; will only change the variable to reference a different object.
What I would do is to have a list of constructor invocations:
var stuffs = [
() => stuff.s0(),
() => stuff.s1(),
// ...
() => stuff.s500(),
];
and then call the function when I access the list:
var currentValue = stuffs[5]();
This would not create the objects until you need them, and it would not keep them alive after you stop referencing them. On the other hand, if you need stuffs[5]() twice, it will build a new object each time.

How to assign method output to variable by reference MQL4

I'm guessing this question is going to apply to many similar languages other than MQL4 such as c++ (which I also forget how to use) which require you manually specify when you are passing by reference.
Method reference:
int[] previous = GetPrevious(i, ZigZagBuffer);
Method definition:
int GetPrevious[](int current, const double& buffer[])
{
int count = 0;
int result[];
// calculate count
ArrayResize(result,count);
// fill array
return result;
}
The resulting compile error is:
"Invalid Array Access"
From what I understand, this is because array's can only be passed by reference, but you have to explicitly state that you are passing it by reference. But the more I look up the syntax for passing by reference, the more I find articles about passing parameter by reference. (which I already know how to do as you can see in the code example.)
What is the syntax to assign the output of a method to a variable?
In case it matters, I only need to read the array multiple times; I'm not needing to alter or re-assign it after it is declared.
You cannot return array. You have to create it and pass into the function, fill inside the function and that's it.
OnTick(){
double array[]; //declaration of the array
fillArray(array,10); //passing array by ref, updating it there
Print(array[0]=0 && array[9]=9);//returns true
}
void fillArray(double &array[],int size){
ArrayResize(array,size);
for(int i=0;i<size;i++){array[i]=i;}
}

When does Chapel pass by reference and when by constant?

I am looking for examples of Chapel passing by reference. This example works but it seems like bad form since I am "returning" the input. Does this waste memory? Is there an explicit way to operate on a class?
class PowerPuffGirl {
var secretIngredients: [1..0] string;
}
var bubbles = new PowerPuffGirl();
bubbles.secretIngredients.push_back("sugar");
bubbles.secretIngredients.push_back("spice");
bubbles.secretIngredients.push_back("everything nice");
writeln(bubbles.secretIngredients);
proc kickAss(b: PowerPuffGirl) {
b.secretIngredients.push_back("Chemical X");
return b;
}
bubbles = kickAss(bubbles);
writeln(bubbles.secretIngredients);
And it produces the output
sugar spice everything nice
sugar spice everything nice Chemical X
What is the most efficient way to use a function to modify Bubbles?
Whether Chapel passes an argument by reference or not can be controlled by the argument intent. For example, integers normally pass by value but we can pass one by reference:
proc increment(ref x:int) { // 'ref' here is an argument intent
x += 1;
}
var x:int = 5;
increment(x);
writeln(x); // outputs 6
The way that a type passes when you don't specify an argument is known as the default intent. Chapel passes records, domains, and arrays by reference by default; but of these only arrays are modifiable inside the function. ( Records and domains pass by const ref - meaning they are passed by reference but that the function they are passed to cannot modify them. Arrays pass by ref or const ref depending upon what the function does with them - see array default intent ).
Now, to your question specifically, class instances pass by "value" by default, but Chapel considers the "value" of a class instance to be a pointer. That means that instead of allowing a field (say) to be mutated, passing a class instance by ref just means that it could be replaced with a different class instance. There isn't currently a way to say that a class instance's fields should not be modifiable in the function (other than making them to be explicitly immutable data types).
Given all of that, I don't see any inefficiencies with the code sample you provided in the question. In particular, here:
proc kickAss(b: PowerPuffGirl) {
b.secretIngredients.push_back("Chemical X");
return b;
}
the argument accepting b will receive a copy of the pointer to the instance and the return b will return a copy of that pointer. The contents of the instance (in particular the secretIngredients array) will remain stored where it was and won't be copied in the process.
One more thing:
This example works but it seems like bad form since I am "returning" the input.
As I said, this isn't really a problem for class instances or integers. What about an array?
proc identity(A) {
return A;
}
var A:[1..100] int;
writeln(identity(A));
In this example, the return A in identity() actually does cause a copy of the array to be made. That copy wasn't created when passing the array in to identity(), since the array was passed by with a const ref intent. But, since the function returns something "by value" that was a reference, it's necessary to copy it as part of returning. See also arrays return by value by default in the language evolution document.
In any case, if one wants to return an array by reference, it's possible to do so with the ref or const ref return intent, e.g.:
proc refIdentity(ref arg) ref {
return arg;
}
var B:[1..10] int;
writeln(refIdentity(B));
Now there is no copy of the array and everything is just referring to the same B.
Note though that it's currently possible to write programs that return a reference to a variable that no longer exists. The compiler includes some checking in that area but it's not complete. Hopefully improvements in that area are coming soon.