I've noticed that when I have a widget/class that takes Functions as arguments, when it comes time to call those functions, it can be done one of three ways (that I know of):
(Consider a Function, myFunction)
myFunction
myFunction()
myFunction.call()
But the weird thing is, I've noticed that when using option 1), it will (ONLY SOMETIMES) not work and require the use of option 2 or 3 in order to work.
Why is that?
Specific example (I've verified the inconsistent calling behaviour with print debugging in the parent):
class SoundPickerTile extends StatelessWidget {
final Sound sound;
final Function() checkboxCallback;
final Function() soundPlayCallback;
SoundPickerTile(
{required this.sound, required this.checkboxCallback, required this.soundPlayCallback});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: checkboxCallback, // <--------------- Function executes in parent
child: Container(
color: sound.isIncluded ? Colors.lightGreen.withAlpha(100) : Colors.white,
child: Padding(
padding: EdgeInsets.fromLTRB(20, 10, 0, 10),
child: Row(
children: [
Expanded(
child: Text(
sound.shortTitle,
),
),
Expanded(
child: IconButton(
icon: Icon(Icons.play_circle_outline),
onPressed: () {
print("this line of code was reached"); // this works
soundPlayCallback; // <--------------- Function *does not* execute in parent
},
),
),
],
),
),
),
);
}
}
CodePudding user response:
They are all the same object, but with two different behaviours.
myFunction is your function but shaped like an object. So you can pas this around as an argument for onTap (which takes a function like that as argument). That's also why it's run in the parent, that's how it's supposed to work. It gets tossed around as an object and the parent calls () on it.
The reason it's not being executed below is because there you are simple putting the function down as an object. Much like you earlier passed it as an object, right now you're just saying hey here's the function, but I'm not gonna do anything with it.
myFunction; -> no ()
So in order for it to work you need to use number 2. or 3.
myFunction() -> This will call your object (your function) and run it's code, contrary to the previous mentioned example where you just lay the object down. The () is important!
Now the difference between 2. and 3. is.. almost nothing!
() actually does the .call() in the background, however if you have a myFunction that's possibly null, then you can do something like this:
myFunction?.call();
This will only call the function if it's not null, else it will not do anything.
Hope that's clear, also try to define a return value when specifying callbacks, this will make you understand passing around functions quicker. And have a look at typedefs, they are basically signatures for specific functions (VoidCallback for example). Once you grasp that concept passing around functions will become a breeze! Goodluck.
CodePudding user response:
In the GestureDetector
we use:
onTap: checkboxCallback,
without the ()
, since that would call the function immediately, we don't want to call the function, we just want to pass a reference to the function on what should happen when onTap
is called.
Then with:
onPressed: () {
print("this line of code was reached"); // this works
soundPlayCallback; // <--------------- Function *does not* execute in parent
},
Since were are not using ()
it's not being called it's just a reference to the function.
Instead, what you can do is:
onPressed: soundPlayCallback
;
Or add the ()
Edit.
What is the difference between calling the function without parentheses and with parentheses