November 18, 2022
On 18.11.22 11:59, Timon Gehr wrote:
> 
> 
>> which is used to optimize performance (in Dart, `const` is closer to D's `immutable`).
> 
> Actually, it is closer to `static immutable`.

(But even that analogy has significant limitations, e.g., transitivity of Dart `const` is often checked at runtime, even if it is completely obvious during type checking that an assignment is not going to work.)
November 18, 2022

On Friday, 18 November 2022 at 11:06:44 UTC, Timon Gehr wrote:

>

On 18.11.22 11:59, Timon Gehr wrote:

> >

which is used to optimize performance (in Dart, const is closer to D's immutable).

Actually, it is closer to static immutable.

(But even that analogy has significant limitations, e.g., transitivity of Dart const is often checked at runtime, even if it is completely obvious during type checking that an assignment is not going to work.)

It's not as complicated as you are making it out to be. The purpose of Dart's late variables is as they describe:

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.

The same use-cases would apply in D, these situations are programming-language agnostic. For example, you are building a complicated geometric library object (as is the case in the S2 Geometric library), and it contains a complex index data structure which will be used to organize the data before it is written to disk. When data is being written to disk, you want this variable to be computed only once, it will not change once used, and you would still like to use these objects in const contexts that will not change the values. However, if you are not calling the methods that write to disk, then computing the index isn't necessary and can be avoided.

There are many cases where lazy initialization can be used to avoid costly setup, but currently in D, if you use lazy initialization, you must immediately rewrite all your code and avoid ever using const, because it might trigger initialization of lazy variables. This is especially silly for functions like "print" or "writeToDisk", which absolutely do not modify the classes at hand.

November 18, 2022
On Thursday, 17 November 2022 at 15:33:47 UTC, razyk wrote:
> On 17.11.22 13:04, MorteFeuille123 wrote:
>>>
>>> Is there another way to perform lazy initialization that is compatible with const/immutable, or is this needed as a language feature?
>> 
>> No, this is needed as a bultin feature I'd say. I sometime think that since we can have local static variablbes, we could have local member variables. Similarly hiddden, only accessible through a getter, which replaces the need for a const member.
>
> module2.d
> ```
> import std.stdio;
>
> private string _lazy1;
>
> string compute(){
>   writeln("computing...");
>   return "_lazy1 val";
> }
>
> string lazy1(){
>   if (_lazy1 == null)
>     _lazy1 = compute();
>   return _lazy1;
> }	
> ```
>
> module1.d
> ```
> import std.stdio;
> import module2;
>
> void main() {
>   writeln(lazy1);
>   writeln(lazy1);
> }
> ```

No, I tought to this pattern:

    auto getLazyGlobal()
    {
        static int result; // global but only accessible in getLazyGlobal
        static bool done;  // ditto
        scope(exit) done = true;
        return done ? result : (result = compute())
    }

but applied to member variables.
That would require a new syntax or a new storage class

    struct S
    {
        auto getLazyMember()
        {
            int S.result;
            bool S.done;
            scope(exit) done = true;
            return done ? result : (result = compute())
        }
    }

so that `result` and `done` are well `S` members but only accessible in `getLazyMember()`.
November 19, 2022
On 18.11.22 18:22, Vijay Nayar wrote:
> On Friday, 18 November 2022 at 11:06:44 UTC, Timon Gehr wrote:
>> On 18.11.22 11:59, Timon Gehr wrote:
>>>
>>>
>>>> which is used to optimize performance (in Dart, `const` is closer to D's `immutable`).
>>>
>>> Actually, it is closer to `static immutable`.
>>
>> (But even that analogy has significant limitations, e.g., transitivity of Dart `const` is often checked at runtime, even if it is completely obvious during type checking that an assignment is not going to work.)
> 
> It's not as complicated as you are making it out to be.

I don't understand what you think is complicated. Everything I wrote was true. The issue was that in your post you were conflating concepts in D and Dart that are only superficially similar.

Anyway, by all means, go ahead and create a DIP for lazy initialization. I have proposed this exact thing (with lazy keyword and all) in the past, but it never really caught on. (And frankly, it _would_ be confusing if for fields "lazy" actually meant lazy while for function parameters it still means "by name"...)

> The purpose of Dart's late variables is as they describe:
> 

I am very much aware of the purpose of lazy initialization. It's one reason for my recommendation to avoid D's mutability qualifiers if any kind of abstraction is involved. The mutability qualifiers break abstractions.

Anyway, Dart is not actually providing anything that you can't have in D. It does not actually have transitive `const` and `immutable` qualifiers. Those are the issue. If you don't use them you can use the same patterns as in Dart, just with different syntax.

> ...
> 
> There are many cases where lazy initialization can be used to avoid costly setup, but currently in D, if you use lazy initialization, you must immediately rewrite all your code

Not if you avoided qualifiers. (As I do.)

> and avoid ever using `const`, 

Yes, that was my point. Lazy initialization is not the only common pattern that the qualifiers prevent. Don't use them unless you know exactly what you are doing and will want to do in the future. (So very infrequently or at least in very special circumstances.)

> because it might trigger initialization of lazy variables. This is especially silly for functions like "print" or "writeToDisk", which absolutely do not modify the classes at hand.

That's a weird way to put it because they do actually modify memory during late initialization and `const` prevents you from doing it. Don't use `const` if that's not what you want. Probably you want what's sometimes called "logical const", but that's not a feature in D.

In your OP, you asked the question "Is there another way to perform lazy initialization that is compatible with const/immutable, or is this needed as a language feature?"

You'd need to change the language to do what you want, but just adding built-in support for lazy initialization would not actually fix the more general problem. Mutation of memory is often an implementation detail, not just for lazy initialization. You'd probably just run into some other roadblock further down the line. And any hack you do in your own code to work around the strictness of qualifiers leads to undefined behavior. It's just not worth the hassle.

1 2
Next ›   Last »