8

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.

AnsellC
  • 795
  • 3
  • 9
  • 17

2 Answers2

7

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.

Igor Kharakhordin
  • 9,185
  • 3
  • 40
  • 39
  • In this case, should I assign model instances to null in a Stateless/ful widget? eg: a `person` variable created with `Person()` class inside a stateful widget should be set to null inside the stateful widget's `dispose()?` or does flutter/GC/dart takes care of that? – AnsellC Nov 21 '19 at 03:18
  • 1
    @AnsellC In your previous question I mentioned that you need to set it to null, to make sure the controller is no longer used by widget. Other than that you don't need to set every field to null inside widget state's `dispose()` as they will get garbage-collected along with state's instance. But some things need to get disposed of manually like stream subscriptions, controllers, listeners etc. – Igor Kharakhordin Nov 21 '19 at 03:52
  • Yea I was just over thinking on how things gets freed because GC wasn't freeing up the resources even with manually running GC. – AnsellC Nov 21 '19 at 10:28
3

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!

mezoni
  • 10,684
  • 4
  • 32
  • 54
  • 5
    correct me if I'm wrong but... what is happening in `tryChangeMyVarByRef()` is that a new instance of `Object` is assigned to variable `referencedStorgeOfValue` and that variable is scoped only to its function. meaning you're not even trying to modify passed in object but rather discarding reference to it by assigning a new value to `referencedStorgeOfValue`. – metalinspired Sep 22 '20 at 19:04
  • 3
    Unfortunately a line from this answer was selected by Google in response to the question of "Is Dart pass by reference?" While the answer in its larger context is correct that Dart does not pass a reference to the _variable_, it does pass a reference to the original _object_. Unfortunately, in the context of C++, the implication of "pass by value" is that a copy of the object is made and this is incorrect. – James Foster Jul 29 '21 at 04:18
  • @JamesFoster Pass by reference: Pass by reference (also called pass by address) means to pass the reference of an argument in the calling function to the corresponding formal parameter of the called function so that a copy of the address of the actual parameter is made in memory, i.e. the caller and the callee use the same variable for the parameter. If the callee modifies the parameter variable, the effect is visible to the caller’s variable. – mezoni Jul 29 '21 at 06:09
  • I recommend that beginners take a short course to broaden their horizons and increase their level of knowledge.: `Is Java “pass-by-reference” or “pass-by-value”?` https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value/40523 Dart is no different from Java in this regard, and this is all true for Dart as well. – mezoni Jul 29 '21 at 06:18