View mode: basic / threaded / horizontal-split · Log in · Help
July 17, 2012
Is this actually supposed to be legal?
This code strikes me as being a bug:

--------
class MyBase(T)
{}

class MySubA : MyBase!MySubA
{}

class MySubB : MyBase!MySubB
{}

void main()
{}
--------

but it compiles just fine. However, given the fact that MySubA isn't even 
properly defined until its base class has been defined, I don't see how it could 
possibly _not_ be a bug for the base class to be templatized on it. You could 
get some really weird behavior if you use compile time reflection on the 
derived class in the base class definition.

Does anyone know if this is actually supposed to work? Or is it in fact a bug 
like I think it is?

- Jonathan M Davis
July 17, 2012
Re: Is this actually supposed to be legal?
On 17-07-2012 07:24, Jonathan M Davis wrote:
> This code strikes me as being a bug:
>
> --------
> class MyBase(T)
> {}
>
> class MySubA : MyBase!MySubA
> {}
>
> class MySubB : MyBase!MySubB
> {}
>
> void main()
> {}
> --------
>
> but it compiles just fine. However, given the fact that MySubA isn't even
> properly defined until its base class has been defined, I don't see how it could
> possibly _not_ be a bug for the base class to be templatized on it. You could
> get some really weird behavior if you use compile time reflection on the
> derived class in the base class definition.
>
> Does anyone know if this is actually supposed to work? Or is it in fact a bug
> like I think it is?
>
> - Jonathan M Davis
>

(Not sure if MySubB was meant to demonstrate anything; it's effectively 
semantically equal to MySubA.)

This code is meant to work. It doesn't actually introduce any circular 
inheritance. Consider, on the other hand, this:

class A : B {}
class B : A {}

or closer to your example:

class A(T) : T {}
class B : A!B {}

The difference is that here you have direct, circular inheritance, while 
in your example, the base type is merely parameterized with the deriving 
type, which is perfectly legal (and trivially resolvable in semantic 
analysis).

-- 
Alex Rønne Petersen
alex@lycus.org
http://lycus.org
July 17, 2012
Re: Is this actually supposed to be legal?
On Tuesday, July 17, 2012 07:37:38 Alex Rønne Petersen wrote:
> (Not sure if MySubB was meant to demonstrate anything; it's effectively
> semantically equal to MySubA.)

It's a simplification of an example in this question:

http://stackoverflow.com/questions/11516066/d-inheriting-static-variables-
differentiating-by-class

which was itself a simplification of other code.

- Jonathan M Davis
July 17, 2012
Re: Is this actually supposed to be legal?
It is indeed supposed to work, and was actually touted as a 
common and lauded example way back in the day.  However, with the 
advent of this-params for templates it seems less useful now 
(once they've been through the ringer a little more at least).

I did use this-params to great effect in Zeal, to auto-inject 
behavior into subclasses with the proper scoping and other 
concerns.  The base class didn't even have to be a template 
itself (just the magical internals).
https://github.com/csauls/zeal.d/blob/master/source/zeal/base/controller.d

So, to repeat, yes it is supposed to work... but I'm not so sure 
it is such a good idea anymore -- assuming this-params will work 
on the class declaration.

-- Chris NS
July 17, 2012
Re: Is this actually supposed to be legal?
There's a thorough explanation of how "incomplete types" work in 
C++:
http://www.drdobbs.com/the-standard-librarian-containers-of-inc/184403814

And there's some more C++ related stuff:
http://www.boost.org/doc/libs/1_50_0/doc/html/container/containers_of_incomplete_types.html

I wouldn't know about D though.
July 17, 2012
Re: Is this actually supposed to be legal?
On Tuesday, 17 July 2012 at 05:24:26 UTC, Jonathan M Davis wrote:
> This code strikes me as being a bug:
>
> --------
> class MyBase(T)
> {}
>
> class MySubA : MyBase!MySubA
> {}
>
> class MySubB : MyBase!MySubB
> {}
>
> void main()
> {}
> --------

This pattern is actually quite common in C++ code, and referred 
to as CRTP (curiously recurring template pattern). If you propose 
to kill it, Andrei is going to get mad at you. ;)

David
July 17, 2012
Re: Is this actually supposed to be legal?
On Tuesday, July 17, 2012 14:48:32 David Nadlinger wrote:
> On Tuesday, 17 July 2012 at 05:24:26 UTC, Jonathan M Davis wrote:
> > This code strikes me as being a bug:
> > 
> > --------
> > class MyBase(T)
> > {}
> > 
> > class MySubA : MyBase!MySubA
> > {}
> > 
> > class MySubB : MyBase!MySubB
> > {}
> > 
> > void main()
> > {}
> > --------
> 
> This pattern is actually quite common in C++ code, and referred
> to as CRTP (curiously recurring template pattern). If you propose
> to kill it, Andrei is going to get mad at you. ;)

Well, it certainly seems insane to me at first glance - particularly when you 
take compile time reflection into account, since the derived classes' 
definitions are now effectively recursive (so I suspect that the situation is 
worse in D, since C++ doesn't have conditional compliation like D does). But 
if it's supposed to be legal, I guess that it's suppose to be legal. I'd never 
seen the idiom before, and it seemed _really_ off to me, which is why I brought 
it up. But I'd have to study it in order to give an informed opinion on it.

- Jonathan M Davis
July 17, 2012
Re: Is this actually supposed to be legal?
On 7/17/2012 12:23 PM, Jonathan M Davis wrote:
> On Tuesday, July 17, 2012 14:48:32 David Nadlinger wrote:
>> On Tuesday, 17 July 2012 at 05:24:26 UTC, Jonathan M Davis wrote:
>>> This code strikes me as being a bug:
>>>
>>> --------
>>> class MyBase(T)
>>> {}
>>>
>>> class MySubA : MyBase!MySubA
>>> {}
>>>
>>> class MySubB : MyBase!MySubB
>>> {}
>>>
>>> void main()
>>> {}
>>> --------
>>
>> This pattern is actually quite common in C++ code, and referred
>> to as CRTP (curiously recurring template pattern). If you propose
>> to kill it, Andrei is going to get mad at you. ;)
>
> Well, it certainly seems insane to me at first glance - particularly when you
> take compile time reflection into account, since the derived classes'
> definitions are now effectively recursive (so I suspect that the situation is
> worse in D, since C++ doesn't have conditional compliation like D does). But
> if it's supposed to be legal, I guess that it's suppose to be legal. I'd never
> seen the idiom before, and it seemed _really_ off to me, which is why I brought
> it up. But I'd have to study it in order to give an informed opinion on it.
>
> - Jonathan M Davis
>

A 'proper' D port of this kind design would be to use mixins instead of 
the template.  They both accomplish the same thing:

The template (or mixins) are written to call functions in the user 
defined type.  A simple example would be the C++ WTL library: A user 
defined control defines its own window style, but the template code is 
responsible for creating the window, and accesses the style and class 
flags from the user defined type.

The advantage is the same in both: you avoid making the interface 
virtual, you still get to use some generic code.
July 17, 2012
Re: Is this actually supposed to be legal?
On 07/17/2012 07:23 PM, Jonathan M Davis wrote:
> On Tuesday, July 17, 2012 14:48:32 David Nadlinger wrote:
>> On Tuesday, 17 July 2012 at 05:24:26 UTC, Jonathan M Davis wrote:
>>> This code strikes me as being a bug:
>>>
>>> --------
>>> class MyBase(T)
>>> {}
>>>
>>> class MySubA : MyBase!MySubA
>>> {}
>>>
>>> class MySubB : MyBase!MySubB
>>> {}
>>>
>>> void main()
>>> {}
>>> --------
>>
>> This pattern is actually quite common in C++ code, and referred
>> to as CRTP (curiously recurring template pattern). If you propose
>> to kill it, Andrei is going to get mad at you. ;)
>
> Well, it certainly seems insane to me at first glance - particularly when you
> take compile time reflection into account, since the derived classes'
> definitions are now effectively recursive (so I suspect that the situation is
> worse in D, since C++ doesn't have conditional compliation like D does).

The fact that it is allowed does not make the compiler's job
significantly more complicated. It is not important if the type is
passed as a template argument or referred to directly from inside the
template -- the issues are the same.
July 17, 2012
Re: Is this actually supposed to be legal?
On Tuesday, July 17, 2012 22:36:10 Timon Gehr wrote:
> On 07/17/2012 07:23 PM, Jonathan M Davis wrote:
> > On Tuesday, July 17, 2012 14:48:32 David Nadlinger wrote:
> >> On Tuesday, 17 July 2012 at 05:24:26 UTC, Jonathan M Davis wrote:
> >>> This code strikes me as being a bug:
> >>> 
> >>> --------
> >>> class MyBase(T)
> >>> {}
> >>> 
> >>> class MySubA : MyBase!MySubA
> >>> {}
> >>> 
> >>> class MySubB : MyBase!MySubB
> >>> {}
> >>> 
> >>> void main()
> >>> {}
> >>> --------
> >> 
> >> This pattern is actually quite common in C++ code, and referred
> >> to as CRTP (curiously recurring template pattern). If you propose
> >> to kill it, Andrei is going to get mad at you. ;)
> > 
> > Well, it certainly seems insane to me at first glance - particularly when
> > you take compile time reflection into account, since the derived classes'
> > definitions are now effectively recursive (so I suspect that the
> > situation is worse in D, since C++ doesn't have conditional compliation
> > like D does).
> The fact that it is allowed does not make the compiler's job
> significantly more complicated. It is not important if the type is
> passed as a template argument or referred to directly from inside the
> template -- the issues are the same.

The problem is that if you have static ifs and the like in the base class 
which depends on compile time reflection of the derived class, you effectively 
have a recursive template definition. e.g.

class MyBase(T)
{
static if(is(tyepeof(T.func())))
{
int func() { return 42; }
}
}

- Jonathan M Davis
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home