November 19, 2022

On Friday, 18 November 2022 at 22:49:33 UTC, Timon Gehr wrote:

>

Why "contemplate"? D already has such inference for delegates.

import std.stdio;

enum A{
    a,
    b,
}
enum B{
    b,
    c,
}

void foo(A delegate(A) dg){
    writeln("first overload");
}
void foo(B delegate(B) dg){
    writeln("second overload");
}

void main(){
    foo((x){ // first overload
        static if(__traits(hasMember,typeof(x),"a"))
            return typeof(x).a;
    });
    /+foo((x){ // error, ambiguous
        static if(__traits(hasMember,typeof(x),"b"))
            return typeof(x).b;
    });+/
    foo((x){ // second overload
        static if(__traits(hasMember,typeof(x),"c"))
            return typeof(x).c;
    });
}

It works just fine. Now just do literally the same thing for the new enum inference. Probably one can even reuse some of the compiler code.

Excellent observation, definitely did not occur to me! IMO this would greatly increase the appeal of this DIP. It can sidestep many of the difficult questions about corner cases with complex expressions.

November 19, 2022

On Saturday, 19 November 2022 at 02:57:27 UTC, Walter Bright wrote:

>

On 11/18/2022 6:06 PM, ryuukk_ wrote:

>

MySuperLongType flag = MySuperLongType.ValueA | MySuperLongType.ValueB | MySuperLongType.ValueC | MySuperLongType.ValueD | MySuperLongType.ValueE | MySuperLongType.ValueF | MySuperLongType.ValueG;

// vs

MySuperLongType flag = .ValueA | .ValueB | .ValueC | .ValueD | .ValueE | .ValueF | .ValueG;

with (MySuperLongType)
MySuperLongType flag = ValueA | ValueB | ValueC | ValueD | ValueE | ValueF | ValueG;

Since with creates a new scope, it would have to be

auto flag = { with(MySuperLongType) return
     ValueA | ValueB | ValueC | ValueD
     | ValueE | ValueF | ValueG;
}();

Still a lot better than repeating MySuperLongType for each member IMO, but ugly enough that this DIP would be an improvement.

November 19, 2022

On Saturday, 19 November 2022 at 08:33:50 UTC, Dukc wrote:

>

Since with creates a new scope, it would have to be

auto flag = { with(MySuperLongType) return
     ValueA | ValueB | ValueC | ValueD
     | ValueE | ValueF | ValueG;
}();

Still a lot better than repeating MySuperLongType for each member IMO, but ugly enough that this DIP would be an improvement.

Will this be better if it's supported?

auto flag = with(MySuperLongType)
            ValueA | ValueB | ValueC | ValueD | ValueE | ValueF | ValueG;
November 19, 2022

On Friday, 18 November 2022 at 19:33:05 UTC, H. S. Teoh wrote:

>

On Fri, Nov 18, 2022 at 07:14:14PM +0000, IGotD- via Digitalmars-d wrote:

>

The $myEnum syntax is really hideous compared to the .myEnum. The
.myEnum syntax feels natural where $myEnum looks like it is some kind
macro parameter or something. There is a reason that all other example
languages like Swift use the . syntax.

Yeah, $ is really hideous and sticks out like a sore thumb in typical
D code. On top of that, it overloads the current usage of $ to
something completely unrelated, which makes it look really messy. Why
can't we just stick with .?

(He / She)? gave a good reason, that already means "fetch from module namespace". While we could devise rules to make those disambiguate from each other, it'd be too much complexity for slightly better-looking syntax IMO.

I thus prefer $. However, Timons idea, _, is even better.

November 19, 2022
The contextual inference only takes place in certain contexts. Perhaps we can run with that idea. Let's take case statements:

  enum WordLetterOfTheDay{ a,b,c,d/*...*/ }

  void main(){
    auto letterToday = WordLetterOfTheDay.b;

    import std.stdio;
    switch(letterToday){
        case $a:
            writeln("Apple");
            break;
        case $b:
            writeln("Bicycle");
            break;
        case $c:
            writeln("Caterpillar");
            break;
        case $d:
            writeln("Didgeridoo");
            break;
        /*...*/
    }
  }

and recognize that the SwitchExpression is of type WordLetterOfTheDay. Implicitly enclose the switch body with a `with (WordLetterOfTheDay)` resulting in:

  enum WordLetterOfTheDay{ a,b,c,d/*...*/ }

  void main(){
    auto letterToday = WordLetterOfTheDay.b;

    import std.stdio;
    switch(letterToday){
        case a:
            writeln("Apple");
            break;
        case b:
            writeln("Bicycle");
            break;
        case c:
            writeln("Caterpillar");
            break;
        case d:
            writeln("Didgeridoo");
            break;
        /*...*/
    }
  }

Note the disappearance of the `$`, and use of the leading `.` operator retains its existing meaning.

Applying the same to Initializers and assignments:

  enum A{ a,b,c,d }

  struct S{ A one, two; }

  void main(){
    A    myA1 = b;      // myA1 = A.b
    A    myA2 = b | c;  // myA2 = A.c
    auto myA3 = b;      // error, b is undefined

    S myS;
    myS.one = c; // myB.one = A.c
    myS.two = d; // myB.two = A.d
  }

To Return statements:

  enum A{ a,b,c,d }

  A myFn(){
    return c; //returns A.c
  }

  auto myBrokenFn(){
    return c; // error, c is undefined
  }

Argument lists:

  Only works if there are no overloads.

Array literals:

  enum A{ a,b,c,d }

  // (A)
  A[4] x = [a, b, c, d];
  // (B)
  auto y = [A.a, b, c, d]; // error, b is undefined
  auto z = [A.c, 64, b, b]; // error, b is undefined

Now, suppose instead you write:

  enum A{ a,b,c,d }

  A b = c;
  A[4] x = [a, b, c, d];

Is the `b` A.b or A.c? A.b since the `with` has a narrower scope than the local `b`. If the user wants the local `b`, he will need to rename it.

Advantages of this scheme:

1. doesn't need the special `$` which people don't seem to like, and using `.` conflicts with existing use

2. makes use of the already present `with` semantics

3. seems to have a natural feel to it


November 19, 2022
I like this design.
November 19, 2022

On Saturday, 19 November 2022 at 08:44:34 UTC, Andrey Zherikov wrote:

>

Will this be better if it's supported?

auto flag = with(MySuperLongType)
            ValueA | ValueB | ValueC | ValueD | ValueE | ValueF | ValueG;

I'd like that sure! In this case yes IMO.

The proposed syntax is still better though when you reassign to an already declared value.

flag &= $.ValueA | $.ValueC;

Whether that's a strong enough case to implement the proposal alongside expression withs, is another question. I haven't decided my opinion yet.

November 19, 2022
On 11/19/22 05:22, Walter Bright wrote:
> Consider this:
> 
>      enum A { a; }
>      enum B { a; }
> 
>      void f(A);
>      void f(B);
> 
>      ...
>      f($a + $a); // mentioned in the DIP as allowed
>      ...
> 
> Since the DIP allows expressions containing such enum inferences, it looks like we are faced with the possibility of having to re-run the semantic pass for enum arguments for every enum overload.

Only if the new feature is actually used, and yes, this is the same as for function literals. I guess the implementation can be optimized further for enum arguments, but I doubt it would make a meaningful difference.

November 19, 2022
On Saturday, 19 November 2022 at 08:49:31 UTC, Walter Bright wrote:
> The contextual inference only takes place in certain contexts. Perhaps we can run with that idea.

Would this generalize to struct construction like i mentioned here:
https://forum.dlang.org/post/bievvzpabbxddogbmpgu@forum.dlang.org


If you can do an implicit with, you can also do an implicit alias of the with subject. And once you have implicit alias you can  construct a struct which adds to the value significantly.


Actually, I do wish `with` in general had a way to refer back to the subject of it. Maybe we could add something there then it'd magically apply to the implicit with too.
November 19, 2022
On Saturday, 19 November 2022 at 03:46:55 UTC, Walter Bright wrote:
> True, but you could also do:
>
> with (MySuperLongType):  // <= note colon
> MySuperLongType flag = ValueA | ValueB | ValueC | ValueD | ValueE | ValueF |
>  ValueG;

Something I do before making a post is to run it through the compiler to ensure it actually works like I'm claiming it works. You should do this too.

The colon form is only valid outside functions, not inside them*. Inside a function, you need to use the {} form.

(btw my experience with the colon form outside functions tends to be regret anyway so I very rarely use it anymore anyway.)

* well ok, you can put a nested aggregate inside a function and that's kinda still inside a function. but you know what i mean, i think the grammar calls it a declaration context vs a statement context but i forget the formal words.