May I introduce `lazy with`?

Quirin Schroll qs.il.paperinik at gmail.com
Thu Nov 24 17:41:20 UTC 2022


[Enhancement issue 
23503](https://issues.dlang.org/show_bug.cgi?id=23503)

In the discussion thread for DIP 1044, because Walter suggested 
adding an implicit `with (typeof(expr))` to `switch (expr)`, it 
occurred to me that `with` has an issue that makes it unsuitable 
for certain use-cases, including generic code, and that issue can 
be solved.

The essence of the problem is that `with (TypeOrExpr)` will 
prefer resolving an identifier `id` as `TypeOrExpr.id` whenever 
`TypeOrExpr.id` is viable:
```d
with (EnumType)
switch (enumValue)
{
     static foreach (member; EnumMembers!EnumType)
     {
         case member: // What if EnumType has a member named 
`member`?
             ...;
     }
}
```
When `EnumType` happens to have a member named `member`, `with` 
will greedily take it and the loop will produce nonsense.

What would be useful here is a version of `with` that only 
resolves `id` as `TypeOrExpr.id` whenever `id` is not otherwise 
resolvable, i.e. as a last resort.

I’d suggest using `lazy with` for that construct. It is otherwise 
exactly like `with`. Its advantage is that it can be used in 
generic code and thus be implicitly added.

Were the `with` statement above a `lazy with`, the identifier 
`member` would always resolve to the `foreach` iteration.

Following Walter’s suggestion, a `lazy with` can be added 
implicitly to `switch` statements and declarations with 
spelled-out type:
```d
EnumType e = enumMember;
// as if `EnumType e = EnumType.enumMember`, unless `enumMember` 
is in scope

int x = max - 1; // as if `int x = int.max - 1`, unless another 
`max` is in scope.
double myEps = 2 * epsilon; // as if `= 2 * double.epsilon`, 
unless...
```
Note that `with (int)` currently does not work.

What do you think?


More information about the Digitalmars-d mailing list