Thread overview
[Issue 3217] New: std.functional.binaryFunImpl doesn't support UDT with string functions , therefore neither does many std.algorithm functions
Jul 30, 2009
sandford@jhu.edu
July 30, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3217

           Summary: std.functional.binaryFunImpl doesn't support UDT with
                    string functions , therefore neither does many
                    std.algorithm functions
           Product: D
           Version: 2.031
          Platform: x86
        OS/Version: Windows
            Status: NEW
          Keywords: patch
          Severity: major
          Priority: P2
         Component: Phobos
        AssignedTo: nobody@puremagic.com
        ReportedBy: sandford@jhu.edu


std.functional.binaryFunImpl doesn't support user defined data types. As this is used by many functions in std.algorithm, it represents a major loss of function.

import std.functional;
import std.algorithm;

struct foo{
    foo opAdd(foo f) {
        return this;
    }
}

void main(char[][] args) {
    foo[] foos = new foo[5];
    //    binaryFunImpl!("a + b","a","b").Body!(foo,foo);
    //    writeln( reduce!"a + b"(foos) );
    // C:\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 foo and b of type foo."|

    // This is the failed static if
    //  static if (__traits(compiles, mixin(testAsExpression)))
    //  and testAsExpression equals
    // {foo a; foo b; return (a + b);}()

    static assert(__traits(compiles, mixin("{foo a; foo b; return (a +
b);}()")) == true );

    static if (__traits(compiles, mixin("{foo a; foo b; return (a + b);}()")))
// okay
        static assert(true);
    else
        static assert(false);
    return;
}

I tried replacing ElementType1.stringof with "ElementType1", ElementType2.stringof with , "ElementType2" which seemed to work:

The patch in brief:
            enum testAsExpression = "{ ElementType1 "
                ~parm1Name~"; ElementType2 "
                ~parm2Name~"; return ("~fun~");}()";

The patch in full:

template binaryFunImpl(alias fun,
        string parm1Name, string parm2Name)
{
    static if (is(typeof(fun) : string))
    {
        template Body(ElementType1, ElementType2)
        {
            enum testAsExpression = "{ ElementType1 "
                ~parm1Name~"; ElementType2 "
                ~parm2Name~"; return ("~fun~");}()";
            enum testAsStmts = "{ "~ElementType1.stringof~" "
                ~parm1Name~"; "~ElementType2.stringof~" "
                ~parm2Name~"; "~fun~"}()";
            static if (__traits(compiles, mixin(testAsExpression)))
            {
                enum string code = "return (" ~ fun ~ ");";
                alias typeof(mixin(testAsExpression)) ReturnType;
            }
            // else static if (__traits(compiles, mixin(testAsStmts)))
            // {
            //     enum string code = fun;
            //     alias typeof(mixin(testAsStmts)) ReturnType;
            // }
            else
            {
                // Credit for this idea goes to Don Clugston
                enum string msg =
                    "Bad binary function q{" ~ fun ~ "}."
                    ~" You need to use a valid D expression using symbols "
                    ~parm1Name~" of type "~ElementType1.stringof~" and "
                    ~parm2Name~" of type "~ElementType2.stringof~"."
                    ~(fun.length && fun[$ - 1] == ';'
                            ? " The trailing semicolon is _not_ needed."
                            : "")
                    ~(fun.length && fun[$ - 1] == '}'
                            ? " The trailing bracket is mistaken."
                            : "");
                static assert(false, msg);
            }
        }
        Body!(ElementType1, ElementType2).ReturnType
            result(ElementType1, ElementType2)
            (ElementType1 __a, ElementType2 __b)
        {
            mixin("alias __a "~parm1Name~";");
            mixin("alias __b "~parm2Name~";");
            mixin(Body!(ElementType1, ElementType2).code);
        }
    }
    else
    {
        alias fun result;
    }
    // static if (is(typeof(comp) : string))
    // {
    //     // @@@BUG1816@@@: typeof(mixin(comp)) should work
    //     typeof({
    //                 static ElementType1 a;
    //                 static ElementType2 b;
    //                 return mixin(comp);
    //             }())
    //         binaryFun(ElementType1, ElementType2)
    //         (ElementType1 a, ElementType2 b)
    //     {
    //         return mixin(comp);
    //     }
    // }
    // else
    // {
    //     alias comp binaryFun;
    // }
}

The patch passes the unittests in functional.d. i.e.
unittest
{
    alias binaryFun!(q{a < b}) less;
    assert(less(1, 2) && !less(2, 1));
    assert(less("1", "2") && !less("2", "1"));

    static int f1(int a, string b) { return a + 1; }
    static assert(is(typeof(binaryFun!(f1)(1, "2")) == int));
    assert(binaryFun!(f1)(41, "a") == 42);
    string f2(int a, string b) { return b ~ "2"; }
    static assert(is(typeof(binaryFun!(f2)(1, "1")) == string));
    assert(binaryFun!(f2)(1, "4") == "42");
    assert(binaryFun!("a + b")(41, 1) == 42);
    //@@BUG
    //assert(binaryFun!("return a + b;")(41, 1) == 42);
}

As a note, unaryFunImpl uses "{ ElementType " as well, and it looks like testAsStmts is dead code in each (grepping the source tree only turned up he definition in functional.d). As testAsStmts also uses .stringof, which seems to be wrong, I'd recommend either fixing or removing it in both templates.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 30, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3217


Andrei Alexandrescu <andrei@metalanguage.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |ASSIGNED
                 CC|                            |andrei@metalanguage.com
         AssignedTo|nobody@puremagic.com        |andrei@metalanguage.com




-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
August 28, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3217


Andrei Alexandrescu <andrei@metalanguage.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|ASSIGNED                    |RESOLVED
         Resolution|                            |FIXED




--- Comment #1 from Andrei Alexandrescu <andrei@metalanguage.com>  2009-08-28 09:21:34 PDT ---
Ok, thanks. I've integrated the patch. As for testAsStmts, it used to crash the compiler so I'm leaving it commented (albeit corrected) for now.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------