TDPL: Overloading template functions

Andrej Mitrovic andrej.mitrovich at gmail.com
Fri Jul 30 15:58:50 PDT 2010


On Sat, Jul 31, 2010 at 12:04 AM, Philippe Sigaud <philippe.sigaud at gmail.com
> wrote:

> First,  trying a copy-paste of your code gives me an error in object.di
> (DMD 2.047 on Windows)
>
>
Yes, I get the same error.


> C:\dmd\windows\bin\..\..\src\druntime\import\object.di|487|Error:
> incompatible types for ((a) != (a2[i])): 'string' and 'immutable(char)'|
> ||=== Build finished: 1 errors, 0 warnings ===|
>
> And Code::Blocks jumps me to object.di:
>
> bool _ArrayEq(T1, T2)(T1[] a1, T2[] a2)
> {
>     if (a1.length != a2.length)
>  return false;
>     foreach(i, a; a1)
>     { if (a != a2[i]) // <-- line 487. Uh oh, trying to compare strings
> and chars
>     return false;
>     }
>     return true;
> }
>
> I had to modify it:
>
> bool _ArrayEq(T1, T2)(T1[] a1, T2[] a2)
>  if (is(typeof(T1.init != T2.init))) // Are T1 and T2 comparable? If not,
> do not bother to compile
> {
>    if (a1.length != a2.length) return false;
>     foreach(i, a; a1)
>     { if (a != a2[i])
>         return false;
>     }
>     return true;
> }
>
> Another possibility would have it return false, but in that case, array
> comparisons always compile and we lose the ability to use them as test for
> instantiating a template.
>
> I guess _ArrayEq is some internal called by the constraint, while doing the
> comparison. Saving object.di and recompiling everything allows the templates
> constraints to function and gives me a call to the first find.
>
> Without the '&& false', it still calls the first find... because it still
> cannot instantiate the second template:
>
> The first find can be instantiated with T = immutable(char)[] and E =
> immutable(char)[], there is nothing stopping it: T and E are the same type,
> so they are trivially comparable. "two" is a valid target value for ["one",
> "two"].
> The second find would have T1 = immutable(char)[] and T2 = immutable(char)
> and those do not compare.
>
>
> testing it, find("one two three", "two") correctly calls the second version
> and returns "two three".
>
>
>
So, maybe you just found a bug in object.di._ArrayEq. I'll post on the main
> list. Anyway, for me, it seems to work, if I understand correctly what
> you're doing.
>
>
What I am trying to do is to get the code sample from TDPL working. I tried
to constraint the second template so it never gets called with:

    assert(find(s, "two") == ["two"]);

because this was in the unittest right under the first template, and I
assumed it should work only with the first template. On TDPL page 143 it
states that there is no ambiguity between the two templates, so this entire
following code should work (could you please try this out with your new
object.di if you have any time?). I hope Andrei won't mind for pasting this
here:


import std.stdio;

void main()
{
}

T[] find(T, E)(T[] haystack, E needle)
    if (is(typeof(haystack[0] != needle) == bool))
{
    while (haystack.length > 0 && haystack[0] != needle) {
        haystack = haystack[1 .. $];
    }
    return haystack;
}

unittest {
    double[] d = [1.5, 2.4];
    assert(find(d, 1.0) == null);
    assert(find(d, 1.5) == d);
    string[] s = ["one", "two"];
    assert(find(s, "two") == ["two"]);
}


T1[] find(T1, T2)(T1[] longer, T2[] shorter)
    if (is(typeof(longer[0 .. 1] == shorter) : bool))
{
    while (longer.length >= shorter.length) {
        if (longer[0 .. shorter.length] == shorter)
            break;
        longer = longer[1 .. $];
    }
    return longer;
}

unittest {
    double[] d1 = [6.0, 1.5, 2.4, 3];
    float[] d2 = [1.5, 2.4];
    assert(find(d1, d2) == d1[1 .. $]);
}



> Btw, if you find yourself using the same constraint regularly, you can
> abstract it away in another template that returns (er, becomes, rather) a
> boolean:
>
> template areComparable(T1, T2)
> {
>    enum bool areComparable = is(typeof(T1.init == T2.init)); // eponymous
> template trick
> }
>
> And then:
>
> T[] find(T, E)(T[] haystack, E needle)
>     if (areComparable!(T, E))
> {
> }
>
>
> T[] find(T, E)(T[] longer, E[] shorter)
>     if (areComparable!(T, E))
>
> {
> }
>
> Which makes for cleaner code. I renamed T1 and T2 to T and E, so showcase
> the difference between the two.
>
>
> Philippe
>
>
I was actually thinking about ways of simplifying the constraint definitions
with some helper functions. That's a pretty cool trick, thanks!
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20100731/03a61bcf/attachment.html>


More information about the Digitalmars-d mailing list