D Editions

Quirin Schroll qs.il.paperinik at gmail.com
Wed Jun 12 12:54:03 UTC 2024


On Tuesday, 11 June 2024 at 16:08:54 UTC, Atila Neves wrote:
> On Sunday, 9 June 2024 at 18:43:51 UTC, Vladimir Panteleev 
> wrote:
>> On Thursday, 30 May 2024 at 18:31:48 UTC, Atila Neves wrote:
>>> [...]
>>
>> I would just like to comment on one aspect of the DIP for now: 
>> the "Examples" section is a bit of a sore sight currently. 
>> It's difficult to get excited about the idea when the proposed 
>> actions it unlocks is "we're changing two defaults and 
>> removing three features without providing an immediate 
>> replacement".
>>
>> Regarding the removal of `lazy`, I'm particularly curious 
>> about the consequent fate of `assert` and `enforce`, two 
>> prominent current users of `lazy. It seems like either way 
>> would involve a compromise:
>>
>> - Will `assert` fully become "compiler magic", unimplementable 
>> in user code, and `enforce` replaced with an explicit delegate 
>> variant?
>> - Will both `assert` and `enforce` require an explicit 
>> delegate, thus making unit tests quite a bit more 
>> syntactically noisy?
>> - Will both `assert` and `enforce` become "compiler magic" 
>> (and therefore unimplementable in user code)?
>
> Good questions. Enforce would have to take a delegate, but 
> `assert` could be magic. I'm not sure that's a good idea 
> though. In any case, that's an idea of what we could do, I'm 
> not sure we will.

I don’t see why `assert` would be considered “magic.” On the one 
hand, it’s a language primitive, so it’s not magic, it’s just 
defined in some way, and short circuiting operations do exist in 
`&&` and `||` and those are around basically forever. On the 
other hand, why not just evaluate the message regardless if the 
condition fails? In many cases, the message is a string literal, 
and almost all cases where it’s not just a literal, it has no 
side-effects, so the compiler can actually refrain from 
evaluating the message unless the condition fails – as an 
optimization. Assert messages with side-effects are such an 
anti-pattern, maybe it shouldn’t even be allowed.

For `lazy`, yes, lazy function parameters are weird and I’d 
rather have explicit delegates. One thing `lazy` could bring as a 
storage class applied to a delegate type or array or slice of 
delegate type parameter: The caller guarantees that each such 
delegate is evaluated at most once.

TL;DR (next): Don’t give up `lazy` as a keyword, it might be 
handy.

For data members of structs or classes, `lazy` could be 
implemented so that they’re lazily evaluated. Of course, for 
mutable objects, one can implement lazy evaluation by hand, but 
in D, `immutable` values can’t make use of lazy evaluation except 
by having state that’s conceptually part of an object actually 
placed in a global/thread local outside of them, which is 
incompatible with `pure`. With `lazy`, one could have an object 
be `immutable` with all its guarantees (maybe with select 
exceptions such as placing it in the read only section of the 
binary), but allowing for lazy evaluation. If the language 
handles the lazy evaluation, it can make guarantees that the 
programmer simply can’t. It’s a design hole. The essence of 
`immutable` is that no-one can observe mutations of this object. 
If the programmer cannot ask: “Has this `lazy` data member been 
evaluated and cached yet?” No mutations can be observed. It does 
not have to be a data member storage class either, it might be 
much more practical to implement as a function attribute so that 
the annotated function runs at most once, and if it did, the 
result is cached into a (hidden) data member, so that when it 
runs again, only the value of the data member is returned.


More information about the dip.ideas mailing list