8

So after dart made new keyword optional,

we can initialize an object with exact same syntax but different internal implementation.

class Color {
  int r = 0, g = 0, b = 0;

  Color({this.r, this.b, this.g});

  //Named constructors
  Color.red() //Implementation

  Color.cyan() //Implementation

  // Static Initializers
  static Color red() => //Initialze with parameter

  static Color cyan() => //Initialze with parameter
}

We can use them like this regardless of being it a named constructor or static method:

Color red = Color.red();
Color cyan = Color.cyan();

What is the place to use each of them?

erluxman
  • 18,155
  • 20
  • 92
  • 126
  • 1
    They are not the same thing since, as you've said, they have different internal implementations. Named constructors are constructors, while static methods are functions. They serve different purposes. – Rémi Rousselet May 26 '20 at 03:45
  • But the function is just wrapper for constructor right? I can't find the link but I think I have read somewhere that named constructors are also static – erluxman May 26 '20 at 04:22
  • 1
    You perhaps are mixing up `factory` constructors with named constructors. There isn't much [difference between `factory` constructors and `static` methods](https://stackoverflow.com/q/52299304/). – jamesdlin May 26 '20 at 08:06
  • 1
    I made a small list about the differences between factories and static methods. Maybe this will help your case https://dash-overflow.net/articles/factory/ – Rémi Rousselet May 26 '20 at 12:02

5 Answers5

7

In practice there is little difference between a factory constructor and a static method.

For a generic class, it changes where you can (and must) write a type parameter:

class Box<T> {
  T value;
  Box._(this.value);
  factory Box.withValue(this.value) => Box<T>._(value);
  static Box<T> fromValue<T>(T value) => Box<T>._(value);
}
...
  var box1 = Box<int>.withValue(1);
  var box2 = Box.fromValue<int>(2);

So, for generic classes, factory constructors are often what you want. They have the most pleasant syntax.

For non-generic classes, there is very little difference, so it's mainly about signaling intent. And deciding which category the name goes into in the DartDoc.

If the main objective of the function is to create a new object, make it a constructor.

If the main objective is to do some computation and eventually return an object (even if it's a new object), make it a static function. That's why parse methods are generally static functions.

In short, do what feels right for your API.

lrn
  • 64,680
  • 7
  • 105
  • 121
  • It also seems to me that factories and static functions allow you to fix the type parameter (i.e. creating a non-generic way to create an instance), while named constructors do not. – Ber Sep 15 '21 at 07:43
  • That is correct *so far* (or at least it requires you to write more because you can't tear off a constructor like you can a function). If all goes according to plan, you'll be able to tear-off and partially instantiate constructors too in Dart 2.15, which adds the "constructor tear-off" feature – lrn Sep 15 '21 at 08:30
4

Constructors and static functions are different. You usually create a named constructor that returns an instance of an object with some predefined values. For example, you have a class called Person which stores Name and Job. You can create this named constructor Person.doctor(name) which you will return a Person object with Job = 'doctor'

 class Person{
  final name;
  final job;

  Person(this.name, this.job);

  Person.doctor(this.name, {this.job = "doctor"});

 }

Static functions or variable persists on all the instance of a class. Let us say, Person has a static variable called count. You increment the count variable whenever an instance of Person is created. You can call Person.count anywhere later in your code to get the value of count (Number of instances of Person)

class Person{
  final name;
  final job;
  static int count;

  Person(this.name, this.job){
    count++;
  }

  Person.doctor(this.name, {this.job = "doctor"});

}
tonymontana
  • 5,728
  • 4
  • 34
  • 53
2

Another very useful feature of static class methods is that you can make them asynchronous, i.e. wait for full initialisation in case this depends on some asynchronous operation:

Future<double> getCurrentPrice(String ticker) async {
  double price;
  // for example, fetch current price from API
    price = 582.18;
  return price;
}

class Stock {
      String ticker;
      double currentPrice=0.0;
      
      Stock._(this.ticker);
      
      static Future<Stock> stockWithCurrentPrice(String ticker) async {
        Stock stock = Stock._(ticker);
        stock.currentPrice =  await getCurrentPrice (ticker);
        return stock;
      }
}

void main() async {
  Stock stock = await Stock.stockWithCurrentPrice('AAPL');
  print ('${stock.ticker}: ${stock.currentPrice}');
}
Pinocchio
  • 65
  • 5
1

Another benefit of the distinction between named constructor and static function is that in the documentation generated the function will be either filed in the construction section or the methods section, which further makes it's intentions clearer to the reader.

A person looking for a constructor in the constructor section of the documentation will easily discover the named constructors as opposed to having to also dig through the static functions section too.

Kernel James
  • 3,752
  • 25
  • 32
0

In case the class has final fields you may not be able to write a named constructor, but still can write a static method.

In code below we cannot have fromHex constructor, but can have static method:

class Color {
  final int r;
  final int g;
  final int b;

  Color({this.r = 0, this.g = 0, this.b = 0});

  //Color.fromHex(String hex) {...}   //does not compile

  static Color fromHex(String hex) {
    int intColor = int.parse(hex);
    int red = (intColor >> 16) & 0xff;
    int green = (intColor >> 8) & 0xff;
    int blue = (intColor >> 0) & 0xff;
    return Color(r: red, g: green, b: blue);
  }
}

Also, Dart compiler somehow acknowledges similarity and does not allow to have both a named constructor and a static method with the same name.

Yuriy N.
  • 4,936
  • 2
  • 38
  • 31