Christopher Wright wrote:
Andrei has put up a few enhancement requests in the bugzilla:
http://d.puremagic.com/issues/show_bug.cgi?id=2784
http://d.puremagic.com/issues/show_bug.cgi?id=2785
http://d.puremagic.com/issues/show_bug.cgi?id=2786

Yah, this too:

http://d.puremagic.com/issues/show_bug.cgi?id=2050

These are intended to change interfaces from being solely a tool of polymorphism into a way of specifying type constraints. The additions recommended can only be used at compile time (constructors, static functions, and nested types).

Yah. Let me add that I haven't thought the changes through, but I posted them to foster discussion, which is happening (thanks!).

I grant that it would be quicker and clearer to write:
interface Foo
{
   static void stuff();
   this (int);
}
template Template(Arg : Foo) {}

than to write:
template Template(Arg) if (is (typeof (new Arg(0)) && isStaticFunction!(Arg, "stuff")) {}

Yah. Let me add that after the OOP meteoric rise in the past years, many of us can instantly figure how the former works, whereas the latter is thoroughly obscure.

Let me also pull the definition of a couple of range types in std.range (by the way, I should commit the new Phobos today):

template isInputRange(R)
{
    enum bool isInputRange = is(typeof(
    {
        R r;             // can define a range object
        if (r.empty) {}  // can test for empty
        r.next;          // can invoke next
        auto h = r.head; // can get the head of the range
    }()));
}

I wrote it as clearly as I could, and it doesn't quite look that pretty. I didn't even know the typeof({ ... }()) trick is possible; I saw it somewhere on this group, and took to it. Otherwise the code would have been even more convoluted (along the lines of what you wrote, just more of it). Furthermore, if a type is not a range, there's no simple way to output an error message telling exactly which test if failed. The only test possible is e.g. isInputRange!MyType.

I think we can't quite be happy that this is D's offering with regard to concepts. On the other hand, we'd like to avoid the aggravation of C++ concepts, which, in my humble opinion, have a very low power/complexity ratio. So I wanted to look at how interfaces can be reasonably extended into expressing concepts while still being strongly integrated with their classic runtime polymorphic role.

However, I'm not sure whether this would be used much at all, and it deserves some discussion.

One detail of #2785 seems problematic:
interface Foo
{
    extern void bar(int, Foo, double);
}

meaning that a non-member function bar should exist that accepts an int, *the implementor of Foo*, and a double.

This is a huge and silent divergence from the standard meaning of using the interface name; it would allow:
class C : Foo
{
    static void bar(int, C, double);
}

and disallow:
class C : Foo
{
    static void bar(int, Foo, double);
}

Thoughts? Any concerns that I have not raised? I don't do sufficient metaprogramming to find any of this useful, I admit.

I thought of that, too. One option is to parameterize Foo with its subtype's name:

interface Foo(X)
{
    extern void bar(int, X, double);
}

Then you'd require C : Foo!C and so on. I'm not sure how important this detail is, but it is worth thinking of.

Another issue is that constructors in a struct are one thing, whereas in a class they are quite a different thing (references of a class can be copied!)


Andrei

Reply via email to