April 28, 2012
On Saturday, 28 April 2012 at 09:40:49 UTC, Timon Gehr wrote:
> On 04/28/2012 09:46 AM, Max Samukha wrote:
>> On Saturday, 28 April 2012 at 06:03:54 UTC, Mehrdad wrote:
>>>> You expected that to work?
>>>
>>> Uhm, why not?
>>>
>>> template<class T>
>>> struct F
>>> {
>>>   F<F<T> > f() { return F<F<T> >(); }
>>> };
>>>
>>> int main()
>>> {
>>>   F<int>().f().f().f().f().f();  // etc.
>>>   return 0;
>>> }
>>>
>>
>> dmd is not smart enough
>
> DMD behaves according to the language specification here.
That is not specified anywhere in the language specification.

>
>> to avoid recursion by treating f as a
>> templated function. I am not sure whether it should,
>
> Maybe, but that would be a strange special case.

That is arguable. Non-templated functions are a special (degenerate) case of templated functions. The way virtual functions work doesn't allow C++/D to fully implement that notion. Mark f() 'virtual' in the C++ example and the code won't compile. Otherwise, C++ tries to be close to the ideal and I would expect D be no worse.

>
>> but the following should certainly work:
>>
>> struct F(T)
>> {
>>      auto f()() { return F!(F!T)(); }
>> }
>>
>> void main()
>> {
>>      F!int().f().f().f();
>> }
>>
>> Error: struct a.F(T) recursive template expansion for template
>> argument - why?
>>
>
> The checking for infinite recursion seems to be too conservative here. You could open a bug report.


April 28, 2012
On 04/28/2012 12:05 PM, Max Samukha wrote:
> On Saturday, 28 April 2012 at 09:40:49 UTC, Timon Gehr wrote:
>> On 04/28/2012 09:46 AM, Max Samukha wrote:
>>> On Saturday, 28 April 2012 at 06:03:54 UTC, Mehrdad wrote:
>>>>> You expected that to work?
>>>>
>>>> Uhm, why not?
>>>>
>>>> template<class T>
>>>> struct F
>>>> {
>>>>     F<F<T> > f() { return F<F<T> >(); }
>>>> };
>>>>
>>>> int main()
>>>> {
>>>>     F<int>().f().f().f().f().f(); // etc.
>>>>     return 0;
>>>> }
>>>>
>>>
>>> dmd is not smart enough
>>
>> DMD behaves according to the language specification here.
> That is not specified anywhere in the language specification.
>

"Semantic analysis is not done until instantiated."

On second thought, you are right, this is really badly phrased and does not say what it probably wants to. Anyway, the fact that templates are analysed fully eagerly upon instantiation is by design and the documentation should explicitly state that.

>>
>>> to avoid recursion by treating f as a
>>> templated function. I am not sure whether it should,
>>
>> Maybe, but that would be a strange special case.
>
> That is arguable.

If we are talking about the same thing, then it probably is not. I thought you were proposing to automatically templatise the function iff there is recursion?

> Non-templated functions are a special (degenerate) case of templated functions.

How to 'instantiate' a non-templated function? This would necessarily be a supported operation, if there actually was such a relation between the two concepts.

> The way virtual functions work doesn't allow C++/D to fully implement that notion.

That implies that the notion does not have merit. In D it was left out by design. And even C++ does not consistently implement it for non-virtuals.

> Mark f() 'virtual' in the C++ example and the code won't compile.

I know. Furthermore, add an invalid member function to the templated struct F and don't refer to it. There won't be any compile time error. (unless it is virtual, of course!)

> Otherwise, C++ tries to be close to the ideal

IMAO, it fails to be close to the ideal.

> and I would expect D be no worse.
>

Yah, and it really is not.

The other issue you brought up in this thread is certainly a real issue with the implementation though.
April 29, 2012
On Saturday, 28 April 2012 at 09:36:55 UTC, Timon Gehr wrote:
> On 04/28/2012 08:03 AM, Mehrdad wrote:
>>> You expected that to work?
>>
>> Uhm, why not?
>>
>> template<class T>
>> struct F
>> {
>>    F<F<T> > f() { return F<F<T> >(); }
>> };
>>
>> int main()
>> {
>>    F<int>().f().f().f().f().f();  // etc.
>>    return 0;
>> }
>
>
> D templates are analysed eagerly upon instantiation, whereas C++ templates are analysed lazily. This is not a bug, it is a feature.

Furthermore, eager analysis is necessary for other D features like CTFE and compile-time reflection. Honestly, in C++ I would stay away from code like the above anyway, irrelevant of whether it compiles, seems too "magic-y" for my tastes. I don't like things not being explicit.

--
James Miller
April 29, 2012
On Sunday, 29 April 2012 at 06:22:34 UTC, James Miller wrote:
>> D templates are analysed eagerly upon instantiation, whereas C++ templates are analysed lazily. This is not a bug, it is a feature.
>
> Furthermore, eager analysis is necessary for other D features like CTFE and compile-time reflection.

Ah, I was  wondering about that. Thank you for confirming.
I will gladly ditch lazy template eval for something like CTFE.

> Honestly, in C++ I would stay away from code like the above anyway, irrelevant of whether it compiles, seems too "magic-y" for my tastes. I don't like things not being explicit.
>

+1

May 01, 2012
Some ICE for y'all.

void filter(R)(scope bool delegate(ref BAD!R) func) { }
void main() { filter(r => r); }
May 01, 2012
Also, what exactly is wrong with this code?

private import std.range;
void filter(R)(R, bool delegate(ElementType!R)) { }
void main() { [1, 2, 3].filter(delegate bool(x) { return x < 3; }); }

May 01, 2012
On 05/01/2012 03:09 AM, Mehrdad wrote:
> Also, what exactly is wrong with this code?
>
> private import std.range;
> void filter(R)(R, bool delegate(ElementType!R)) { }
> void main() { [1, 2, 3].filter(delegate bool(x) { return x < 3; }); }
>

The current type deduction strategy for IFTI is (imho) too weak.

private import std.range;
void filter(R)(R, bool delegate(ElementType!R)) { }
void main() { [1, 2, 3].filter!(int[])(delegate bool(x) { return x < 3; }); }
May 01, 2012
Is it just "weak", or is it outright wrong?
It's telling me "R" isn't a valid identifier...


"Timon Gehr"  wrote in message news:jnnefl$2j69$1@digitalmars.com... 

On 05/01/2012 03:09 AM, Mehrdad wrote:
> Also, what exactly is wrong with this code?
>
> private import std.range;
> void filter(R)(R, bool delegate(ElementType!R)) { }
> void main() { [1, 2, 3].filter(delegate bool(x) { return x < 3; }); }
>

The current type deduction strategy for IFTI is (imho) too weak.

private import std.range;
void filter(R)(R, bool delegate(ElementType!R)) { }
void main() { [1, 2, 3].filter!(int[])(delegate bool(x) { return x < 3; }); }
May 01, 2012
On 05/01/2012 03:46 AM, Mehrdad wrote:
> Is it just "weak", or is it outright wrong?

Unfortunately it is by design that it does not work afaik.

> It's telling me "R" isn't a valid identifier...
>

That one is a diagnostics bug.

May 01, 2012
Wha..?!

I can't believe delegates work so poorly in D... they're practically unusable unless you're passing them as template parameters (which brings on its own set of bugs)...

Seems like every time I try to escape a bug somehow, another one pops up :(


"Timon Gehr"  wrote in message news:jnnfc6$2jve$2@digitalmars.com...

On 05/01/2012 03:46 AM, Mehrdad wrote:
> Is it just "weak", or is it outright wrong?

Unfortunately it is by design that it does not work afaik.

> It's telling me "R" isn't a valid identifier...
>

That one is a diagnostics bug.