Thread overview
D: Unexpected output when using a delegate and EnumMembers
Jun 19, 2012
Travis Gockel
Jun 19, 2012
Artur Skawina
Jun 19, 2012
Timon Gehr
Jun 19, 2012
Artur Skawina
Jun 19, 2012
Timon Gehr
Jun 19, 2012
Travis Gockel
June 19, 2012
I have some rather odd behavior in my D program that I've narrowed down to this:

    import std.algorithm;
    import std.stdio;
    import std.traits;

    enum E { a, b, c };

    struct S { E e; };

    void main()
    {
        immutable(S)[] source = [ S(E.a), S(E.a), S(E.b) ];
        foreach (e; EnumMembers!E)
        {
            size_t c = count!(x => x.e == e)(source);
            writeln(e, " -> ", c);
        }
    }

I would expect the output of this program to be something along the lines of:

    a -> 2
    b -> 1
    c -> 0

But the actual result is:

    a -> 2
    b -> 2
    c -> 2

Curiously, changing the for loop to foreach (e; [ E.a, E.b, E.c ]) produces my expected output. Using foreach (e; [ EnumMembers!E ]) also produces my expected result, so clearly my use of the range from EnumMemebers is the problem here...I just don't know why.

By moving the count call to a separate function:

    size_t counte(Range)(E e, Range src)
    {
        return count!(x => x.e == e)(src);
    }

and changing c's initialization to size_t c = counte(e, source);, the program works as I would expect.

I am clearly doing something wrong, but I have no idea what and would appreciate some insight.

My compiler is DMD64 D Compiler v2.059 on Linux.
June 19, 2012
On 06/19/12 16:44, Travis Gockel wrote:
>     import std.algorithm;
>     import std.stdio;
>     import std.traits;
> 
>     enum E { a, b, c };
> 
>     struct S { E e; };
> 
>     void main()
>     {
>         immutable(S)[] source = [ S(E.a), S(E.a), S(E.b) ];
>         foreach (e; EnumMembers!E)
>         {
>             size_t c = count!(x => x.e == e)(source);
>             writeln(e, " -> ", c);
>         }
>     }
> 
> I would expect the output of this program to be something along the lines of:
> 
>     a -> 2
>     b -> 1
>     c -> 0
> 
> But the actual result is:
> 
>     a -> 2
>     b -> 2
>     c -> 2
> 
> Curiously, changing the for loop to foreach (e; [ E.a, E.b, E.c ]) produces my expected output. Using foreach (e; [ EnumMembers!E ]) also produces my expected result, so clearly my use of the range from EnumMemebers is the problem here...I just don't know why.
> 
> By moving the count call to a separate function:
> 
>     size_t counte(Range)(E e, Range src)
>     {
>         return count!(x => x.e == e)(src);
>     }
> 
> and changing c's initialization to size_t c = counte(e, source);, the program works as I would expect.
> 
> I am clearly doing something wrong, but I have no idea what and would appreciate some insight.

Yes, it can be surprising, but I'm not convinced it's actually wrong behavior (the bug is http://d.puremagic.com/issues/show_bug.cgi?id=2043)

Just do this:

   size_t c = count!(function(x, e) { return x.e == e;} )(source, e);

and it will work. [1]

artur

[1] I don't do that new kinky lambda syntax, sorry. ;)
June 19, 2012
On 06/19/2012 04:44 PM, Travis Gockel wrote:
>
> I am clearly doing something wrong,

You are not.

> but I have no idea what and would
> appreciate some insight.
>

You have found a bug in DMD.

Reduced test case that should compile:

template Seq(T...){alias T Seq;}
auto exec(alias a)(){return a();}
void main(){
    foreach(e; Seq!(0, 1))
        static assert(exec!(()=>e)()==e);
}

You can report the bug here: http://d.puremagic.com/issues/

The 'exec' template is instantiated only once instead of two times.
June 19, 2012
On 06/19/2012 05:08 PM, Artur Skawina wrote:
>
> Yes, it can be surprising, but I'm not convinced it's actually wrong
> behavior (the bug is http://d.puremagic.com/issues/show_bug.cgi?id=2043)
>

It is not this bug. (And what is listed there is clearly wrong
behaviour, because it can be used to break the type system.)

> Just do this:
>
>     size_t c = count!(function(x, e) { return x.e == e;} )(source, e);
>
> and it will work. [1]
>
> artur
>
> [1] I don't do that new kinky lambda syntax, sorry. ;)

Your embarrassment about this issue is justifiable.
June 19, 2012
== Quote from Timon Gehr (timon.gehr@gmx.ch)'s article
> You can report the bug here: http://d.puremagic.com/issues/
> The 'exec' template is instantiated only once instead of two times.

Reported: http://d.puremagic.com/issues/show_bug.cgi?id=8267
June 19, 2012
On 06/19/12 17:32, Timon Gehr wrote:
> On 06/19/2012 05:08 PM, Artur Skawina wrote:
>>
>> Yes, it can be surprising, but I'm not convinced it's actually wrong behavior (the bug is http://d.puremagic.com/issues/show_bug.cgi?id=2043)
>>
> 
> It is not this bug. (And what is listed there is clearly wrong behaviour, because it can be used to break the type system.)

It's not that simple. I remember considering the alternatives when I originally ran into this, and they have problems too.

The "static foreach" case may be special, possibly.


>> [1] I don't do that new kinky lambda syntax, sorry. ;)
> 
> Your embarrassment about this issue is justifiable.
> 
I'm proud of it. ;) But maybe it has something to do with the fact that my compiler doesn't support them...

artur