www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 3217] New: std.functional.binaryFunImpl doesn't support UDT with string functions , therefore neither does many std.algorithm functions

reply d-bugmail puremagic.com writes:
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: -------
Jul 30 2009
next sibling parent d-bugmail puremagic.com writes:
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: -------
Jul 30 2009
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=3217


Andrei Alexandrescu <andrei metalanguage.com> changed:

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





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: -------
Aug 28 2009