On Sunday, 16 May 2021 at 09:55:31 UTC, Chris Piker wrote:
Maybe that's eminently reasonable to those with deep knowledge, but it seems crazy to a new D programmer. It breaks a general assumption about programming when copying and pasting a definition yields two things that aren't the same type. (except in rare cases like SQL where null != null.)

It's due to a quirk with passing lambdas as template arguments. Each lambda is actually separated into its own function.

It's kind of hard to explain, but examine this code:

```d
// runnable version: https://run.dlang.io/is/NbU3iT
struct S(alias Func)
{
    pragma(msg, __traits(identifier, Func));
}

int func(int a)
{
    return a*2;
}

void main()
{
    auto a = S!(a => a*2)();
    auto b = S!(a => a*2)();

    // Comment above. Then uncomment below for a working version.
    /*
    auto a = S!func();
    auto b = S!func();
    */

    pragma(msg, typeof(a));
    pragma(msg, typeof(b));
    a = b;
}
```

In its given state, this is the following output:

```
__lambda1
__lambda3
S!((a) => a * 2)
S!((a) => a * 2)
onlineapp.d(24): Error: cannot implicitly convert expression `b` of type `onlineapp.main.S!((a) => a * 2)` to `onlineapp.main.S!((a) => a * 2)`
```

So while `typeof(a)` and `typeof(b)` **look** like they are the same, in actuality you can see that `auto a` uses `__lambda1`, whereas `auto b` uses `__lambda3`.

This means that, even though visually they should be equal, they are in fact two entirely separate types.

So if you had a nested `Result` struct, it'd look more like `S!__lambda1.Result` and `S!__lambda3.Result`, instead of just `S!IDENTICAL_LAMBDA.Result`.

Confusing, I know...

So if we change this to using a non-lambda function (doing the commenting/uncommenting as mentioned in the code) then we get successful output:

```
func
S!(func)
S!(func)
```

p.s. I love that you can debug D within D.

Reply via email to