On 27-11-2011 01:40, Kapps wrote:
One of the great things about D is the ability to do so much work at compile-time, including static verification. An example is the amount of constraints available for templates, static ifs, etc. But at some point, it starts getting very problematic to just figure out what something does, and what something can do. An example for this, is ranges. They can be very confusing, and you don't know what they can do without actually going and looking up the exact definition of them. Even then, you have to know that the templated type a function expects is a range. Again, very confusing, and arguably messy. Finally, even now that you know what methods you can call on this mysterious type T, and you see that there's a clause isInputRange!(T) on the method, your IDE still has no clue about any of these things making it impossible to have semi-decent code completion for that type.Which brings in, compile-time interfaces. It seems like a natural thing to include when you have the above tools. Instead of having a method such as: auto DoSomething(T)(T Data) if(isInputRange!(T)) { } You could simply do: auto DoSomething(Range Data) { } where Range is defined as: enum interface Range { void popFront() const; @property bool empty() const; @property auto front(); } Much nicer than this very confusing looking statement (taken from std.range): template isInputRange(R) { enum bool isInputRange = is(typeof( { R r; // can define a range object if (r.empty) {} // can test for empty r.popFront(); // can invoke popFront() auto h = r.front; // can get the front of the range }())); } And then instead of returning auto, you could return Range if you wanted to, or OutputRange, etc. This gives much more info by just looking at the signature of the method, as opposed to comb through the documentation to find out what this mysterious type is that it returns. Another useful thing is that new types could now actually have it be statically verified that they implement this feature: struct MyRange(T) { T popFront() const { } @property bool empty() const { } @property ref T front() { } } When you try to use this in a method that takes in a type T where isInputRange!(T), you would get a confusing message saying no suitable overloads found. If you had, this however: struct MyRange(T) : (static|enum)? Range { T popFront() const { } @property bool empty() const { } @property ref T front() { } } You would see a message saying that it can't implement Range because popFront returns T instead of void. Not only that, but a good IDE will also offer to implement the Range signatures for you, like Visual Studio does for C#. The main issue I can think of is when a method takes in multiple different types that implement the same static interface. An example: Range Zip(Range First, Range Second); Would First/Second be the same type? Does it matter? Should the compiler handle it? What about the return type? An alternate way though would just be to (when there are multiple types of the same interface) force the use of: Range Zip(R1 : Range, R2 : Range)(R1 First, R2) Second; An IDE will still know that these are ranges. You still get the readability of it. You still get all the benefits of the ranges. You just have to make Zip a template method anyways. The other issue I can think of is that this could potentially make someone believe that methods that take in / return a Range aren't template methods when they actually are. Of course, in order for that to matter, they have to realize in the first place that a template method creates multiple instances of the method while caring about the overhead that creates. Overall though, I think that this would be a huge benefit to D's compile time capability (not to mention learning ranges), while incurring no run-time cost. It also makes it much nicer when your IDE now knows what the types you're working with are. There are already IDEs that can take advantage of the above benefits, and only more will come. Plus, it's much much nicer to just be able to look at the interface rather than figuring out the documentation for, say, a range (and many editors/ides will offer a go-to-definition to do this for you). Template types / figuring out what they are is the messiest thing in D at the moment (IMO), and this would be a nice way of solving it for many situations. Thoughts?
I think 'static interface' or 'template interface' or something like that would make more sense. 'enum interface' just doesn't really make sense in this context. Other than that, seems like a reasonable idea to me.
- Alex
