0

Consider the following class. It is what we may call a "two-dimensional enum". We could have used an enum with four states, but since the four states have a clear meaning, we choose the more direct approach of storing two Boolean flags.

class FlowerType {
  bool has_scent = false;
  bool has_thorns = false;

  FlowerType({this.has_scent = false, this.has_thorns = false});
}

The class has one constructor with two named optional parameters.

This constructor also acts as a default constructor, and since the two bools are non-nullable, they need to be specified (again) in the constructor.

Can default values be specified once?

Declaring two final static variables for this purpose is one option (though a pretty lousy one). Here I'm wondering whether I'm missing some basic fact about constructors.

Sam
  • 563
  • 5
  • 15

2 Answers2

2

I'd remove the default values from the fields:

class FlowerType {
  final bool hasScent;
  final bool hasThorns;
  FlowerType({this.hasScent = false, this.hasThorns = false});
}

The values written as field initializers will always be overridden by the constructor anyway, and they prevent the fields from being final.

You could consider alternatives like multiple constructors:

  FlowerType.plain() : this(hasScent: false, hasThorns: false);
  FlowerType.thorny() : this(hasScent: false, hasThorns: true); 
  FlowerType.scented() : this(hasScent: true, hasThorns: false);
  FlowerType.thornyAndScented() : this(hasScent: true, hasThorns: true);

(I assume there will be more fields and constructor parameters, otherwise you only ever need four instance of the class).

lrn
  • 64,680
  • 7
  • 105
  • 121
  • Nice. Another (related? distinct?) question is this: is the presence of `required` to negate the effect of a parameter being optional a sign that Dart already has bug patches built into the fabric of the language? – Sam Oct 11 '21 at 15:02
  • @Sam If you mean why `required` isn't implicit by virtue of omitting a default argument to a named parameter, then it's necessary to allow `f({T? x})` and `f(required T? x})` to both be legal and distinct. They maybe could have made optional nullable parameters require an explicit `= null`, but I would guess that it was to be more consistent with pre-NNBD code, especially since there already was a similar `@required` annotation that was in common use. – jamesdlin Oct 11 '21 at 16:40
0

An alternative (albeit a less efficient one) is to make the members non-nullable but to use nullable parameters:

class FlowerType {
  bool has_scent = false;
  bool has_thorns = false;

  FlowerType({bool? has_scent, bool? has_thorns}) {
    this.has_scent = has_scent ?? this.has_scent;
    this.has_thorns = has_thorns ?? this.has_thorns;
  }
}

Drawbacks:

  • Less efficient (the member would be initialized, the argument would be tested, and the member would be reassigned).
  • Members could not be final.
  • Members would receive their intended value later in the construction process. It wouldn't matter in this example, though.
jamesdlin
  • 81,374
  • 13
  • 159
  • 204