Thread overview
setIntersection of struct range
Aug 11, 2009
Jesse Phillips
Aug 12, 2009
Jesse Phillips
Aug 12, 2009
Jesse Phillips
Aug 12, 2009
Sergey Gromov
August 11, 2009
I am trying to obtain a rang that is the intersection of two other ranges. To do this I am using the _setIntersection()_ function.

    import std.algorithm;
    import std.stdio;

    struct S {
	string label;
    }

    void main() {
        auto s1 = new S[2];
        auto s2 = new S[2];

        s1[0].label = "fish";
        s1[1].label = "bar";
        s2[0].label = "foo";
        s2[1].label = "fish";

        foreach(str; setIntersection(s1,s2))
            writeln(str);
    }

The code above generates this error:

     C:\opt\dmd\windows\bin\..\..\src\phobos\std\functional.d(191):
          Error: static assert  "Bad binary function q{a < b}.
             You need to use a valid D expression using symbols a of type S and b of type S."

So I attempted an intersection of string arrays, and received a different error. I'm not sure if I am at fault or the compiler. Shouldn't these work?

    import std.algorithm;
    import std.stdio;
    import std.array;

    struct S {
        string label;
    }

    void main() {
        auto s1 = ["fish", "bar"];
        auto s2 = ["foo", "fish"];

        foreach(str; setIntersection(s1,s2))
            writeln(str);
    }

Which ended up with:

    test.d(13): Error: template std.algorithm.setIntersection(alias less = "a < b",Rs...)
        if (allSatisfy!(isInputRange,Rs)) does not match any function template declaration
    test.d(13): Error: template std.algorithm.setIntersection(alias less = "a < b",Rs...)
        if (allSatisfy!(isInputRange,Rs)) cannot deduce template function from
        argument types !()(immutable(char)[][2u],immutable(char)[][2u])
    test.d(13): Error: foreach: int is not an aggregate type
August 12, 2009
On Tue, 11 Aug 2009 19:35:40 -0400, Jesse Phillips <jessekphillips+d@gmail.com> wrote:

> I am trying to obtain a rang that is the intersection of two other ranges. To do this I am using the _setIntersection()_ function.
>
>     import std.algorithm;
>     import std.stdio;
>
>     struct S {
> 	string label;
>     }
>
>     void main() {
>         auto s1 = new S[2];
>         auto s2 = new S[2];
>
>         s1[0].label = "fish";
>         s1[1].label = "bar";
>         s2[0].label = "foo";
>         s2[1].label = "fish";
>
>         foreach(str; setIntersection(s1,s2))
>             writeln(str);
>     }
>
> The code above generates this error:
>
>      C:\opt\dmd\windows\bin\..\..\src\phobos\std\functional.d(191):
>           Error: static assert  "Bad binary function q{a < b}.
>              You need to use a valid D expression using symbols a of type S and b of type S."

You did not define a way to compare two S structs.  Try redefining S like this:

struct S {
  string label;
  int opCmp(ref const S s2) const {
     if(label < s2.label)
       return -1;
     if(label > s2.label)
       return 1;
     return 0;
  }
}

>
> So I attempted an intersection of string arrays, and received a different error. I'm not sure if I am at fault or the compiler. Shouldn't these work?
>
>     import std.algorithm;
>     import std.stdio;
>     import std.array;
>
>     struct S {
>         string label;
>     }
>
>     void main() {
>         auto s1 = ["fish", "bar"];
>         auto s2 = ["foo", "fish"];
>
>         foreach(str; setIntersection(s1,s2))
>             writeln(str);
>     }
>
> Which ended up with:
>
>     test.d(13): Error: template std.algorithm.setIntersection(alias less = "a < b",Rs...)
>         if (allSatisfy!(isInputRange,Rs)) does not match any function template declaration
>     test.d(13): Error: template std.algorithm.setIntersection(alias less = "a < b",Rs...)
>         if (allSatisfy!(isInputRange,Rs)) cannot deduce template function from
>         argument types !()(immutable(char)[][2u],immutable(char)[][2u])

I think it's expecting dynamc arrays, not static ones.  Auto is making them static.

Try explicitly defining s1 and s2 as string[] or slice the literal, typing them as dynamic arrays like this:

auto s1 = ["fish", "bar"][];
auto s2 = ["foo", "fish"][];

>     test.d(13): Error: foreach: int is not an aggregate type

This is a dummy error because it couldn't figure out the type of setIntersection, so it just assumes int (a quirk of dmd).

-Steve
August 12, 2009
On Wed, 12 Aug 2009 11:25:10 -0400, Steven Schveighoffer <schveiguy@yahoo.com> wrote:

>
> I think it's expecting dynamc arrays, not static ones.  Auto is making them static.

BTW, this probably should not be true, I would guess that static arrays should be intersectable, of course the return type would have to be a dynamic array.  When will static arrays be first class? *sigh*

-Steve
August 12, 2009
Steven Schveighoffer Wrote:

> You did not define a way to compare two S structs.  Try redefining S like this:
> 
> struct S {
>    string label;
>    int opCmp(ref const S s2) const {
>       if(label < s2.label)
>         return -1;
>       if(label > s2.label)
>         return 1;
>       return 0;
>    }
> }

You know, I didn't think about this because struct arrays are sorted by the first element if you do array.sort. But this does make the error a little more clear.
August 12, 2009
Jesse Phillips Wrote:

> Steven Schveighoffer Wrote:
> 
> > You did not define a way to compare two S structs.  Try redefining S like this:
> > 
> > struct S {
> >    string label;
> >    int opCmp(ref const S s2) const {
> >       if(label < s2.label)
> >         return -1;
> >       if(label > s2.label)
> >         return 1;
> >       return 0;
> >    }
> > }
> 
> You know, I didn't think about this because struct arrays are sorted by the first element if you do array.sort. But this does make the error a little more clear.

Got around to trying this, but it didn't fix the problem.
August 12, 2009
Tue, 11 Aug 2009 19:35:40 -0400, Jesse Phillips wrote:

> I am trying to obtain a rang that is the intersection of two other ranges. To do this I am using the _setIntersection()_ function.
> 
>     import std.algorithm;
>     import std.stdio;
> 
>     struct S {
> 	string label;
>     }
> 
>     void main() {
>         auto s1 = new S[2];
>         auto s2 = new S[2];
> 
>         s1[0].label = "fish";
>         s1[1].label = "bar";
>         s2[0].label = "foo";
>         s2[1].label = "fish";
> 
>         foreach(str; setIntersection(s1,s2))
>             writeln(str);
>     }
> 
> The code above generates this error:
> 
>      C:\opt\dmd\windows\bin\..\..\src\phobos\std\functional.d(191):
>           Error: static assert  "Bad binary function q{a < b}.
>              You need to use a valid D expression using symbols a of type S and b of type S."

Looks like a compiler bug/feature to me.  The following is a reduced test case:

import std.functional;

struct S {
    string label;
}

void main() {
    auto f1 = &binaryFunImpl!("a < b", "a", "b").result!(int, int);
    auto f2 = &binaryFunImpl!("a.label < b.label", "a", "b").result!(S, S);
}

Compiled with dmd2 test.d:

C:\opt\dmd.2.031\windows\bin\..\..\src\phobos\std\functional.d(191):
Error: static assert  "Bad binary function q{a.label < b.label}. You
need to use a valid D expression using symbols a of ty
pe S and b of type S."

Note that int,int passes while S,S fails.