On Saturday, 17 May 2014 at 00:42:35 UTC, Phil Lavoie wrote:
On Friday, 16 May 2014 at 23:14:13 UTC, Idan Arye wrote:
On Friday, 16 May 2014 at 20:31:40 UTC, Phil Lavoie wrote:
The main problem is that `myTemplateFunction`'s signature makes it look like it's a concrete function, when in fact it's a template.

True. To me that is not a big issue though. It can lead to some surprises I see your point but I would be ok with that.

When I see such a signature as `void myTemplateFunction( InputRange!int r ) {` I'm automatically assuming I can do things like `void function(InputRange!int) foo = &myTemplateFunction;`, but in our case I can't since it's a template. Also, since it's a template, certain instantiations might cause it to crash. We have come to expect such things from templates, but here we don't expect a template.

Also, I'm not very familiar with the internals of the parser, but I'm pretty sure that not being able to tell if a declaration is a template or not based on it's signature will cause a serious headache...


Another problem is that we now have to have an argument if we want to pass a template parameter, which is a serious limitation.

Not sure I get what you mean. I didn't mean for the old syntax to be abandonned if that makes sense, just to add some sugar to the existing one.

    void myTemplateFunction(){
        InputRange!int r;
        r.doSomething();
    }

When you call `myTemplateFunction`, how do you tell it which concrete type that implements `InputRange` to use?

Also:

void myTemplateFunction(InputRange!int a, InputRange!int b){...

Must `a` and `b` share the same type, or can they have two different types as long as the two types fulfill `InputRange!int`?


How about if instead these constraint could be used in `is` expressions like type specializations?

   void myTemplateFunction(T)(T r) if(is(T : InputRange!int)) {
     foreach(elt; r) { ... }
   }

True, the syntax is less elegant, but it's more flexible, you can easily tell that it's a template, and you can use the same syntax in static branching.


It's interesting. But would it warrant a change from the usual syntax, which would probably be:

void myTemplateFunction(T)(T r) if( isInputRange!(T, int)) {
  foreach(elt; r) { ... }
}

Not as nearly as different from your proposal!

At any rate, this syntax will not be used THAT much. We can create a wrapper template in Phobos that encapsulates any type that follows a constraint to create a concrete type that delegates ONLY the constraints' methods to the real struct/object. That way we can create concrete functions:

void myTemplateFunction(InterfaceTemplateWrapper!(InputRange!int) r) {...

That way we can make sure `myTemplateFunction` doesn't use any other methods of `r` that don't appear in `InputRange!int` but happen to be in the all concrete types we have send to the function.


Hmm do you mean like a struct "implementing" an interface?

struct MagicRange: InputRange {
...
}

Where it's not an actual interface but the compiler would check it against the constraint(s). Which would be nice to make sure that a type follows a given interface, although, as soon as it is used as an InputRange you would know.

Assuming it is used as an InputRange at some template that gets instantiated. If you are writing a library there is a chance that a lot of your code is templates that only get instantiated when the library is used.

Yes, you should have unit tests, but having the type system check things is better.


BTW - I'm don't think we need a new keyword for this - we can use `interface template` instead.

Love it! Would "template interface" make more sense?

In `mixin template` the word "template" comes second. Consistency is always good, and I see no benefit from breaking it here.

Reply via email to