POV-Ray : Newsgroups : povray.off-topic : Generics annoyance Server Time
13 Oct 2026 05:44:56 EDT (-0400)
  Generics annoyance (Message 1 to 38 of 38)  
From: Darren New
Subject: Generics annoyance
Date: 12 Apr 2010 18:41:08
Message: <4bc3a184$1@news.povray.org>
Actually, one place I think C++ style templates beat out generics is in this:

In MS's simple game libraries, there's a class called GameComponent.
It inherits from IUpdatable, IDrawable, and IMumble, each of which provides 
the declaration of one of the main routines in a game (update, draw, and 
initialize, respectively).

Now, if I wanted (and I do) to make a collection of things that act like 
GameComponent objects but aren't necessarily game components, I don't think 
I can do that in C#. I would have to have a collection parameterized on all 
three of those interfaces. GameComponent supports a bunch of things that i 
might not want to have to support, but I can't make a collection that'll let 
me add "anything with those three routines, including GameComponent."

I think this is something that Google's Go did better, if I understand it. 
C++ templates don't have that problem, but that's because you don't compile 
them separately, so what would normally have to be a runtime check gets done 
at compile time.

In any case, it's rather annoying. :-) I might have to figure out how to 
patch up MS's samples to also host a collection of game components as well 
as the scene-activation/deactivation they do.

-- 
Darren New, San Diego CA, USA (PST)
   Yes, we're traveling together,
   but to different destinations.


Post a reply to this message

From: Invisible
Subject: Re: Generics annoyance
Date: 13 Apr 2010 04:38:54
Message: <4bc42d9e$1@news.povray.org>
Darren New wrote:
> Actually, one place I think C++ style templates beat out generics is in 
> this:

As I've written before, AFAIK these are two entirely unrelated 
technologies that do totally different things.

> In MS's simple game libraries, there's a class called GameComponent.
> It inherits from IUpdatable, IDrawable, and IMumble, each of which 
> provides the declaration of one of the main routines in a game (update, 
> draw, and initialize, respectively).
> 
> Now, if I wanted (and I do) to make a collection of things that act like 
> GameComponent objects but aren't necessarily game components, I don't 
> think I can do that in C#. I would have to have a collection 
> parameterized on all three of those interfaces. GameComponent supports a 
> bunch of things that i might not want to have to support, but I can't 
> make a collection that'll let me add "anything with those three 
> routines, including GameComponent."

Heh, just use a language that has first-class functions, and store a 
collection of functions. ;-)


Post a reply to this message

From: Warp
Subject: Re: Generics annoyance
Date: 13 Apr 2010 06:25:59
Message: <4bc446b7@news.povray.org>
Darren New <dne### [at] sanrrcom> wrote:
> Actually, one place I think C++ style templates beat out generics is in this:

  Who are you and what have you done to our friend Darren?

  (I know, I know, very old joke. But I just *had* to.)

> In MS's simple game libraries, there's a class called GameComponent.
> It inherits from IUpdatable, IDrawable, and IMumble, each of which provides 
> the declaration of one of the main routines in a game (update, draw, and 
> initialize, respectively).

> Now, if I wanted (and I do) to make a collection of things that act like 
> GameComponent objects but aren't necessarily game components, I don't think 
> I can do that in C#. I would have to have a collection parameterized on all 
> three of those interfaces. GameComponent supports a bunch of things that i 
> might not want to have to support, but I can't make a collection that'll let 
> me add "anything with those three routines, including GameComponent."

> I think this is something that Google's Go did better, if I understand it. 
> C++ templates don't have that problem, but that's because you don't compile 
> them separately, so what would normally have to be a runtime check gets done 
> at compile time.

  I wouldn't say it's that simple with C++ templates either.

  You can write a template function which takes an object which "behaves like
a GameComponent" and does things to it ok. However, making a collection (data
container) is a slightly different issue.

  If all the objects in the container are of the exact same type, then it's
possible and trivial. Problems start if, in the situation you describe, you
would want to store objects of different types in the container (even if they
all behave like a GameComponent).

  You could store *pointers* to the objects in your container, but then you
would end up with the same problem as in C# (if I understood correctly): You
would have to decide the type of the pointer (which has to be the same for
all the container elements).

-- 
                                                          - Warp


Post a reply to this message

From: clipka
Subject: Re: Generics annoyance
Date: 13 Apr 2010 07:48:10
Message: <4bc459fa@news.povray.org>
Am 13.04.2010 00:41, schrieb Darren New:
> Actually, one place I think C++ style templates beat out generics is in
> this:
>
> In MS's simple game libraries, there's a class called GameComponent.
> It inherits from IUpdatable, IDrawable, and IMumble, each of which
> provides the declaration of one of the main routines in a game (update,
> draw, and initialize, respectively).
>
> Now, if I wanted (and I do) to make a collection of things that act like
> GameComponent objects but aren't necessarily game components, I don't
> think I can do that in C#. I would have to have a collection
> parameterized on all three of those interfaces. GameComponent supports a
> bunch of things that i might not want to have to support, but I can't
> make a collection that'll let me add "anything with those three
> routines, including GameComponent."

 From the little I could find ad-hoc on the internet, there seems to be 
an interface IGameComponent, so probably all you have to do is make sure 
that all classes you want to store in that thing implement 
IGameComponent, and use an IGameComponent container.

That's what interfaces are for, after all.


Post a reply to this message

From: Darren New
Subject: Re: Generics annoyance
Date: 13 Apr 2010 11:23:36
Message: <4bc48c78$1@news.povray.org>
Invisible wrote:
> Darren New wrote:
>> Actually, one place I think C++ style templates beat out generics is 
>> in this:
> 
> As I've written before, AFAIK these are two entirely unrelated 
> technologies that do totally different things.

Yep.

> Heh, just use a language that has first-class functions, and store a 
> collection of functions. ;-)

Except I want objects, and not just functions. They all have state, and 
(worse) they tend to keep pointers to each other. The gridplane needs to 
remember how big you want the grid, and it also needs to know where the 
camera is so it can draw itself, for example. The guy in the maze needs to 
know where the camera is, needs the maze structure, needs the reference to 
the gamepad, etc.

-- 
Darren New, San Diego CA, USA (PST)
   Yes, we're traveling together,
   but to different destinations.


Post a reply to this message

From: Invisible
Subject: Re: Generics annoyance
Date: 13 Apr 2010 11:25:24
Message: <4bc48ce4$1@news.povray.org>
>> Heh, just use a language that has first-class functions, and store a 
>> collection of functions. ;-)
> 
> Except I want objects, and not just functions. They all have state, and 
> (worse) they tend to keep pointers to each other. The gridplane needs to 
> remember how big you want the grid, and it also needs to know where the 
> camera is so it can draw itself, for example. The guy in the maze needs 
> to know where the camera is, needs the maze structure, needs the 
> reference to the gamepad, etc.

It wasn't an entirely serious suggestion. (Although you could probably 
make it work. Just have the functions point to the state you want them 
to mutate...)


Post a reply to this message

From: Darren New
Subject: Re: Generics annoyance
Date: 13 Apr 2010 11:27:04
Message: <4bc48d48$1@news.povray.org>
clipka wrote:
>  From the little I could find ad-hoc on the internet, there seems to be 
> an interface IGameComponent, so probably all you have to do is make sure 
> that all classes you want to store in that thing implement 
> IGameComponent, and use an IGameComponent container.

IGameComponent implements the "Initialize" method.
IDrawable implements the "Draw" method.
IUpdatable implements the "Update" method.
GameComponent inherits IGameComponent, IDrawable, IUpdatable.

There's no way to make a "collection of objects that implement 
IGameComponent, IDrawable, and IUpdatable" as far as I know.

> That's what interfaces are for, after all.

Yeah, and it would have been nice if IGameComponent included most or all of 
the methods that GameComponent implements.

-- 
Darren New, San Diego CA, USA (PST)
   Yes, we're traveling together,
   but to different destinations.


Post a reply to this message

From: Darren New
Subject: Re: Generics annoyance
Date: 13 Apr 2010 11:32:33
Message: <4bc48e91$1@news.povray.org>
Warp wrote:
> Darren New <dne### [at] sanrrcom> wrote:
>> Actually, one place I think C++ style templates beat out generics is in this:
> 
>   Who are you and what have you done to our friend Darren?

Heh.

>   You could store *pointers* to the objects in your container, but then you
> would end up with the same problem as in C# (if I understood correctly): You
> would have to decide the type of the pointer (which has to be the same for
> all the container elements).

That's a point I hadn't considered, yes.

Actually, I think that clued me in a bit. They *are* all of type "object". ;-)

So I could just have a list of objects, and when I get an update, 
(dynamic)-cast each element to a IUpdatable and invoke that if it works; 
when I get a draw, cast each to an IDrawable and invoke that if it works, etc.

Ugly, but it'll do the trick, I think.

I still don't want to implement all the other mechanics going on there, and 
I *do* want to implement somewhat different mechanics to make things more 
self-contained. (As it stands, for example, there's no good place to "add 
yourself to the list" during initialization. The object that is creating you 
has to add you to the list of objects it knows about, which is inconvenient 
in some ways.)

Anyway, maybe I'll grope thru the brand new 4.0 release and see what they 
have there. They really changing a bunch of this sort of stuff around each 
release, while leaving the basic underlying drawing calls alone, so maybe 
they realized people need more support for the kind of problem I'm trying to 
solve.

-- 
Darren New, San Diego CA, USA (PST)
   Yes, we're traveling together,
   but to different destinations.


Post a reply to this message

From: Invisible
Subject: Re: Generics annoyance
Date: 13 Apr 2010 11:36:52
Message: <4bc48f94$1@news.povray.org>
Darren New wrote:

> Actually, I think that clued me in a bit. They *are* all of type 
> "object". ;-)
> 
> So I could just have a list of objects, and when I get an update, 
> (dynamic)-cast each element to a IUpdatable and invoke that if it works; 
> when I get a draw, cast each to an IDrawable and invoke that if it 
> works, etc.
> 
> Ugly, but it'll do the trick, I think.

Ah yes, ye olde "upcast everything to Object" antipattern. :-D


Post a reply to this message

From: Darren New
Subject: Re: Generics annoyance
Date: 13 Apr 2010 11:43:50
Message: <4bc49136$1@news.povray.org>
Invisible wrote:
> It wasn't an entirely serious suggestion. (Although you could probably 
> make it work. Just have the functions point to the state you want them 
> to mutate...)

We already have that. We call them "objects". ;-)

No, seriously, what do you think a pointer to an array of closures all 
referencing the same variable is?

-- 
Darren New, San Diego CA, USA (PST)
   Yes, we're traveling together,
   but to different destinations.


Post a reply to this message

From: Christian Froeschlin
Subject: Re: Generics annoyance
Date: 13 Apr 2010 11:51:04
Message: <4bc492e8$1@news.povray.org>
Darren New wrote:

> There's no way to make a "collection of objects that implement 
> IGameComponent, IDrawable, and IUpdatable" as far as I know.

I suppose you could subclass a collection of IGameComponents
and add run-time type checks to only allow adding objects which
also implement IDrawable and IUpdatable.


Post a reply to this message

From: Darren New
Subject: Re: Generics annoyance
Date: 13 Apr 2010 11:53:08
Message: <4bc49364$1@news.povray.org>
Invisible wrote:
> Darren New wrote:
> 
>> Actually, I think that clued me in a bit. They *are* all of type 
>> "object". ;-)
>>
>> So I could just have a list of objects, and when I get an update, 
>> (dynamic)-cast each element to a IUpdatable and invoke that if it 
>> works; when I get a draw, cast each to an IDrawable and invoke that if 
>> it works, etc.
>>
>> Ugly, but it'll do the trick, I think.
> 
> Ah yes, ye olde "upcast everything to Object" antipattern. :-D

Well, it gives me the advantage that I could use the same container as a 
"service provider."  So as soon as you create something that inherits from
a specific interface, you can also retrieve that thing from other 
components.  This should work out better with what I'm trying to do, which 
is more a scene manager (opening screen, start menu, options menu, game, 
high-score list, cutscenes, etc) than a single-screen game. The services 
manager that comes with XNA is tied to the overall game, meaning you 
couldn't have (say) different gamepad managers or different cameras for the 
different sections.

But yeah, it would be a generic bag'o'objects, which is certainly not the 
best way of doing things.

http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.gameservicecontainer.getservice.aspx

-- 
Darren New, San Diego CA, USA (PST)
   Yes, we're traveling together,
   but to different destinations.


Post a reply to this message

From: Darren New
Subject: Re: Generics annoyance
Date: 13 Apr 2010 12:31:55
Message: <4bc49c7b$1@news.povray.org>
Christian Froeschlin wrote:
> Darren New wrote:
> 
>> There's no way to make a "collection of objects that implement 
>> IGameComponent, IDrawable, and IUpdatable" as far as I know.
> 
> I suppose you could subclass a collection of IGameComponents
> and add run-time type checks to only allow adding objects which
> also implement IDrawable and IUpdatable.

Yeah. I think I'm just going to make it an array of objects, and only act on 
the ones that have the right routines defined.

Unfortunately, GameComponent also implements a whole bunch of stuff that 
isn't in the interfaces, like LoadContent (for loading textures and such 
whenever the screen resolution changes) and UpdateOrder (for determining 
what order to update the components in).

I think I'll just do it myself. The stuff that's already there isn't that 
sophisticated, and the promise of lots of people building standard 
components apparently didn't materialize because MS never released the 
point-and-click "designer" part that would let you build games out of 
components the way you build Windows apps out of widgets.

-- 
Darren New, San Diego CA, USA (PST)
   Yes, we're traveling together,
   but to different destinations.


Post a reply to this message

From: Warp
Subject: Re: Generics annoyance
Date: 13 Apr 2010 16:46:40
Message: <4bc4d82f@news.povray.org>
Invisible <voi### [at] devnull> wrote:
> Darren New wrote:

> > Actually, I think that clued me in a bit. They *are* all of type 
> > "object". ;-)
> > 
> > So I could just have a list of objects, and when I get an update, 
> > (dynamic)-cast each element to a IUpdatable and invoke that if it works; 
> > when I get a draw, cast each to an IDrawable and invoke that if it 
> > works, etc.
> > 
> > Ugly, but it'll do the trick, I think.

> Ah yes, ye olde "upcast everything to Object" antipattern. :-D

  Yeah, that kind of OO programming has always been considered bad design.

  If C# offered multiple inheritance (I don't know if it does), then you
could inherit all the objects you are using from GameComponent and your
own "base class", which is what the container then contains.

  (Of course this solution wouldn't help if you have to store objects
which have been eg. instantiated by the library framework itself because
those would not have been inherited from your "base class".)

-- 
                                                          - Warp


Post a reply to this message

From: clipka
Subject: Re: Generics annoyance
Date: 13 Apr 2010 17:47:08
Message: <4bc4e65c$1@news.povray.org>
Am 13.04.2010 22:46, schrieb Warp:

>    If C# offered multiple inheritance (I don't know if it does), then you
> could inherit all the objects you are using from GameComponent and your
> own "base class", which is what the container then contains.
>
>    (Of course this solution wouldn't help if you have to store objects
> which have been eg. instantiated by the library framework itself because
> those would not have been inherited from your "base class".)

I guess the typical C# approach to this type of problem would be wrapper 
classes, which IIRC are not too difficult to write in C#. Such wrappers 
could then just implement a common interface you intend to support.


Post a reply to this message

From: Darren New
Subject: Re: Generics annoyance
Date: 13 Apr 2010 18:32:40
Message: <4bc4f108$1@news.povray.org>
Warp wrote:
>   Yeah, that kind of OO programming has always been considered bad design.

Actually, in this case, it kind of makes sense. You want to call draw() on 
things with a draw() function, call initialize() on things with an 
initialize() function, etc.  Basic duck typing.

>   If C# offered multiple inheritance (I don't know if it does), 

Only via interfaces. Much like Java in that respect.

> then you
> could inherit all the objects you are using from GameComponent and your
> own "base class", which is what the container then contains.

Then everything would be of type GameComponent, and that wouldn't really fix 
that I wanted to use both GameComponents and my own stuff. :-)

In other words, I wanted a generic list that would hold both GameComponents 
that other people wrote that I don't have the source to, as well as my own 
components that have the same routines but a different base class.

>   (Of course this solution wouldn't help if you have to store objects
> which have been eg. instantiated by the library framework itself because
> those would not have been inherited from your "base class".)

Oh. Yes, right, that's the problem.  Other people are writing those 
components. That's what makes them "components."  :-)

Altho I found another sample project that the documentation makes it look 
like it's using the same framework I want to use (same class names, layouts, 
etc), as well as talking about using custom GameComponents as part of it, so 
I need to take time to dig into that source and see if they changed the 
framework to invoke the right routines of a GameComponent as needed.

-- 
Darren New, San Diego CA, USA (PST)
   Yes, we're traveling together,
   but to different destinations.


Post a reply to this message

From: Warp
Subject: Re: Generics annoyance
Date: 14 Apr 2010 07:48:51
Message: <4bc5aba2@news.povray.org>
Darren New <dne### [at] sanrrcom> wrote:
> >   If C# offered multiple inheritance (I don't know if it does), 

> Only via interfaces. Much like Java in that respect.

  I really can't understand what would be the problem in supporting
full-fledged multiple inheritance.

  If your answer contains the term "diamond inheritance", then forbid
diamond inheritance, not multiple inheritance.

  (Could this be, perhaps, related to garbage collection? It makes GC a lot
more complicated if references don't always point to the beginning of the
allocated memory block?)

-- 
                                                          - Warp


Post a reply to this message

From: Nicolas Alvarez
Subject: Re: Generics annoyance
Date: 14 Apr 2010 11:38:46
Message: <4bc5e186$1@news.povray.org>
Warp wrote:
>   I really can't understand what would be the problem in supporting
> full-fledged multiple inheritance.
> 
>   If your answer contains the term "diamond inheritance", then forbid
> diamond inheritance, not multiple inheritance.

If you add multiple inheritance to a language where every class inherits 
from a common base class (Object), every time you multiple-inherit you're 
getting a diamond.


Post a reply to this message

From: Warp
Subject: Re: Generics annoyance
Date: 14 Apr 2010 12:47:26
Message: <4bc5f19e@news.povray.org>
Nicolas Alvarez <nic### [at] gmailcom> wrote:
> Warp wrote:
> >   I really can't understand what would be the problem in supporting
> > full-fledged multiple inheritance.
> > 
> >   If your answer contains the term "diamond inheritance", then forbid
> > diamond inheritance, not multiple inheritance.

> If you add multiple inheritance to a language where every class inherits 
> from a common base class (Object), every time you multiple-inherit you're 
> getting a diamond.

  Then don't make every class inherit from a common base class. Interfaces
don't, so why should classes?

  If you really want must have classes inherit from Object, then simply
allow interfaces to have member variables and function implementations.
Then you'll have full-fledged multiple inheritance without diamond
inheritance.

-- 
                                                          - Warp


Post a reply to this message

From: Darren New
Subject: Re: Generics annoyance
Date: 14 Apr 2010 12:49:45
Message: <4bc5f229$1@news.povray.org>
Warp wrote:
>   I really can't understand what would be the problem in supporting
> full-fledged multiple inheritance.

Complexity, perhaps.

Also, remember the CIL is designed to support multiple languages. Granted, 
you're going to have trouble accessing objects from COBOL, but it's likely 
that MI would just make it that much more difficult. There's already kludgey 
work-arounds for (e.g.) getting to properties and indexers from languages 
that don't have properties.

>   If your answer contains the term "diamond inheritance", then forbid
> diamond inheritance, not multiple inheritance.

Impossible if everything inherits from Object. :-)

>   (Could this be, perhaps, related to garbage collection? It makes GC a lot
> more complicated if references don't always point to the beginning of the
> allocated memory block?)

That's certainly part of it, but you don't need to support multiple 
inheritance in the same way C++ does it.  Eiffel has multiple inheritance, 
garbage collection, and O(1) virtual dispatch.  (That last would probably be 
quite difficult if you didn't compile everything at the same time, of course.)

C# allows you to inherit from multiple interfaces that define the same 
method names and distinguish between them at compile time and runtime. 
(I.e., you can already have a Dog::Run interface and a Thread::Run interface 
and invoke them that way and have different implementations.) So it's not 
just a problem with the metadata and naming. (Eiffel has a different 
solution to this problem.)

Some of the rules of the language are based on superclasses. If you throw an 
object, it has to descend from Exceptions. A class with value semantics has 
to descend from "Values" or something like that. A delegate (like an OO 
function pointer) has to descend from Delegate. Etc. Maybe that's part of 
the problem.

But really, I don't think there are any obvious technical problems that 
couldn't be solved with enough work.

-- 
Darren New, San Diego CA, USA (PST)
   Yes, we're traveling together,
   but to different destinations.


Post a reply to this message

From: Darren New
Subject: Re: Generics annoyance
Date: 14 Apr 2010 13:13:21
Message: <4bc5f7b1$1@news.povray.org>
Warp wrote:
>   Then don't make every class inherit from a common base class. Interfaces
> don't, so why should classes?

Because then you can put routines on that common base class that are common 
to every class, like ToString() and Equals() and HashCode() and such.

>   If you really want must have classes inherit from Object, then simply
> allow interfaces to have member variables and function implementations.
> Then you'll have full-fledged multiple inheritance without diamond
> inheritance.

That certainly sounds like a good idea to me. :-)

Of course, the way it works now is that an interface doesn't actually change 
what's in the class. It's more a promise that the class implements a 
particular set of routines. So it's not unlike a pure abstract class. If you 
already implement a routine called Run, whether you inherit from Runnable 
doesn't change what's in your class, only what's in your metadata. So adding 
that feature isn't as much of a no-brainer as it might otherwise be.

On the other hand, maybe it wouldn't be a bad idea to have inheriting from 
an interface actually insert code into your class as necessary. It would 
certainly be a trivial way to make that work in C# at least, if not in other 
languages based on the CIL.

Where have you found multiple inheritance particularly useful in C++? Eiffel 
uses it all the time to good effect in its data structures, but I've never 
really seen anything in C++ that used it, in part maybe because of the way 
it's implemented in C++ with classes nested inside other classes and such 
and not being able to inherit from basic types.

-- 
Darren New, San Diego CA, USA (PST)
   Yes, we're traveling together,
   but to different destinations.


Post a reply to this message

From: Warp
Subject: Re: Generics annoyance
Date: 14 Apr 2010 13:53:24
Message: <4bc60113@news.povray.org>
Darren New <dne### [at] sanrrcom> wrote:
> Because then you can put routines on that common base class that are common 
> to every class, like ToString() and Equals() and HashCode() and such.

  I think that a class for which it doesn't make any sense to have something
like "ToString()" it would be bad design to force it to have it after all.

> On the other hand, maybe it wouldn't be a bad idea to have inheriting from 
> an interface actually insert code into your class as necessary. It would 
> certainly be a trivial way to make that work in C# at least, if not in other 
> languages based on the CIL.

  I wonder if it would make garbage collection more complicated because now
you can have references pointing to the middle of an object rather than the
beginning (and it may be the *only* reference pointing to that object, so
the object must not be collected as long as this reference exists, but it
may be more complicated for the GC engine to know this).

> Where have you found multiple inheritance particularly useful in C++?

  Wherever implementing multiple interfaces (or a base class and one or
more interfaces) is useful in any OO language, in cases where it would
actually be useful if the "interface" methods could have default
implementations, or if it would be useful if the interface provided
auxiliary methods for the derived class to use.

  The problem with "interfaces" is that they are not *helpful* at all.
The don't offer any functionality, any default implementations or any
data. These "interfaces" could often become a lot more helpful if they
actually offered something for the derived class so that it doesn't have
to implement everything from scratch every time.

  I'm not saying that every single program I have written (or even a
significant amount of them) uses multiple inheritance, but it has been
useful sometimes.

-- 
                                                          - Warp


Post a reply to this message

From: Warp
Subject: Re: Generics annoyance
Date: 14 Apr 2010 14:04:57
Message: <4bc603c9@news.povray.org>
Darren New <dne### [at] sanrrcom> wrote:
> That's certainly part of it, but you don't need to support multiple 
> inheritance in the same way C++ does it.  Eiffel has multiple inheritance, 
> garbage collection, and O(1) virtual dispatch.  (That last would probably be 
> quite difficult if you didn't compile everything at the same time, of course.)

  As I have mentioned before, you can cast an object pointer to an
incompatible type assuming that:

  1) Both the source and destination types have a virtual table (in C++ it's
created by making at least one member function virtual; usually at least the
destructor should be in these cases).

  2) The actual object to which this pointer is pointing to has been
multiple-inherited from both the source and destination types (even if
by a very long inheritance chain).

  The dynamic cast checks at runtime whether the casting is ok or not
(if it isn't, it returns a null pointer). If the object is of a type
which has been multiple-inherited from both, the dynamic cast will return
a pointer which will point to the destination type part inside the object.

  Curiously, the code which performs the cast doesn't need to know that
the multiple-inherited class even exists or what it looks like, and the
cast will still work properly.

  I wonder if Eiffel supports this as well.

-- 
                                                          - Warp


Post a reply to this message

From: Darren New
Subject: Re: Generics annoyance
Date: 14 Apr 2010 14:14:09
Message: <4bc605f1$1@news.povray.org>
Warp wrote:
>   I think that a class for which it doesn't make any sense to have something
> like "ToString()" it would be bad design to force it to have it after all.

I think there's a reasonable "ToString()" for every class. There aren't many 
routines in Object, but the ones there are pretty universal. "What type am 
I?"  "What code defines this type?"  "What's my address?"  Stuff like that.

In the CIL, I haven't memorized exactly what's there, and some stuff like 
that might be in other libraries. But it's usually pretty universal.

>   I wonder if it would make garbage collection more complicated because now
> you can have references pointing to the middle of an object rather than the
> beginning (and it may be the *only* reference pointing to that object, so
> the object must not be collected as long as this reference exists, but it
> may be more complicated for the GC engine to know this).

For something managed, I think that would be the wrong way to implement MI. 
It's still just one object, even if it inherits data and code from multiple 
classes.  For example, Python has MI and doesn't have pointers into the 
middle of objects.

You could also do it as a sort of "automatic delegation", where each of the 
multiple parent classes is represented as a separate object on the heap, for 
example, and the child class delegates all the non-overridden calls to the 
parent class. In this case, you'd have no significant overhead if the parent 
class contributed only code (as the JIT would optimize out the additional 
redirection on first invocation).  You might be able to also jit-compile the 
multiple classes and rearrange their code to use different offsets for the 
instance variables when you load the CIL code for a class that has multiple 
parents, for example.

The only reason C++ carries pointers to the middle of objects (as far as I 
can tell) is that they can't rewrite the object code to use different 
offsets in the child class compared to the parent class, and of course 
because it can since there's no memory compaction.

>> Where have you found multiple inheritance particularly useful in C++?
> 
>   Wherever implementing multiple interfaces (or a base class and one or
> more interfaces) is useful in any OO language, in cases where it would
> actually be useful if the "interface" methods could have default
> implementations, or if it would be useful if the interface provided
> auxiliary methods for the derived class to use.

So the "mix in" sort of inheritance. OK.

>   The problem with "interfaces" is that they are not *helpful* at all.
> The don't offer any functionality, any default implementations or any
> data. These "interfaces" could often become a lot more helpful if they
> actually offered something for the derived class so that it doesn't have
> to implement everything from scratch every time.

That would definitely be useful, yes.  Maybe a later version will add it.

Probably right after the folks working on Java do. ;-)

-- 
Darren New, San Diego CA, USA (PST)
   Yes, we're traveling together,
   but to different destinations.


Post a reply to this message

From: Darren New
Subject: Re: Generics annoyance
Date: 14 Apr 2010 14:20:55
Message: <4bc60787$1@news.povray.org>
Warp wrote:
> Darren New <dne### [at] sanrrcom> wrote:
>> That's certainly part of it, but you don't need to support multiple 
>> inheritance in the same way C++ does it.  Eiffel has multiple inheritance, 
>> garbage collection, and O(1) virtual dispatch.  (That last would probably be 
>> quite difficult if you didn't compile everything at the same time, of course.)
> 
>   As I have mentioned before, you can cast an object pointer to an
> incompatible type assuming that:

Right.  I'm not sure what that had to do with what I was saying.

I was trying to say that Eiffel holds only one pointer to any given object, 
and that points to the start of the instance. This way, Eiffel gets simpler 
GC. It also does multiple inheritance in fairly complex ways, and has an 
efficient dispatch to handle it (i.e., no run-time lookups up the 
inheritance chain).

I believe the mechanism relies on knowing at compile time what every class 
in the system will be. You don't get the O(1) lookup in Eiffel if you don't 
have the source to all the classes you inherit from when you compile the 
class. You might not even get it if you don't have the source code for those 
classes when you compile the callers, but I'm not sure.

>   I wonder if Eiffel supports this as well.

Eiffel lets you cast up and down the heirarchy. All methods are semantically 
virtual (even if the compiler optimizes them to direct jumps), so the fact 
that you're casting up and down doesn't make it "invalid". You can't cast a 
reference to an object to a type that isn't in that object's parent class 
heirarchy.

There is one class called "ALL" that everyone inherits from. There is one 
class called "NONE" that inherits from everyone, and which has only one 
instance, called "Null". :-) So NULL can cast to any type, and any type can 
cast to "ALL" (which serves as Object).

-- 
Darren New, San Diego CA, USA (PST)
   Yes, we're traveling together,
   but to different destinations.


Post a reply to this message

From: Darren New
Subject: Re: Generics annoyance
Date: 14 Apr 2010 14:21:59
Message: <4bc607c7$1@news.povray.org>
Darren New wrote:
> I think there's a reasonable "ToString()" for every class. 

Oh, and it's definitely helpful to have a class to which everything else can 
be cast. Imagine C if you didn't have the functionality of void*.

-- 
Darren New, San Diego CA, USA (PST)
   Yes, we're traveling together,
   but to different destinations.


Post a reply to this message

From: Warp
Subject: Re: Generics annoyance
Date: 14 Apr 2010 15:37:30
Message: <4bc6197a@news.povray.org>
Darren New <dne### [at] sanrrcom> wrote:
> For something managed, I think that would be the wrong way to implement MI. 
> It's still just one object, even if it inherits data and code from multiple 
> classes.  For example, Python has MI and doesn't have pointers into the 
> middle of objects.

  That sounds like it would be somewhat inefficient. If the pointer always
points to the beginning of the object, then it would always need to resolve
the offset to the members it wants every time it wants to access them
(because in a multiple-inherited object the members of the base class you
want do not necessarily start from the beginning of the object the pointer
is pointing to, but could start from anywhere).

> You could also do it as a sort of "automatic delegation", where each of the 
> multiple parent classes is represented as a separate object on the heap, for 
> example, and the child class delegates all the non-overridden calls to the 
> parent class.

  That sounds like you would need several steps of indirection in order
to access a base class member using a derived class pointer. And checks
for this would need to be done for *all* accesses, even in situations where
there's no inheritance at all (because the code which tries to access the
object through the pointer cannot know if the object it was given was a
derived object or not, without always checking).

> The only reason C++ carries pointers to the middle of objects (as far as I 
> can tell) is that they can't rewrite the object code to use different 
> offsets in the child class compared to the parent class, and of course 
> because it can since there's no memory compaction.

  It's more efficient when code which handles objects of a certain type
doesn't need to perform any checks to see if the object is really of that
precise type, or whether it's some inherited type. From the point of view
of that code the object looks exactly like if it was exactly of that
precise type (all the member offsets are always the same) regardless of
what the actual type of the object is.

  (Things like virtual inheritance can complicate this a bit, though.)

> Probably right after the folks working on Java do. ;-)

  Well, the Java people added their crippled version of templates to the
language regardless of all the arguments why templates are bad, so maybe
there's hope that MI will also be added, regardless of all the arguments
why it's bad.

  (It has always amused me how in the dawn of Java people constantly
preached how Java was like "C++ done right", yet it seems to lack most
things which are *good* and/or useful in C++, like RAII, destructors,
typedefs, enums, templates, multiple inheritance, handling objects by
value, operator overloading and whatnot.)

-- 
                                                          - Warp


Post a reply to this message

From: Warp
Subject: Re: Generics annoyance
Date: 14 Apr 2010 15:38:38
Message: <4bc619be@news.povray.org>
Darren New <dne### [at] sanrrcom> wrote:
> Darren New wrote:
> > I think there's a reasonable "ToString()" for every class. 

> Oh, and it's definitely helpful to have a class to which everything else can 
> be cast. Imagine C if you didn't have the functionality of void*.

  It's useful mostly if you have some way of casting back to the original
type.

-- 
                                                          - Warp


Post a reply to this message

From: Warp
Subject: Re: Generics annoyance
Date: 14 Apr 2010 15:43:09
Message: <4bc61acd@news.povray.org>
Darren New <dne### [at] sanrrcom> wrote:
> Warp wrote:
> > Darren New <dne### [at] sanrrcom> wrote:
> >> That's certainly part of it, but you don't need to support multiple 
> >> inheritance in the same way C++ does it.  Eiffel has multiple inheritance, 
> >> garbage collection, and O(1) virtual dispatch.  (That last would probably be 
> >> quite difficult if you didn't compile everything at the same time, of course.)
> > 
> >   As I have mentioned before, you can cast an object pointer to an
> > incompatible type assuming that:

> Right.  I'm not sure what that had to do with what I was saying.

  Nothing. Not everything has to be a direct answer to what has been written.
It's chatter.

> I believe the mechanism relies on knowing at compile time what every class 
> in the system will be.

  You mean it doesn't support precompiled libraries? (Why does that seem to
be so common with "higher-level" languages?)

> >   I wonder if Eiffel supports this as well.

> Eiffel lets you cast up and down the heirarchy. All methods are semantically 
> virtual (even if the compiler optimizes them to direct jumps), so the fact 
> that you're casting up and down doesn't make it "invalid". You can't cast a 
> reference to an object to a type that isn't in that object's parent class 
> heirarchy.

  Does that mean "no"?

  Note that in the case I was talking about you are not casting only up or
only down in the hierarchy. You are actually casting down and then up in one
go (in a multiple inheritance situation), without seeing any of the
intermediate classes directly.

-- 
                                                          - Warp


Post a reply to this message

From: Darren New
Subject: Re: Generics annoyance
Date: 14 Apr 2010 16:35:11
Message: <4bc626ff$1@news.povray.org>
Warp wrote:
>   It's useful mostly if you have some way of casting back to the original
> type.

Exactly. In languages where everything comes from Object, they're usually 
either dynamically typed or they have the equivalent of dynamic_cast<>. 
Otherwise, it wouldn't really be useful.  Handy when you want to do 
something like "Print this array of objects with that string as the format 
specifier" a la printf.

-- 
Darren New, San Diego CA, USA (PST)
   Yes, we're traveling together,
   but to different destinations.


Post a reply to this message

From: Darren New
Subject: Re: Generics annoyance
Date: 14 Apr 2010 16:41:33
Message: <4bc6287d$1@news.povray.org>
Warp wrote:
> Darren New <dne### [at] sanrrcom> wrote:
>> For something managed, I think that would be the wrong way to implement MI. 
>> It's still just one object, even if it inherits data and code from multiple 
>> classes.  For example, Python has MI and doesn't have pointers into the 
>> middle of objects.
> 
>   That sounds like it would be somewhat inefficient. If the pointer always
> points to the beginning of the object, then it would always need to resolve
> the offset to the members it wants every time it wants to access them
> (because in a multiple-inherited object the members of the base class you
> want do not necessarily start from the beginning of the object the pointer
> is pointing to, but could start from anywhere).

Yep. Python is very dynamic.  You can, for example, turn
   xyz.pdq = 5
into a function call on xyz that passes the string "pdq" as the first 
argument and 5 as the second.  It's not supposed to be efficient. It's 
supposed to be expressive. :-)

>> You could also do it as a sort of "automatic delegation", where each of the 
>> multiple parent classes is represented as a separate object on the heap, for 
>> example, and the child class delegates all the non-overridden calls to the 
>> parent class.
> 
>   That sounds like you would need several steps of indirection in order
> to access a base class member using a derived class pointer. 

Yep. Either that or, as I said, have the JIT do it the first time.

> And checks
> for this would need to be done for *all* accesses, even in situations where
> there's no inheritance at all (because the code which tries to access the
> object through the pointer cannot know if the object it was given was a
> derived object or not, without always checking).

Well, what I meant was that if you have Alpha::Hello() and Beta::There() and 
you create a Gamma that inherits from both, you could actually copy the code 
of Alpha::Hello and Beta::There into Gamma, adjusting the offsets of local 
variables as you go. With clever vtable layout, you could have Alpha::Hello 
and Gamma::Hello at the same offset in the vtable, and the same with 
Beta:There and Gamma::There.  (That's what Meyer invented for Eiffel.)

>   It's more efficient when code which handles objects of a certain type
> doesn't need to perform any checks to see if the object is really of that
> precise type, or whether it's some inherited type. From the point of view
> of that code the object looks exactly like if it was exactly of that
> precise type (all the member offsets are always the same) regardless of
> what the actual type of the object is.

Yes. But that's not really the problem. The problem is that it's *machine* 
code you're dealing with in C++, where all the information about what local 
variables you're using has been lost.  In the CIL, I have no trouble taking 
a method and making every reference to "the first member variable" and 
changing it to "the third member variable". And then you JIT that and you 
get equally efficient code.

>   Well, the Java people added their crippled version of templates to the
> language regardless of all the arguments why templates are bad, so maybe
> there's hope that MI will also be added, regardless of all the arguments
> why it's bad.

Well, not templates as such. Nothing near as useful. Just generics, using 
the same awful C++ syntax. :-)

>   (It has always amused me how in the dawn of Java people constantly
> preached how Java was like "C++ done right", yet it seems to lack most
> things which are *good* and/or useful in C++, like RAII, destructors,
> typedefs, enums, templates, multiple inheritance, handling objects by
> value, operator overloading and whatnot.)

Yep.  Altho I never heard it as "C++ done right", but usually "C++ done 
better." :-)

-- 
Darren New, San Diego CA, USA (PST)
   Yes, we're traveling together,
   but to different destinations.


Post a reply to this message

From: Darren New
Subject: Re: Generics annoyance
Date: 14 Apr 2010 16:45:52
Message: <4bc62980$1@news.povray.org>
Warp wrote:
> Darren New <dne### [at] sanrrcom> wrote:
>> Warp wrote:
>>> Darren New <dne### [at] sanrrcom> wrote:
>>>> That's certainly part of it, but you don't need to support multiple 
>>>> inheritance in the same way C++ does it.  Eiffel has multiple inheritance, 
>>>> garbage collection, and O(1) virtual dispatch.  (That last would probably be 
>>>> quite difficult if you didn't compile everything at the same time, of course.)
>>>   As I have mentioned before, you can cast an object pointer to an
>>> incompatible type assuming that:
> 
>> Right.  I'm not sure what that had to do with what I was saying.
> 
>   Nothing. Not everything has to be a direct answer to what has been written.
> It's chatter.

OK. Just checking. :-)

>> I believe the mechanism relies on knowing at compile time what every class 
>> in the system will be.
> 
>   You mean it doesn't support precompiled libraries? (Why does that seem to
> be so common with "higher-level" languages?)

It does, but I think you need more than just the object code in there. Kind 
of like the way C# is "precompiled" I guess. I'm not sure of the actual 
implementation details.

And it's not like C++ supports precompiled templates, either. :-)

> 
>>>   I wonder if Eiffel supports this as well.
> 
>> Eiffel lets you cast up and down the heirarchy. All methods are semantically 
>> virtual (even if the compiler optimizes them to direct jumps), so the fact 
>> that you're casting up and down doesn't make it "invalid". You can't cast a 
>> reference to an object to a type that isn't in that object's parent class 
>> heirarchy.
> 
>   Does that mean "no"?

I wasn't 100% sure what the "this" was.

>   Note that in the case I was talking about you are not casting only up or
> only down in the hierarchy. You are actually casting down and then up in one
> go (in a multiple inheritance situation), without seeing any of the
> intermediate classes directly.

Oh. Honestly, I'm not so up on Eiffel I could answer that without looking it 
up. But I would suspect not. I mean, if you have Gamma inherit from Alpha 
and Beta, and you have a variable declared as Beta and you want to assign it 
to a variable of type Alpha, while you could get Gamma to do that, I don't 
think you could compile that without first casting the Beta to a Gamma or 
something. I really don't know, honestly.

-- 
Darren New, San Diego CA, USA (PST)
   Yes, we're traveling together,
   but to different destinations.


Post a reply to this message

From: Warp
Subject: Re: Generics annoyance
Date: 15 Apr 2010 05:39:17
Message: <4bc6dec4@news.povray.org>
Darren New <dne### [at] sanrrcom> wrote:
> >   That sounds like you would need several steps of indirection in order
> > to access a base class member using a derived class pointer. 

> Yep. Either that or, as I said, have the JIT do it the first time.

  JIT-compiling can't help if the *same* code has to handle objects of
different types.

> > And checks
> > for this would need to be done for *all* accesses, even in situations where
> > there's no inheritance at all (because the code which tries to access the
> > object through the pointer cannot know if the object it was given was a
> > derived object or not, without always checking).

> Well, what I meant was that if you have Alpha::Hello() and Beta::There() and 
> you create a Gamma that inherits from both, you could actually copy the code 
> of Alpha::Hello and Beta::There into Gamma, adjusting the offsets of local 
> variables as you go. With clever vtable layout, you could have Alpha::Hello 
> and Gamma::Hello at the same offset in the vtable, and the same with 
> Beta:There and Gamma::There.  (That's what Meyer invented for Eiffel.)

  Wouldn't that be difficult to do if Alpha and Beta are precompiled?

> >   Well, the Java people added their crippled version of templates to the
> > language regardless of all the arguments why templates are bad, so maybe
> > there's hope that MI will also be added, regardless of all the arguments
> > why it's bad.

> Well, not templates as such. Nothing near as useful. Just generics, using 
> the same awful C++ syntax. :-)

  That's why I said "crippled version of templates".

-- 
                                                          - Warp


Post a reply to this message

From: Warp
Subject: Re: Generics annoyance
Date: 15 Apr 2010 05:47:51
Message: <4bc6e0c6@news.povray.org>
Darren New <dne### [at] sanrrcom> wrote:
> And it's not like C++ supports precompiled templates, either. :-)

  Not to create new code (obviously), but you can precompile explicit
instantiations of template code into a library. If the user is expected
to use only those specific types with the library, then you don't actually
have to provide any code. (You lose the flexibility of templates from the
user's point of view, but you still have the flexiblity from the point of
view of the library developer.)

> > 
> >>>   I wonder if Eiffel supports this as well.
> > 
> >> Eiffel lets you cast up and down the heirarchy. All methods are semantically 
> >> virtual (even if the compiler optimizes them to direct jumps), so the fact 
> >> that you're casting up and down doesn't make it "invalid". You can't cast a 
> >> reference to an object to a type that isn't in that object's parent class 
> >> heirarchy.
> > 
> >   Does that mean "no"?

> I wasn't 100% sure what the "this" was.

  You have two completely unrelated classes A and B (ie. they don't inherit
from each other in any way, or have anything in common), and you can do this:

void foo(A* aPtr)
{
    B* bPtr = dynamic_cast<B*>(aPtr);
    if(bPtr)
        ...
}

  The dynamic_cast will succeed if the object pointed by aPtr is in actuality
of a type which has been multiple-inherited from A and B (even if by a very
long inheritance chain). The foo() function doesn't need to know anything
about that class in question, and can eg. be precompiled into a library.

-- 
                                                          - Warp


Post a reply to this message

From: Darren New
Subject: Re: Generics annoyance
Date: 15 Apr 2010 11:17:45
Message: <4bc72e19$1@news.povray.org>
Warp wrote:
> Darren New <dne### [at] sanrrcom> wrote:
>>>   That sounds like you would need several steps of indirection in order
>>> to access a base class member using a derived class pointer. 
> 
>> Yep. Either that or, as I said, have the JIT do it the first time.
> 
>   JIT-compiling can't help if the *same* code has to handle objects of
> different types.

I'm not sure that's true.

>> Well, what I meant was that if you have Alpha::Hello() and Beta::There() and 
>> you create a Gamma that inherits from both, you could actually copy the code 
>> of Alpha::Hello and Beta::There into Gamma, adjusting the offsets of local 
>> variables as you go. With clever vtable layout, you could have Alpha::Hello 
>> and Gamma::Hello at the same offset in the vtable, and the same with 
>> Beta:There and Gamma::There.  (That's what Meyer invented for Eiffel.)
> 
>   Wouldn't that be difficult to do if Alpha and Beta are precompiled?

To machine code? Yes. That's why I said I thought Eiffel had a hard time 
with that. (Doing that optimization in Eiffel takes minutes, while a quicky 
test compile takes a second or two.)

In CIL? No, not that difficult, because you know what the instructions 
*mean* in the CIL. Rearranging the local variables inside a class compiled 
down to CIL isn't difficult.

>>>   Well, the Java people added their crippled version of templates to the
>>> language regardless of all the arguments why templates are bad, so maybe
>>> there's hope that MI will also be added, regardless of all the arguments
>>> why it's bad.
> 
>> Well, not templates as such. Nothing near as useful. Just generics, using 
>> the same awful C++ syntax. :-)
> 
>   That's why I said "crippled version of templates".

In all honesty, it's a crippled version of generics, let alone templates. 
They didn't even change the class file format to support it. All they did is 
add sugar to do the casting from object back to the real type without you 
having to type it.

-- 
Darren New, San Diego CA, USA (PST)
   Yes, we're traveling together,
   but to different destinations.


Post a reply to this message

From: Darren New
Subject: Re: Generics annoyance
Date: 15 Apr 2010 11:20:16
Message: <4bc72eb0$1@news.povray.org>
Warp wrote:
>   The dynamic_cast will succeed if the object pointed by aPtr is in actuality
> of a type which has been multiple-inherited from A and B (even if by a very
> long inheritance chain). The foo() function doesn't need to know anything
> about that class in question, and can eg. be precompiled into a library.

That's what I thought you meant. I know you can't do it with a non-dynamic 
cast in Eiffel, but I don't remember if you can do that in one step with a 
dynamic cast. In all honesty, I would expect not. Meyer isn't that sort of 
person. :-)

I can see where that could be handy, and even moreso if it weren't an 
explicit dynamic cast. (I.e., if you could just pass aPtr into a function 
expecting a bPtr and have it work automagically if the actual type inherited 
from both.)

-- 
Darren New, San Diego CA, USA (PST)
   Yes, we're traveling together,
   but to different destinations.


Post a reply to this message

From: scott
Subject: Re: Generics annoyance
Date: 19 Apr 2010 04:26:59
Message: <4bcc13d3$1@news.povray.org>
> In MS's simple game libraries, there's a class called GameComponent.
> It inherits from IUpdatable, IDrawable, and IMumble, each of which 
> provides the declaration of one of the main routines in a game (update, 
> draw, and initialize, respectively).
>
> Now, if I wanted (and I do) to make a collection of things that act like 
> GameComponent objects but aren't necessarily game components, I don't 
> think I can do that in C#. I would have to have a collection parameterized 
> on all three of those interfaces.

If you cannot (or don't want to) derive your custom class(es) from 
GameComponent then the common base class will be System.Object.  You then 
have to make a collection of these if you want to store both GameComponent 
and your custom class, eg:

List<Object> myList;
...
foreach( Object o in myList )
 if( o is IUpdatable )
    (o as IUpdatable).Update();

> In any case, it's rather annoying. :-) I might have to figure out how to 
> patch up MS's samples to also host a collection of game components as well 
> as the scene-activation/deactivation they do.

Yeh, I think the XNA management classes are only meant to be simple ones to 
get you started, most things I've read advocate replacing the whole 
GameComponent system with your own (usually based on "screens" and adding 
components to each "screen").


Post a reply to this message

From: Darren New
Subject: Re: Generics annoyance
Date: 19 Apr 2010 12:29:56
Message: <4bcc8504$1@news.povray.org>
scott wrote:
> foreach( Object o in myList )
> if( o is IUpdatable )
>    (o as IUpdatable).Update();

That was the conclusion I came to.

> Yeh, I think the XNA management classes are only meant to be simple ones 
> to get you started, most things I've read advocate replacing the whole 
> GameComponent system with your own (usually based on "screens" and 
> adding components to each "screen").

Yes, I'm taking their samples and making them reusable now. It seems the 
whole "component" idea that was touted in XNA2 kind of never really 
materialized in XNA3. Now "components" in their samples are more like 
"screen management component" and "audio management component" rather than 
"make the camera bob when you walk" component or "explosion component".

-- 
Darren New, San Diego CA, USA (PST)
   Linux: Now bringing the quality and usability of
   open source desktop apps to your personal electronics.


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.