May I introduce `lazy with`?
Quirin Schroll
qs.il.paperinik at gmail.com
Fri Nov 25 08:58:53 UTC 2022
On Thursday, 24 November 2022 at 19:27:00 UTC, Paul Backus wrote:
> On Thursday, 24 November 2022 at 17:41:20 UTC, Quirin Schroll
> wrote:
>> 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.
>
> I tried it on run.dlang.io and `member` is correctly resolved
> as referring to the loop variable, not the enum member. Here's
> a complete, compilable example:
Sorry, I gust believed that Steven’s post was based on testing
himself, especially note the sentence I highlighted.
On Wednesday, 23 November 2022 at 03:24:30 UTC, Steven
Schveighoffer wrote:
> To spell it out, when you write `case member:` what does
> `member` refer to? It currently, in the implementation of
> Phobos refers to the `member` iteration variable of the foreach
> inside to!string:
>
> ```d
> foreach(member; EnumMembers!E) {
> ```
>
> **But if an implicit `with(Role)` is added to the case clause,
> now it only ever refers to `Role.member`.** Essentially, you
> will end up with a switch that looks like:
>
> ```d
> switch(e) {
> case Role.member: ...
> case Role.member: ...
> case Role.member: ...
> default: ...
> }
> ```
Steven’s claims are based on what the spec [Statement § With
Statement](https://dlang.org/spec/statement.html#with-statement)
says what should happen:
> Within the with body the referenced object is searched first
> for identifier symbols.
And a little later:
> Use of `with` object symbols that shadow local symbols with the
> same identifier are not allowed.
So, Steven seemingly didn’t test and read the spec section
completely and the compiler has a bug: The `static foreach` is
the greedy one here and `with` never gets to see `member` as a
plain identifier.
I guess we could reasonably give `static foreach` that high
priority officially. Still, the point stands that `with` is
greedy enough that it ambiguates local symbols and shadows
lower-scope symbols. `lazy with` would not do that.
More information about the Digitalmars-d
mailing list