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.