How to avoid casting horror with non-generic class derived fromgeneric class

J

John Rivers

I have had to write this monstrosity
as a convenience method because of casting horror

public bool Enumerate(ref GameElement input) {
CubeSpace3.ListElement<GameObject> flip = input;
bool output = base.Enumerate(ref flip);
input = (GameElement)flip;
return output;
}//method

not only does it require two casts but a reference copy as well

this is Enumerate()

public virtual bool Enumerate(ref ListElement<T> input) {
if (input == null) {
input = this.First;
} else {
input = input.Next;
}//if
return input != null;
}//method

which is a convenience method in a generic<T> linked list root class

and GameElement is defined as:

public abstract class GameElement<T> : ListElement<T> {}

(with bits removed)

it would almost be easier to re-implement the base method :-(
 
P

Peter Duniho

John said:
I have had to write this monstrosity
as a convenience method because of casting horror

public bool Enumerate(ref GameElement input) {
CubeSpace3.ListElement<GameObject> flip = input;
bool output = base.Enumerate(ref flip);
input = (GameElement)flip;
return output;
}//method

not only does it require two casts but a reference copy as well

Doubtful. You can look at the JITted code to confirm if you like, but I
doubt in an optimized build, the first reference copy happens, nor the
first implicit cast (because it can be verified at compile-time).

You do have the cast before the return, but that's unavoidable given
what you're trying to do.

That said, generally speaking, that sort of casting isn't guaranteed to
be valid. It's not really clear from your post what a "GameElement" is
(you only mention a "GameElement<T>", and don't offer any information on
what's used for the type parameter, nor what an undecorated
"GameElement" might be), but a method that is free to return any
ListElement<T> may in fact not return a GameElement<T>, nor a
GameElement (whatever that might be).

It's possible, should you care to provide a concise-but-complete code
example that unambiguously shows exactly what you're really trying to
accomplish, a more elegant solution can be provided.

Of course, I'm assuming that's the point of your post: that you are
asking how a more elegant solution can be made. If not, then I suppose
you ought to be clearer about what your question is, exactly. :)

Pete
 
J

John Rivers

here is GameElement

public class GameElement : CubeSpace3.GameElement<GameObject>

I think my question is:

when you derive from a base class
and arguments of the overridden methods should also "follow" the
derived class in some way

so where the base class implemented:

bool Enumerate(ref BaseType)

in the derived class I would want:

bool Enumerate(ref DerivedType)

how can I:

1) (ideal) not have to overload the method and not have clients of the
class go through casting hell
2) (second best) overload the method without that horrible double cast
and copy?

it seems I am writing quite a lot of code just to make using my
derived classes simple and readable etc.

is that the price I have to pay?
 
P

Peter Duniho

John said:
here is GameElement

public class GameElement : CubeSpace3.GameElement<GameObject>

I think my question is:

when you derive from a base class
and arguments of the overridden methods should also "follow" the
derived class in some way

That's a statement, not a question. And if you are asking how to
accomplish the statement, you'll have to be more specific about what you
mean by "in some way" and why this is important.
so where the base class implemented:

bool Enumerate(ref BaseType)

in the derived class I would want:

bool Enumerate(ref DerivedType)

how can I:

1) (ideal) not have to overload the method and not have clients of the
class go through casting hell

First you need to explain why it is your clients of the code do need to
"go through casting hell". Explain it using specific, technical
language, not ambiguous, imprecise language.
2) (second best) overload the method without that horrible double cast
and copy?

it seems I am writing quite a lot of code just to make using my
derived classes simple and readable etc.

is that the price I have to pay?

To write code that's awkward? Yes. There's a price to pay for that.

Without a proper code example, it's not possible to know for sure. But
it actually seems to me you have two different problems: the question of
inheritance, and the question of generic variance.

The former is simpler, so I'll focus on that. And specifically, you
seem to want to override a base class virtual method using a type
different from that used in the base class.

The reason that's awkward is that it completely side-steps and ignores
the point of having a virtual method: to allow for polymorphic behavior.

Polymorphism is useful when you only need to know the base type, and can
successfully use it without referring to the actual derived type. As
soon as you insert into your code some dependency on the actual derived
type, the polymorphism becomes pointless.

Generics offer a different kind of "polymorphism" in that rather than
inheriting a class, you simply get a different class or method depending
on one or more types. This allows for a common implementation to be
shared among pieces of code that vary only according to the type
parameter for the generic code.

In the same way that having virtual method usages depend on the
inherited type is awkward and pointless, so too is having generic code
that depend specifically on the type parameter. Once you start
special-casing type parameters, you might as well make the code non-generic.

There are some exceptions to this, especially in the case of generics
(where you can still leave nearly all the code substantially the same,
having a special-case section only for a very specific and unusual
case). But even there, the exceptions always beg the question: why are
you using virtual methods or generics when the code would work better
without them?

Basically: your question has the form of "I have decided on a particular
implementation, and I want to force this implementation to work".
Whereas a better question would have the form "I have this high-level
problem, and I would like an implementation that is better than the one
I have already decided on".

Without knowing exactly what the high-level problem description, the
best anyone can come up with is "yup, that's awkward". You picked the
implementation, now you have to live with it.

Pete
 
J

John Rivers

up until this point the use of generics + virtual methods works very
elegantly

the problem was because I was crossing between ListRoot<T> and
ListElement<T>

I created an IEnumerator<T> and it is all good again
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top