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

Issue

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.

Answered By – h8moss

Answer Checked By – Jay B. (FlutterFixes Admin)

Leave a Reply

Your email address will not be published.