On Thursday, 30 January 2020 at 14:22:11 UTC, Paul Backus wrote:
On Thursday, 30 January 2020 at 14:10:38 UTC, ShadoLight wrote:
...but in the 'classical' default template style, so I would
have thought the
template_name!(compile_time_args).function_name(run_time_args)
style would still work, even if the template and function
names are identical.
If this is in fact now the intended behavior, then there are
some places where the documentation are in error.
[1]: https://dlang.org/spec/template.html#variadic-templates
Eponymous templates are documented here:
https://dlang.org/spec/template.html#implicit_template_properties
This specific behavior is documented in the first paragraph
below that heading, which reads as follows:
If a template contains members whose name is the same as the
template identifier and if the type or the parameters type of
these members include at least all the template parameters
then these members are assumed to be referred to in a template
instantiation
Yes, the behavior is described but not that it is in fact the
_only_ way that an eponymous template can in fact be instantiated.
I think this behavior will be surprising for someone new to D.
For eponymous templates you actually have the short-hand
declarative style as well...
void foo(S, T)(S s, T t) {}
..ok, needs to call with...
foo!(int, int) (1, 2);
...or even just...
foo(1, 2);
...and your template parameters will be deduced.
This is at least kind-of intuitive. But now if you declare the
template in the fully standard way:
template foo(S, T)
{
void foo(S s, T t) {}
}
..and you call it in the completely standard way (as you would
have in fact been required if template identifier and member were
differently named)...
foo!(int, int).foo(1, 2);
..it not only does _not_ compile, but gives you an error:
onlineapp.d(12): Error: function onlineapp.foo!(int, int).foo(int
s, int t) is not callable using argument types ()
...where foo!(int, int).foo(int s, int t) is clearly a match!
I really like the eponymous template trick and all that, but this
did catch me by surprise -I did not realize that the eponymous
template style in fact invalidates the 'classic' template
invocation style: it is one or the other. I was somehow under the
mistaken impression that you could still revert to the classic
style, even if your template identifier and member identifier
were identical.
Is there a technical reason for this limitation? Why are the
'classical' invocation style not allowed for eponymous templates
as well?
It seems somewhat arbitrary - note that inner/outer functions
does not have this limitation - the fllowing is legal and
compiles (and does not lead to infinite recursion):
int foo(int a, int b)
{
int foo(int x, int y) {return x+y;}
return foo(a, b);
}
void main()
{
int z = foo(2, 4);
}