How can you call a void function in Flutter without passing a parameter?

4,864

You seem to be misunderstanding the assignment of a variable to a function for a function call.

Let me try to show it with example code.

void _updateFromConversion(dynamic unitName) {
    print("Unit name: $unitName");
}

class SomeClass {
    void Function(dynamic arg) myFunction;
}

void main() {
    final c = SomeClass()..myFunction = _updateFromConversion;
    print("Created c. Calling its function");
    c.myFunction("foo");
    print("Done");
}

When you run this code, you will see this printed:

Created c. Calling its function
Unit name: foo
Done

This shows that the _updateFromConversion function is not called when you create the SomeClass instance in SomeClass()..myFunction = _updateFromConversion;. This is only an assignment (it assigns to the field myFunction the value _updateFromConversion... yes, in Dart a function itself can be a value)!

You should know that because there's no () after the function name, and function invocation in Dart always must contain the list of arguments between () even if it's empty.

So, here's where the function is invoked:

c.myFunction("foo");

See? There's a list of arguments containing a single value, "foo". That's why the function then prints Unit name: foo, because the argument unitName takes the value "foo".

TL;DR

This is a function invocation:

c.myFunction("foo");

This is NOT:

c.myFunction;
Share:
4,864
Yashvin Vedanaparti
Author by

Yashvin Vedanaparti

Updated on December 18, 2022

Comments

  • Yashvin Vedanaparti
    Yashvin Vedanaparti over 1 year

    I'm new to Flutter and am working through the intro course on Udacity. In one of the tasks, I was trying to follow the code and I can't make much sense of it. Here's the code from the solution of the project (I've cut and paste the parts that matter, and also legal disclaimer I do not own any of this code, it's from the sample Flutter Udacity project):

    Widget build(BuildContext context) {
        final input = Padding(
          padding: _padding,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
    
              TextField(...),
    
              _createDropdown(_fromValue.name, _updateFromConversion),
            ],
          ),
        );
    }
    
    void _updateFromConversion(dynamic unitName) {
        setState(() {
          _fromValue = _getUnit(unitName);
        });
        if (_inputValue != null) {
          _updateConversion();
        }
      }
    
    Widget _createDropdown(String currentValue, ValueChanged<dynamic> onChanged) {
        return Container(
          margin: EdgeInsets.only(top: 16.0),
          decoration: BoxDecoration(...),
    
          padding: EdgeInsets.symmetric(vertical: 8.0),
          child: Theme(...),
    
            child: DropdownButtonHideUnderline(
              child: ButtonTheme(
                alignedDropdown: true,
                child: DropdownButton(
                  value: currentValue,
                  items: _unitMenuItems,
                  onChanged: onChanged,
                  style: Theme.of(context).textTheme.title,
                ),
              ),
            ),
          ),
        );
    }
    

    Here's where I'm stuck. _updateFromConversion requires an input parameter unitName. But when they call it, in _createDropdown, they don't pass any. So how does _updateFromConversion know what unitName is? Also, is _updateFromConversion executed before _createDropdown, or is it executed when the "onChanged" property of DropdownButton is set?

    Second question: they're passing that function with return type void into _createDropdown, which is expecting ValueChanged. Shouldn't this throw an error?

    If someone can explain the flow of this code and what I am missing I would greatly appreciate it. Thank you!

  • Yashvin Vedanaparti
    Yashvin Vedanaparti about 4 years
    That makes a lot of sense. So then a couple follow up questions: 1) In the code I posted, they are assigning the function to a ValueChanged<dynamic> type. So can you assign a function to any type, not just a function type? 2) When does _updateFromConversion get called? When the onChanged property is assigned? Because even there they are not passing an arg.
  • Renato
    Renato about 4 years
    ValueChanged is a function as well. But it's a typedef (probably a lot to get your head around in this "simple" example!), which is like an alias, so you can name a function type something easier to remember: api.flutter.dev/flutter/foundation/ValueChanged.html
  • Renato
    Renato about 4 years
    2) the code you posted does not show _updateFromConversion being called... but given that you give it to the DropdownButton widget's field called onChange, it must be called by the Widget whenever the Widget changes (via user action, or programmatically).