The output of the following two codes are the same, but what is the essential difference?
A Tour of the Dart Language - Initializer list
import 'dart:math';
class Point {
final num x;
final num y;
final num distanceFromOrigin;
Point(x, y)
: x = x,
y = y,
distanceFromOrigin = sqrt(x * x + y * y);
}
main() {
var p = Point(3, 4);
print(p.distanceFromOrigin);
}
My code
Point(this.x, this.y)
: distanceFromOrigin = sqrt(x * x + y * y);
Both Outputs are the same 5.
Best regards,
An initializer list allows you to assign properties to a new instance variables before the constructor body runs, but after creation. This is handy when you want to set a final variables value, but the value isn't a compile-time constant.
A constructor is a special function of the class that is responsible for initializing the variables of the class. Dart defines a constructor with the same name as that of the class. A constructor is a function and hence can be parameterized. However, unlike a function, constructors cannot have a return type.
Initializer List is used in initializing the data members of a class. The list of members to be initialized is indicated with constructor as a comma-separated list followed by a colon. Following is an example that uses the initializer list to initialize x and y of Point class.
As already answered, initialization lists get completely executed before entering the constructor block. So it is completely safe to use (initialized) members in the constructor body.
There is no difference, the result will be the same except that you can take advantage of different type of constructors.
In the case you don't want to expose your variables defined in Point and your mark those as private, the initializer would be a good option.
class Point {
final num _x;
final num _y;
final num _distanceFromOrigin;
Point(x, y)
: _x = x,
_y = y,
_distanceFromOrigin = sqrt(x * x + y * y);
}
Also take a look to the constructor with optional parameters or factory constructors.
Whether by train or pram, once you reach the station, it makes no "essential" difference if only arriving at the destination matters.
Using "constructor" and "initializer list", you did get the same output, but that example is not the only use case supported by these features in Dart. Moreover, the shorter form (using "constructor" as an alternative to "initializer list") is just a frequent manifestation where Dart provided it as "syntactic sugar":
The pattern of assigning a constructor argument to an instance variable is so common, Dart has syntactic sugar to make it easy:
class Point {
double x = 0;
double y = 0;
// Syntactic sugar for setting x and y
// before the constructor body runs.
Point(this.x, this.y);
}
I have used the terms "constructor" and "initializer list" apropos of your question/example, but to clearly mention the differences, I shall be using the following terminology for a broader perspective:
ClassName[.<constructor-name>](<constructor-args>)
: <initializer-list> {
<constructor-body>
}
Until this part of the answer, the focus on "constructor" was largely disregarding the constructor's body, which happened to be the case since that example was probably meant to introduce initializer lists, as evident from the involvement of final members.
Constructor's body cannot be used to initialize non-nullable and/or final members. It could be done
this.
syntactic sugar), orclass Demo {
int x; // non-nullable member
final int? y; // final member
// ERROR (observe <constructor-body>'s limitation)
Demo.constructor1(int x, int y) {
this.x = x;
this.y = y;
}
// Allowed
Demo.constructor2(int x, int y)
: x = x,
y = y;
// Better (observe <constructor-args>'s syntactic sugar)
Demo.constructor3(this.x, this.y);
// ERROR
Demo.constructor4(this.x, this.y = this.x + 1);
// Allowed (observe <initializer-list>'s rescue)
Demo.constructor5(this.x) : y = x + 1;
}
Aside, this does not make initializer list a replacement for constructor body since initializer lists are very limited in functionality.
Another important difference is their order of execution, which could be significant from a design perspective, especially involving inheritance. It is fittingly documented in the language tour:
[...] the order of execution is as follows:
- initializer list
- superclass’s no-arg constructor
- main class’s no-arg constructor
If the superclass doesn’t have an unnamed, no-argument constructor, then you must manually call one of the constructors in the superclass. Specify the superclass constructor after a colon (:), just before the constructor body (if any).
Jamesdlin's comment contains a good summary.
How should I use constructor and initializer list properly?
Keeping the aforementioned differences in mind, "proper" usage objectively abides by such language constraints, but in cases where both the usage is appropriate, I reckon you are correct in utilizing the syntactic sugar for writing idiomatic Dart code unless required otherwise by something akin to an enforced style guide.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With