November 15, 2017
On Tuesday, 14 November 2017 at 23:41:39 UTC, Steven Schveighoffer wrote:
>>> An very similar problem exists for int and char overloads:
>>>
>>> alias foo = (char c) => 1;
>>> alias foo = (int i) => 4;
>>>
>>> enum int e = 7;
>>> static assert(foo(e) == 4); // fails
>> 
>> Wait a minute!  This doesn't appear to be a casting or overload problem.  Can you really overload aliases in D?
>
> In fact, I'm surprised you can alias to an expression like that. Usually you need a symbol. It's probably due to how this is lowered.

Boy did I "step in it" with my original post:  Started out with one issue and ended up with 3.

I looked at what the compiler is doing, and it is generated a new symbol (e.g. `__lambda4`).  I suspect this is not intended.

My question now is, should the compiler actually be treating the lambda as an expression instead of a new symbol, thus disallowing it altogether? (sigh! more breakage)?

Mike
November 15, 2017
On Tuesday, 14 November 2017 at 23:53:49 UTC, H. S. Teoh wrote:

> Argh, should've checked before I posted.  What I meant was more something like this:
>
> 	import std.stdio;
> 	void f(dchar) { writeln("dchar overload"); }
> 	void f(ubyte) { writeln("ubyte overload"); }
> 	void main() {
> 		f(1);
> 		f('a');
> 	}
>
> Output:
> 	ubyte overload
> 	ubyte overload
>
> It "makes sense" from the POV of C/C++-compatible integer promotion rules, but in the context of D, it's just very WAT-worthy.

If you haven't already, can you please submit this to bugzilla.

Thanks,
Mike


November 14, 2017
On 11/14/2017 5:20 AM, Nick Treleaven wrote:
> An very similar problem exists for int and char overloads:
> 
> alias foo = (char c) => 1;
> alias foo = (int i) => 4;
> 
> enum int e = 7;
> static assert(foo(e) == 4); // fails

I cannot reproduce this error.
November 14, 2017
On 11/14/2017 3:09 PM, H. S. Teoh wrote:
> I've been bitten before by things like this:
> 
> 	void myfunc(char ch) { ... }
> 	void myfunc(int i) { ... }
> 
> 	char c;
> 	int i;
> 
> 	myfunc(c);	// calls first overload
> 	myfunc('a');	// calls second overload (WAT)
> 	myfunc(i);	// calls second overload
> 	myfunc(1);	// calls second overload

I just tried:

  import core.stdc.stdio;
  void foo(char c) { printf("char\n"); }
  void foo(int c) { printf("int\n"); }
  void main() {
    enum int e = 1;
    foo(e);
    foo(1);
    foo('c');
  }

and it prints:

  int
  int
  char

I cannot reproduce your or Nick's error.
November 15, 2017
On Wednesday, 15 November 2017 at 04:24:58 UTC, Walter Bright wrote:
> On 11/14/2017 5:20 AM, Nick Treleaven wrote:
>> An very similar problem exists for int and char overloads:
>> 
>> alias foo = (char c) => 1;
>> alias foo = (int i) => 4;
>> 
>> enum int e = 7;
>> static assert(foo(e) == 4); // fails
>
> I cannot reproduce this error.

Try it here: https://run.dlang.io/is/nfMGfG
DMD-nightly
November 15, 2017
On Wednesday, 15 November 2017 at 04:30:32 UTC, Walter Bright wrote:

> I just tried:
>
>   import core.stdc.stdio;
>   void foo(char c) { printf("char\n"); }
>   void foo(int c) { printf("int\n"); }
>   void main() {
>     enum int e = 1;
>     foo(e);
>     foo(1);
>     foo('c');
>   }
>
> and it prints:
>
>   int
>   int
>   char

The code posted was incorrect.  See http://forum.dlang.org/post/mailman.154.1510704335.9493.digitalmars-d@puremagic.com


November 15, 2017
On 11/14/17 8:56 PM, Michael V. Franklin wrote:
> On Tuesday, 14 November 2017 at 23:41:39 UTC, Steven Schveighoffer wrote:
>> In fact, I'm surprised you can alias to an expression like that. Usually you need a symbol. It's probably due to how this is lowered.
> 
> Boy did I "step in it" with my original post:  Started out with one issue and ended up with 3.
> 
> I looked at what the compiler is doing, and it is generated a new symbol (e.g. `__lambda4`).  I suspect this is not intended.
> 
> My question now is, should the compiler actually be treating the lambda as an expression instead of a new symbol, thus disallowing it altogether? (sigh! more breakage)?

I don't think we can prevent the aliasing in the first place, because if this is possible, I guarantee people use it, and it looks quite handy actually. Much less verbose than templates:

alias mul = (a, b) => a * b;

vs.

auto mul(A, B)(A a, B b) { return a * b; }

However, it would be good to prevent the second alias which effectively does nothing.

-Steve
November 15, 2017
On Wednesday, November 15, 2017 07:28:02 Steven Schveighoffer via Digitalmars-d wrote:
> On 11/14/17 8:56 PM, Michael V. Franklin wrote:
> > On Tuesday, 14 November 2017 at 23:41:39 UTC, Steven Schveighoffer
wrote:
> >> In fact, I'm surprised you can alias to an expression like that. Usually you need a symbol. It's probably due to how this is lowered.
> >
> > Boy did I "step in it" with my original post:  Started out with one issue and ended up with 3.
> >
> > I looked at what the compiler is doing, and it is generated a new symbol (e.g. `__lambda4`).  I suspect this is not intended.
> >
> > My question now is, should the compiler actually be treating the lambda as an expression instead of a new symbol, thus disallowing it altogether? (sigh! more breakage)?
>
> I don't think we can prevent the aliasing in the first place, because if this is possible, I guarantee people use it, and it looks quite handy actually. Much less verbose than templates:
>
> alias mul = (a, b) => a * b;
>
> vs.
>
> auto mul(A, B)(A a, B b) { return a * b; }

In general, alias aliases symbols, whereas a lambda isn't a symbol. They're essentially the rvalue equivalent of functions. So, in that sense, it's pretty weird that it works. However, we _do_ use it all the time with alias template parameters. So, regardless of what would make sense for other aliases, if we just made it so that alias in general didn't work with lambdas, we'd be in big trouble. It wouldn't surprise me if the fact that aliases like this works with lambdas is related to the fact that it works with alias template parameters, but I don't know. It may simply be that because of how the compiler generates lambdas, it ends up with a name for them (even if you don't see it), and it just naturally came out that those were aliasable.

> However, it would be good to prevent the second alias which effectively does nothing.

As far as I'm concerned, in principal, it's identical to declaring a
variable with the same name in the same scope, and I'm very surprised that
it
works. Interestingly, this code

alias foo = int;
alias foo = float;

_does_ produce an error. So, it looks like it's a problem related to lambdas specifically.

- Jonathan M Davis

November 15, 2017
On 11/15/17 9:07 AM, Jonathan M Davis wrote:
> On Wednesday, November 15, 2017 07:28:02 Steven Schveighoffer via
> Digitalmars-d wrote:
>> On 11/14/17 8:56 PM, Michael V. Franklin wrote:
>>> On Tuesday, 14 November 2017 at 23:41:39 UTC, Steven Schveighoffer
> wrote:
>>>> In fact, I'm surprised you can alias to an expression like that.
>>>> Usually you need a symbol. It's probably due to how this is lowered.
>>>
>>> Boy did I "step in it" with my original post:  Started out with one
>>> issue and ended up with 3.
>>>
>>> I looked at what the compiler is doing, and it is generated a new symbol
>>> (e.g. `__lambda4`).  I suspect this is not intended.
>>>
>>> My question now is, should the compiler actually be treating the lambda
>>> as an expression instead of a new symbol, thus disallowing it
>>> altogether? (sigh! more breakage)?
>>
>> I don't think we can prevent the aliasing in the first place, because if
>> this is possible, I guarantee people use it, and it looks quite handy
>> actually. Much less verbose than templates:
>>
>> alias mul = (a, b) => a * b;
>>
>> vs.
>>
>> auto mul(A, B)(A a, B b) { return a * b; }
> 
> In general, alias aliases symbols, whereas a lambda isn't a symbol. They're
> essentially the rvalue equivalent of functions. So, in that sense, it's
> pretty weird that it works. However, we _do_ use it all the time with alias
> template parameters. So, regardless of what would make sense for other
> aliases, if we just made it so that alias in general didn't work with
> lambdas, we'd be in big trouble. It wouldn't surprise me if the fact that
> aliases like this works with lambdas is related to the fact that it works
> with alias template parameters, but I don't know. It may simply be that
> because of how the compiler generates lambdas, it ends up with a name for
> them (even if you don't see it), and it just naturally came out that those
> were aliasable.
> 
>> However, it would be good to prevent the second alias which effectively
>> does nothing.
> 
> As far as I'm concerned, in principal, it's identical to declaring a
> variable with the same name in the same scope, and I'm very surprised that
> it
> works. Interestingly, this code
> 
> alias foo = int;
> alias foo = float;

alias statements and alias parameters have differences, so I don't know if there is any real relation here. For example, int cannot bind to a template alias.

Some really weird stuff is going on with aliasing and function overloads in general.

If we change them from anonymous lambdas to actual functions:

auto lambda1(char c) { return 1; }
auto lambda2(int i) { return 4; }

alias foo = lambda1;
alias foo = lambda2;

void main()
{
   assert(foo('a') == 1);
   assert(foo(1) == 4);
}

Hey look, it all works!

Even if lambda1 and lambda2 are turned into templates, it works.

I seriously did not expect this to work.

-Steve
November 15, 2017
On Wednesday, 15 November 2017 at 15:25:06 UTC, Steven Schveighoffer wrote:
> alias foo = lambda1;
> alias foo = lambda2;

What?