Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

most elegant way to initialize members with default values

Tags:

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.

like image 710
user1338952 Avatar asked Mar 13 '13 19:03

user1338952


2 Answers

You can initialize variables in a constructor using this prefix, eg:

class PointA {    double _x;   double get x => _x;   double _y;   double get y => _y;    PointA({double this._x=0.0, double this._y=0.0}); }  class PointB {    final double x;   final double y;    Point({double this.x=0.0, double this.y=0.0}); }  void main() {   new PointA(_y:2.0);    new PointA(_x:3.0);    new PointA(_x:2.0, _y:3.0);     new PointB(y:2.0);    new PointB(x:3.0);    new PointB(x:2.0, y:3.0);  } 
like image 53
Chris Buckett Avatar answered Oct 26 '22 14:10

Chris Buckett


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} 
like image 24
user1338952 Avatar answered Oct 26 '22 13:10

user1338952