In the code below to implement the Singleton design pattern, we approach two different ways.
One of them creates Singleton
but the other creates an object each time we call it.
What's the difference between ??
and =??
in the code below written in dart?
class ExampleStateByDefinition extends ExampleStateBase {
static ExampleStateByDefinition? _instance;
ExampleStateByDefinition._internal() {
initialText = 'A new "ExampleStateByDefinition" instance has been created.';
stateText = initialText;
print(stateText);
}
static ExampleStateByDefinition? getState() {
return _instance ?? ExampleStateByDefinition._internal(); //here we use ??
}
}
The above code creates an object each time we call it, so let us look at another variant:
class ExampleStateByDefinition extends ExampleStateBase {
static ExampleStateByDefinition? _instance;
ExampleStateByDefinition._internal() {
initialText = 'A new "ExampleStateByDefinition" instance has been created.';
stateText = initialText;
print(stateText);
}
static ExampleStateByDefinition? getState() {
_instance ??= ExampleStateByDefinition._internal(); //Here we use ??=
return _instance;
}
}
The above code implements Singleton by definition in Design Patterns: Elements of Reusable Object-Oriented Software
CodePudding user response:
Based on dart tour.
To assign only if the assignment to the variable is null we use ??=
operation.
expr1 ?? expr2
if expr1 is not null, return its value; otherwise, evaluates and return the value of expr2.
Cause ??
operation evaluates each time we call the object, it creates a new object.
CodePudding user response:
Both ??
and ??=
are null-aware operators.
Difference
The difference between the two operators is that the former only evaluates an expression while the latter also assigns the result of the expression.
This is why your first sample returns a new instance each time since you never assign it to your static variable.
??
Use ?? when you want to evaluate and return an expression IFF another expression resolves to null.
The following expression:
exp ?? otherExp;
Is similar to this expression:
((x) => x == null ? otherExp : x)(exp);
??=
Use ??= when you want to assign a value to an object IFF that object is null. Otherwise, return the object.
The following expression:
obj ??= value;
Is similar to this expression:
((x) => x == null ? obj = value : x)(obj);
See Null-aware operators in Dart for reference.
CodePudding user response:
The ??=
operator is a compound assignment operator.
Just like target = 1
is equivalent to target = target 1
(but with target
only evaluated once, if it's a complicated expression),
target ??= expression
is equivalent to target = target ?? expression
(but with target
only evaluated once and the assignment not even happening if target
is non-null
).
So, yhe difference is that the first code probably doesn't work, the second one does.
The code:
return _instance ?? ExampleStateByDefinition._internal();
checks whether _instance
is non-null
, and if so, it returns the value of _instance
. If it is null
, it evaluates and returns ExampleStateByDefinition._internal()
.
No-where in that does it assign to _instance
. So, _instance
is always going to be null
, and the code is probably failing to do what it intended to do—caching a value.
The code:
_instance ??= ExampleStateByDefinition._internal();
return _instance;
or its more streamlined version:
return _instance ??= ExampleStateByDefinition._internal();
will also check if _instance
is null
and return its value if it isn't.
If _instance
is null
, it also evaluates ExampleStateByDefinition._internal();
, and then it assigns it to _instance
, and returns the value.
The next time you come around, _instance
will be non-null
, and the lazy caching works.