Thread overview
How is this code supposed to work?
Jan 25, 2019
AndreasDavour
Jan 25, 2019
rikki cattermole
Jan 25, 2019
AndreasDavour
Jan 25, 2019
AndreasDavour
Jan 25, 2019
AndreasDavour
Jan 25, 2019
AndreasDavour
Jan 25, 2019
Neia Neutuladh
Jan 25, 2019
AndreasDavour
Jan 26, 2019
Neia Neutuladh
January 25, 2019
I'm reading the "Programming D" here:
http://ddili.org/ders/d.en/templates.html
and am a bit confused by the section on templates.

with a struct template like this:
struct Point(T) {
  T x;
  T y;

  T distanceTo(Point that) const {
    immutable real xDistance = x - that.x;
    immutable real yDistance = y - that.y;

    immutable distance = sqrt((xDistance * xDistance) +
			      (yDistance * yDistance));
    return cast(T) distance;
  }
}

and a function template like this:
Point!T getResponse(T : Point!T)(string question) {
    writefln("%s (Point!%s): ", question, T.stringof);

    auto x = getResponse!T(" x");
    auto y = getResponse!T(" y");

    return Point!T(x, y);
}

How am I supposed to use that??

  auto point3 = getResponse!Point!int("What's the point? ");
  auto point4 = getResponse!Point!int("What's the point? ");
  writeln("Distance: ", point3.distanceTo(point4));

generates the error:

struct_templates.d(48): Error: multiple ! arguments are not allowed
struct_templates.d(49): Error: multiple ! arguments are not allowed

Which makes me wonder about the syntax.

January 25, 2019
On 25/01/2019 10:34 PM, AndreasDavour wrote:
> How am I supposed to use that??
> 
>    auto point3 = getResponse!Point!int("What's the point? ");

auto point3 = getResponse!(Point!int)("What's the point? ");

>    auto point4 = getResponse!Point!int("What's the point? ");
>    writeln("Distance: ", point3.distanceTo(point4));
> 
> generates the error:
> 
> struct_templates.d(48): Error: multiple ! arguments are not allowed
> struct_templates.d(49): Error: multiple ! arguments are not allowed
> 
> Which makes me wonder about the syntax.

January 25, 2019
On Friday, 25 January 2019 at 09:36:24 UTC, rikki cattermole wrote:
> On 25/01/2019 10:34 PM, AndreasDavour wrote:
>> How am I supposed to use that??
>> 
>>    auto point3 = getResponse!Point!int("What's the point? ");
>
> auto point3 = getResponse!(Point!int)("What's the point? ");
>
>>    auto point4 = getResponse!Point!int("What's the point? ");
>>    writeln("Distance: ", point3.distanceTo(point4));
>> 
>> generates the error:
>> 
>> struct_templates.d(48): Error: multiple ! arguments are not allowed
>> struct_templates.d(49): Error: multiple ! arguments are not allowed
>> 
>> Which makes me wonder about the syntax.

I thought about that option, if it was unclear to the parser that Point!int was the type to instantiate upon. Changing to the other syntax made me wonder what would happen when getResponse is calling itself, which in self was something I am a bit unsure of how to understand. Because we get the same syntax issue there and it does not seem to work.
January 25, 2019
On Friday, 25 January 2019 at 12:09:34 UTC, AndreasDavour wrote:
> On Friday, 25 January 2019 at 09:36:24 UTC, rikki cattermole wrote:
>> On 25/01/2019 10:34 PM, AndreasDavour wrote:
>>>  [...]
>>
>> auto point3 = getResponse!(Point!int)("What's the point? ");
>>
>>> [...]
>
> I thought about that option, if it was unclear to the parser that Point!int was the type to instantiate upon. Changing to the other syntax made me wonder what would happen when getResponse is calling itself, which in self was something I am a bit unsure of how to understand. Because we get the same syntax issue there and it does not seem to work.

https://run.dlang.io/is/a4oDFZ is an example of how this looks. I feel like there's more to these templates than meet the eye.
January 25, 2019
On Friday, 25 January 2019 at 12:11:51 UTC, AndreasDavour wrote:
> On Friday, 25 January 2019 at 12:09:34 UTC, AndreasDavour wrote:
>> On Friday, 25 January 2019 at 09:36:24 UTC, rikki cattermole wrote:
>>> On 25/01/2019 10:34 PM, AndreasDavour wrote:
>>>>  [...]
>>>
>>> auto point3 = getResponse!(Point!int)("What's the point? ");
>>>
>>>> [...]
>>
>> I thought about that option, if it was unclear to the parser that Point!int was the type to instantiate upon. Changing to the other syntax made me wonder what would happen when getResponse is calling itself, which in self was something I am a bit unsure of how to understand. Because we get the same syntax issue there and it does not seem to work.
>
> https://run.dlang.io/is/a4oDFZ is an example of how this looks. I feel like there's more to these templates than meet the eye.

To clarify. I really don't understand the thinking behind these templates, and wonder a bit about why a tutorial text like that contains examples that doesn't compile. There must be a conceptual unclarity somewhere I feel, not just where the parenthesis goes.
January 25, 2019
On Fri, 25 Jan 2019 09:34:47 +0000, AndreasDavour wrote:
>    auto point3 = getResponse!Point!int("What's the point? ");

This could be:

    getResponse!(Point!int)

or:

    (getResponse!Point)!int

D requires this to be disambiguated at the parsing stage, before the compiler works out what getResponse might be.

An example of the latter:

template getResponse(alias n)
{
    alias getResponse = n;
}

getResponse!Point is just Point.

I'm not sure why that tutorial has it wrong, but the way to get it fixed is to contact the author.
January 25, 2019
On Friday, 25 January 2019 at 14:25:33 UTC, AndreasDavour wrote:

>> https://run.dlang.io/is/a4oDFZ is an example of how this looks. I feel like there's more to these templates than meet the eye.
>
> To clarify. I really don't understand the thinking behind these templates, and wonder a bit about why a tutorial text like that contains examples that doesn't compile. There must be a conceptual unclarity somewhere I feel, not just where the parenthesis goes.

Finally the penny dropped. So for the poor sods who will find this in a web search in the future, I will add to my my monologue and show off both my stupidity and maybe some hints on how to understand what was going on. I know nothing of C++ and if templates are a concept from there, so maybe that was why I did not get it.

The chapter from "Programming D" I was referring to in my first post did start to talk about function templates, and then moved on to step by step show templating of structs, and functions to work upon those. What I did not grasp was that these were all part of the code. The author made me think, by his choice of words or my preconceptions I do not know, that he showed incremental additions to the function template and sequentially the struct template, when he was in fact showing new templates all together. So, if I included all the templates, specializing on Point, and then string, and only T, and so on, it worked as intended.

What I did not grasp with the code of this template:

Point!T getResponse(T : Point!T)(string question) {
    writefln("%s (Point!%s): ", question, T.stringof);

    auto x = getResponse!T(" x");
    auto y = getResponse!T(" y");

    return Point!T(x, y);
}

was that the "inner" call to getResponse() is not a private method within this scope, and thus dispatching on the same type (which would make it recursive), but if you had that other templates specializing on other types it would call the correct function. I had the templating system down as a one pass search-and-replace, but it's clearly more dynamic than that. So I was correct there was a conceptual un-clarity present. With me.

This brings up an interesting point. How do you write a text that teaches these things? If you break up the code in small blocks where you explain the concepts step by step, and show variants and how you can expand the abilities of the code by using more and more complex features, how do you do that so all the code is self contained? Maybe it can not always be done, and should you then have the final code in a block at the end, or do you note clearly in the text that *this* block is an example, but *this new* code block is complete and will work? It would be verbose if you in every instance would quote boilerplate like the import std.* and so on. I'm not sure I know how to best do it. Teaching is hard.
January 25, 2019
On Friday, 25 January 2019 at 16:19:38 UTC, Neia Neutuladh wrote:
> On Fri, 25 Jan 2019 09:34:47 +0000, AndreasDavour wrote:
>>    auto point3 = getResponse!Point!int("What's the point? ");
>
> This could be:
>
>     getResponse!(Point!int)
>
> or:
>
>     (getResponse!Point)!int
>
> D requires this to be disambiguated at the parsing stage, before the compiler works out what getResponse might be.
>
> An example of the latter:
>
> template getResponse(alias n)
> {
>     alias getResponse = n;
> }
>
> getResponse!Point is just Point.
>
> I'm not sure why that tutorial has it wrong, but the way to get it fixed is to contact the author.

Thanks! I had some issues with the syntax, and getting that part correct got me to the conceptual bits, which is where I got lost for real. Syntax errors are such a drag, though.

Appreciated.
January 25, 2019
On 1/25/19 11:19 AM, Neia Neutuladh wrote:
> On Fri, 25 Jan 2019 09:34:47 +0000, AndreasDavour wrote:
>>     auto point3 = getResponse!Point!int("What's the point? ");
> 
> This could be:
> 
>      getResponse!(Point!int)
> 
> or:
> 
>      (getResponse!Point)!int
> 
> D requires this to be disambiguated at the parsing stage, before the
> compiler works out what getResponse might be.

Interestingly, It's not possible to do the second form, so it's a bit curious why we don't just drop the requirements for nested parentheses...

-Steve
January 26, 2019
On Fri, 25 Jan 2019 19:14:51 -0500, Steven Schveighoffer wrote:
> Interestingly, It's not possible to do the second form, so it's a bit curious why we don't just drop the requirements for nested parentheses...

The error messages there are really hideous, too:

template Just(alias s) { alias Just = s; }
alias f = (Just!Just)!int;

scratch.d(16): Error: basic type expected, not (
scratch.d(16): Error: function declaration without return type. (Note that
constructors are always named this)
scratch.d(16): Error: semicolon expected to close alias declaration
scratch.d(16): Error: found ; when expecting . following int
scratch.d(17): Error: found } when expecting identifier following int.
scratch.d(18): Error: found End of File when expecting ; following
statement
scratch.d(18): Error: found End of File when expecting } following
compound statement

So I guess this is just to make people less confused about order of operations, since it would be unexpectedly right-associative in a language where most things are left-associative?