Compile-time Interfaces

Jacob Carlborg doob at me.com
Sun Nov 27 03:07:03 PST 2011


On 2011-11-27 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 have always wonder why D doesn't have any kind of interface type that 
can be used for this purpose, I like it.

You could always force this:

void foo (T : Range) (T t) {}

Then one will know it's a template.

-- 
/Jacob Carlborg


More information about the Digitalmars-d mailing list