Search code examples
flutterdartdart-null-safetynull-safety

How best to convert old Dart code that triggers "parameter can't be 'null' but the implicit default value is 'null'." error?


Take the following non-null safe Dart code:

class RoundedButton extends StatelessWidget {
  RoundedButton({this.title, this.color, @required this.onPressed});

  final Color color;
  final String title;
  final Function onPressed;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.symmetric(vertical: 16.0),
      child: Material(
        elevation: 5.0,
        color: color,
        borderRadius: BorderRadius.circular(30.0),
        child: MaterialButton(
          onPressed: onPressed,
          minWidth: 200.0,
          height: 42.0,
          child: Text(
            title,
            style: TextStyle(
              color: Colors.white,
            ),
          ),
        ),
      ),
    );
  }
}

With regards to the constructor's parameters, Android Studio is saying, "The parameter [parameter] can't have a value of 'null' because of its type, but the implicit default value is 'null'."

I understand the error and have discovered that I can simply modify the code like this:

class RoundedButton extends StatelessWidget {
  RoundedButton({this.title, this.color, required this.onPressed});

  final Color? color;
  final String? title;
  final Function onPressed;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.symmetric(vertical: 16.0),
      child: Material(
        elevation: 5.0,
        color: color,
        borderRadius: BorderRadius.circular(30.0),
        child: MaterialButton(
          onPressed: onPressed.call(),
          minWidth: 200.0,
          height: 42.0,
          child: Text(
            title!,
            style: TextStyle(
              color: Colors.white,
            ),
          ),
        ),
      ),
    );
  }
}

This way, I satisfy the language rules, but using the bang operator to do the "force unwrap" is presumably frowned upon.

So my solution seems hacky... so in this scenario, what is the elegant, proper, or even sexy way to convert this code to null safety, and if there are multiple ways, then what are the pros and cons?

Thanks!


Solution

  • There are several ways to migrate to null safe code, as you said, making all variables nullable is a possible solution, here are two others:

    1. Making the variable have a default value

    from:

    final String title;
    

    to:

    final String title = '';
    

    or

    MyClass {
      MyClass({this.title=''});
      final String title;
    }
    

    When to use

    If you have a variable that should start with some value and change as time goes on or if you have a variable that is unlikely to be unique to each instance.

    GOOD

    int timesOpened = 0;
    

    BAD

    int uniqueValue = 0 // if it should be unique, it shouldn't be default.
    

    2. Forcing a value at the constructor

    from:

    MyClass {
      MyClass({this.title});
      final String title;
    }
    

    to:

    MyClass {
      MyClass({required this.title});
      final String title;
    }
    

    When to use

    When you have a value that must be passed to each instance and that is likely to be different for each instance

    GOOD

    MyClass({required this.onPressed});
    

    BAD

    MyClass({required this.textSize}); // probably should have a default text size value
    

    If I were you, I'd make color have a default value and title and onPressed be required parameters. But You'd know better than me.