![](/i/fill.gif) |
![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Darren New <dne### [at] san rr com> wrote:
> Warp wrote:
> > Darren New <dne### [at] san rr com> 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
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
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
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp wrote:
> Darren New <dne### [at] san rr com> 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
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp wrote:
> Darren New <dne### [at] san rr com> wrote:
>> Warp wrote:
>>> Darren New <dne### [at] san rr com> 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
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Darren New <dne### [at] san rr com> 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
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Darren New <dne### [at] san rr com> 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
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp wrote:
> Darren New <dne### [at] san rr com> 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
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
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
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
> 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
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
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
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |