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