Lazily Initialized Variables that are Compatible with const/immutable
Vijay Nayar
madric at gmail.com
Thu Nov 17 10:57:55 UTC 2022
An uncommon, but not rare, situation that I run into from time to
time, is that there are variables used either globally or as a
member of a class that are expensive in their resource usage
(time to compute, or memory size), but which are only sometimes
used, e.g. only when certain functions are called, which depends
on the runtime usage of the program.
The concept of [lazy
initialization](https://en.wikipedia.org/wiki/Lazy_initialization) is used in these situations to avoid paying this cost up front, and deferring it until the value is used. E.g. if your object has a member named `value`, then `obj.value` may refer to a method that returns a cached value, and if the cache is empty, produces the value and caches it.
However, in D, such usage runs into problems when the
object/method is either `const` or `immutable`. Making such
changes requires modifying a variable that technically existed at
the time `obj` was created.
While working on a project, I encountered a solution in Dart
which I think could be carried over into D:
https://dart.dev/guides/language/language-tour#late-variables
```
When you mark a variable as late but initialize it at its
declaration, then the initializer runs the first time the
variable is used. This lazy initialization is handy in a couple
of cases:
The variable might not be needed, and initializing it is
costly.
You’re initializing an instance variable, and its initializer
needs access to this.
In the following example, if the temperature variable is never
used, then the expensive readThermometer() function is never
called:
// This is the program's only call to readThermometer().
late String temperature = readThermometer(); // Lazily
initialized.
```
The already existing keyword `lazy` could be used for this
purpose in D, and then it would be possible to write code such as:
```
class Thing {
lazy immutable String piDigits = computePiDigits();
String computePiDigits() { ... }
double getTemperature() const {
// If only this function is used, piDigits is never computed.
}
double getCircumferance() const {
// Some silly usage of piDigits, which causes
computePiDigits() to be run.
return piDigits.to!double * radius * 2.0;
}
}
```
Is there another way to perform lazy initialization that is
compatible with const/immutable, or is this needed as a language
feature?
More information about the Digitalmars-d
mailing list