most elegant way to initialize members with default values

dart

Solution

Chris Buckett's answer is great for constants. Apparently there is a ternary operator that does work in member initializer. So if initialization of a field is expensive (say requiring a function call and/or creation of objects), this approach seems to work:

- Don't bother initializing the member in the class - prefer the constructor(s). Otherwise, may be wasted effort.

- Skip the nice this.member parameter syntax. Rather use member name and qualify member with this. in the assignment.

- Make use of the ?parm with ternary operator in member initializer. Here is an example in which creating the default values for the member is assumed expensive.

class Formats {
  static Map<String, dynamic> defaultFormats() {
    print("Expensive call - avoid if possible");
    return {"th": 'default th', "td": 'default td'};
  }

  Map<String, dynamic> leftTbl;
  Map<String, dynamic> rightTbl;

  Formats(
      {Map<String, dynamic>? leftTbl,
      Map<String, dynamic>? rightTbl})
      : leftTbl = leftTbl ?? defaultFormats(),
        rightTbl = rightTbl ?? defaultFormats();

  @override
  String toString() {
    return """
l => $leftTbl,
r => $rightTbl
""";
  }
}

Sample use:

print(new Formats());
print(new Formats(leftTbl: {"th":'solid #089', "td":'solid #089' }));
print(new Formats(leftTbl: {"th":'solid #189', "td":'solid #189'},
      rightTbl: {"th":'solid #189', "td":'solid #189'}));

Output:

Expensive call - avoid if possible
Expensive call - avoid if possible
l => {th: default th, td: default td},
r => {th: default th, td: default td}

Expensive call - avoid if possible
l => {th: solid #089, td: solid #089},
r => {th: default th, td: default td}

l => {th: solid #189, td: solid #189},
r => {th: solid #189, td: solid #189}

Problem

Is there any way to make use of the initializer list to optionally initialize optional parameters in a constructor? The following example resorts to if(?x) type logic in the body since it is not clear how to set _x in the initializer list only if it is passed in. ``` class Point { double _x = 0.0; double get x => _x; double _y = 0.0; double get y => _y; Point( { double x, double y }) { if(?x) { _x = x; } if(?y) { _y = y; } } } ``` An alternative is to have constructor: ``` Point( { double x: 0.0, double y: 0.0 }) : _x = x, _y = y { } ``` But then you are repeating yourself (0.0 more than one place) and it looks like _x and _y get initialized twice, once for the member and then again by the initializer list. Also, a benefit of member initializer is it can be a function call, whereas default values for default parameters seem to require constants. I hope/realize the performance impact is small. Just want a nice canonical approach, likely to be used in code generation.

Original source