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:
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:
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?
Permalink
Reply