www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Delegate parameter name shadows type name

reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
This is something that surprised me in a friend's code.

(A "friend", hmmm? No, really, it wasn't me! :) )

// Some type of the API
struct MyType {
     int i;
}

// Some function of the API that takes a delegate
void call(void delegate(MyType) dlg) {
     dlg(MyType(42));
}

void main() {
     /* The programmer simply copied the delegate definition from
      * the function and used it as-is when passing a lambda: */
     call(delegate void(MyType) {
             /* WAT? Does the following really compile? After all,
              * MyType.i is NOT a static member! */
             if (MyType.i == 42) {
                 // ...
             }
         });
}

I was surprised to see it compiled and worked but of course MyType at 
the lambda definition inside main() is not a type name, rather the 
parameter name. Surprising, but I think this is according to spec.

Ali
Jan 09 2017
next sibling parent reply "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
On Mon, Jan 09, 2017 at 11:18:02AM -0800, Ali Çehreli via Digitalmars-d-learn
wrote:
[...]
 // Some type of the API
 struct MyType {
     int i;
 }
 
 // Some function of the API that takes a delegate
 void call(void delegate(MyType) dlg) {
     dlg(MyType(42));
 }
 
 void main() {
     /* The programmer simply copied the delegate definition from
      * the function and used it as-is when passing a lambda: */
     call(delegate void(MyType) {
Are you sure this isn't spelt `void delegate(MyType)`?
             /* WAT? Does the following really compile? After all,
              * MyType.i is NOT a static member! */
             if (MyType.i == 42) {
                 // ...
             }
         });
 }
 
 I was surprised to see it compiled and worked but of course MyType at
 the lambda definition inside main() is not a type name, rather the
 parameter name. Surprising, but I think this is according to spec.
[...] I think it makes sense relative to your rationalization of it per the spec, but from an objective POV, I think it rightly deserves a WAT?. I can't see anything useful such a construction would allow, besides leading to buggy code caused by unexpected shadowing. I'd say file an enhancement request to make such code a compile error. T -- Ph.D. = Permanent head Damage
Jan 09 2017
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/09/2017 11:23 AM, H. S. Teoh via Digitalmars-d-learn wrote:
 On Mon, Jan 09, 2017 at 11:18:02AM -0800, Ali Çehreli via 
Digitalmars-d-learn wrote:
 // Some function of the API that takes a delegate
 void call(void delegate(MyType) dlg) {
That's a delegate type.
     call(delegate void(MyType) {
Are you sure this isn't spelt `void delegate(MyType)`?
Those two syntaxes always confuse me and I'm never sure without trying which one to use when. :) However, the code is correct in this case because that's a delegate instance. Ali
Jan 09 2017
parent Jacob Carlborg <doob me.com> writes:
On 2017-01-09 20:51, Ali Çehreli wrote:

 Those two syntaxes always confuse me and I'm never sure without trying
 which one to use when. :) However, the code is correct in this case
 because that's a delegate instance.
I agree. When it comes to declaring a delegate type, i.e. a variable or function parameter I always think that the syntax is the same as the declaring a regular function, but replacing the function name with "delegate". -- /Jacob Carlborg
Jan 09 2017
prev sibling next sibling parent Jonathan M Davis via Digitalmars-d-learn writes:
On Monday, January 09, 2017 11:18:02 Ali Çehreli via Digitalmars-d-learn 
wrote:
 This is something that surprised me in a friend's code.

 (A "friend", hmmm? No, really, it wasn't me! :) )

 // Some type of the API
 struct MyType {
      int i;
 }

 // Some function of the API that takes a delegate
 void call(void delegate(MyType) dlg) {
      dlg(MyType(42));
 }

 void main() {
      /* The programmer simply copied the delegate definition from
       * the function and used it as-is when passing a lambda: */
      call(delegate void(MyType) {
              /* WAT? Does the following really compile? After all,
               * MyType.i is NOT a static member! */
              if (MyType.i == 42) {
                  // ...
              }
          });
 }

 I was surprised to see it compiled and worked but of course MyType at
 the lambda definition inside main() is not a type name, rather the
 parameter name. Surprising, but I think this is according to spec.
Well, stuff inside a function is quite free to shadow stuff from outside of it. AFAIK, the only shadowing that's prevented is declarations in a function shadowing other declarations in a function. - Jonathan M Davis
Jan 09 2017
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2017-01-09 20:18, Ali Çehreli wrote:
 This is something that surprised me in a friend's code.

 (A "friend", hmmm? No, really, it wasn't me! :) )

 // Some type of the API
 struct MyType {
     int i;
 }

 // Some function of the API that takes a delegate
 void call(void delegate(MyType) dlg) {
     dlg(MyType(42));
 }

 void main() {
     /* The programmer simply copied the delegate definition from
      * the function and used it as-is when passing a lambda: */
     call(delegate void(MyType) {
             /* WAT? Does the following really compile? After all,
              * MyType.i is NOT a static member! */
             if (MyType.i == 42) {
                 // ...
             }
         });
 }

 I was surprised to see it compiled and worked but of course MyType at
 the lambda definition inside main() is not a type name, rather the
 parameter name. Surprising, but I think this is according to spec.
I know this has come up before, and reported as a bug, at least once. Might have been me :). What's confusing is that using a type that has a keyword will make the parameter unnamed of the specified type, just as a regular function: auto a = (int) => 3; // works, a lambda taking an int, no parameter name auto b = (Foo) => 3; // error, cannot infer type of template lambda alias b = (Foo) => 3; // works, since this is an alias, Foo is the parameter name of an unknown type -- /Jacob Carlborg
Jan 09 2017