0

Learning Dart and using dart_code_metrics to ensure that I write code that meets expectations. One of the rules that is active is avoid-non-null-assertion.

Note, the code below was created to recreate the problem encountered in a larger code base where the value of unitString is taken from a JSON file. As such the program cannot control what is specified in the JSON file.

From pubspec.yaml

environment:
  sdk: '>=2.15.0 <3.0.0'

// ignore_for_file: avoid_print
import 'package:qty/qty.dart';

void main() {
  const String unitString = 'in';
  // unit.Width returns null if unitString is not a unit of Length.
  if (Length().unitWith(symbol: unitString) == null) {
    print('units $unitString not supported.');
  } else {
    // The following line triggers avoid-non-null-assertion with the use of !. 
    final Unit<Length> units = Length().unitWith(symbol: unitString)!; 
    final qty = Quantity(amount: 0.0, unit: units);
    print('Qty = $qty');
  }
}

If I don't use ! then I get the following type error:

A value of type 'Unit<Length>?' can't be assigned to a variable of type 'Unit<Length>'.
Try changing the type of the variable, or casting the right-hand type to 'Unit<Length>'.

Casting the right-hand side to

Unit<Length> 

fixes the above error but cause a new error when instantiating Quantity() since the constructor expects

Unit<Length> 

and not

Unit<Length>?

I assume there is an solution but I'm new to Dart and cannot formulate the correct search query to find the answer.

How can I modify the sample code to make Dart and dart_code_metrics happy?

Christopher Moore
  • 15,626
  • 10
  • 42
  • 52
  • What do you want to do when `units` is `null`? Figure that out, implement it, then you're done. Default values can easily be assigned with the [`??`](https://stackoverflow.com/questions/54031804/what-are-the-double-question-marks-in-dart) operator. Null safety gives you safety from using null variables when you don't expect them to be null, but it also means you need to be explicit about what you want to do when something is null. Otherwise, how would Dart know what to do when it's null? – Christopher Moore Feb 08 '23 at 02:34
  • Christopher, Thanks for the response. In the code where the example is from I throw an exception when Length().unitWith() return null. As such I'm going to cast Unit? to Unit. E.g. final qty = Quantity(amount: 0.0, unit: units as Unit) – YetAnother BugHunter Feb 08 '23 at 14:23
  • Understood, I didn't see that earlier. See my answer as to what you can/should do. – Christopher Moore Feb 08 '23 at 15:58

1 Answers1

0

Your idea of checking for null before using a value is good, it's just not implemented correctly. Dart does automatically promote nullable types to non-null ones when you check for null with an if, but in this case you need to use a temporary variable.

void main() {
  const String unitString = 'in';

  //Use a temp variable, you could specify the type instead of using just using final
  final temp = Length().unitWith(symbol: unitString);
  if (temp == null) {
    print('units $unitString not supported.');
  } else {
    final Unit<Length> units = temp; 
    final qty = Quantity(amount: 0.0, unit: units);
    print('Qty = $qty');
  }
}

The basic reason for that when you call your unitWith function and see that it's not null the first time, there's no guarantee that the when you call it again that it will still return a non-null value. I think there's another SO question that details this better, but I can't seem to find.

Christopher Moore
  • 15,626
  • 10
  • 42
  • 52