Base class - Derived class interaction question

D

Daniel

I think my question is best posed by the code:

class Base<Q extends Quantity>{
private int _val = 0;
public Base(int val){
_val = val;
}
public Base<Q> plus(Base<Q> b){
return new Base<Q>(_val + b._val);
}
}

class Derived1 extends Base<A> { //class A extends Quantity
public Derived1(int val){ super(val);}
}

(I don't believe the generics are relative to my question, but I'm
using them to keep in parallel with my real-world problem.)

I want to be able to do something like the following,
...
Derived1 billy = new Derived1(5);
Derived1 bob = new Derived1(6);
Derived1 billyPlusBob = (Derived1)billy.plus(bob); //
billyPlusBob._val is 11 (if you could access it)
...
I understand this is nonsense because the billy.plus call is returning
a reference of type Base<A> which is obviously not type Derived1,
which is why I would get a ClassCastException when trying to cast the
result of billy.plus(bob) to Derived1.

What's stumping me is why I can't figure out how to accomplish the
seemingly trivial task of putting the 'plus' logic in the base class
so that I don't have to implement it in each derived class. What's
throwing me off is that the plus method has to return a reference of
the _derived_ type, which is seemingly impossible if I'm implementing
the method in the base class. I'd really, really like to avoid having
to push down the plus method (b/c in reality there are many more
'plus'-like methods and many, many derived classes all of whose logic
is the same), but I absolutely need it to return a reference of the
derived type (or at least one that could be cast to the derived type).

Anybody ever had the same problem? Any suggestions/insights?
 
C

Chrisie

What I'm saying may be complete nonsense but couldn't you write a
static method in each one of the derived classes that takes an object
of the base class and turns it into an object of the derived class? I
guess this is actually a way of working around the problem rather than
solving it but I can't think of any other more intelligent solution.
 
P

Patricia Shanahan

Daniel said:
I think my question is best posed by the code:

class Base<Q extends Quantity>{
private int _val = 0;
public Base(int val){
_val = val;
}
public Base<Q> plus(Base<Q> b){
return new Base<Q>(_val + b._val);
}
}

class Derived1 extends Base<A> { //class A extends Quantity
public Derived1(int val){ super(val);}
}

(I don't believe the generics are relative to my question, but I'm
using them to keep in parallel with my real-world problem.)

I want to be able to do something like the following,
...
Derived1 billy = new Derived1(5);
Derived1 bob = new Derived1(6);
Derived1 billyPlusBob = (Derived1)billy.plus(bob); //
billyPlusBob._val is 11 (if you could access it)
...
I understand this is nonsense because the billy.plus call is returning
a reference of type Base<A> which is obviously not type Derived1,
which is why I would get a ClassCastException when trying to cast the
result of billy.plus(bob) to Derived1.

What's stumping me is why I can't figure out how to accomplish the
seemingly trivial task of putting the 'plus' logic in the base class
so that I don't have to implement it in each derived class. What's
throwing me off is that the plus method has to return a reference of
the _derived_ type, which is seemingly impossible if I'm implementing
the method in the base class. I'd really, really like to avoid having
to push down the plus method (b/c in reality there are many more
'plus'-like methods and many, many derived classes all of whose logic
is the same), but I absolutely need it to return a reference of the
derived type (or at least one that could be cast to the derived type).

Anybody ever had the same problem? Any suggestions/insights?

A high level design comment. If you have a very large number of
different classes that all have the same logic, it is possible that you
are using object class to represent some attribute that might be better
represented in a field or as generic information.

I can see ways of dealing with this using reflection, and a method that
is defined to return a new instance whose class is the same as this with
a specified value. Maybe there is something smoother using generics?

Patricia
 
L

Lew

A small side point not pertaining to your main question:

You do not need to initialize _val twice. The initialization to zero is
completely redundant - if you wanted zero Java would've given it to you
without the explicit initialization, but you don't even want zero, you want
the val argument. So don't initialize the member variable to zero.

-- Lew
 
C

Chris Uppal

Daniel said:
What's
throwing me off is that the plus method has to return a reference of
the _derived_ type, which is seemingly impossible if I'm implementing
the method in the base class.

If you think about it you'll see that this is impossible. You want to do two
incompatible things at once

- inherit the code from the superclass

- have that inherited code do something different

There /are/ languages which work like that (where inherited stuff is not merely
inherited but redefined in the subclass), but Java doesn't have the right kind
of type system for that.

The real problem is that the code which creates a new instance does not refer
to the (runtime) class of "this" but the compile-time class where the code is
defined. Since constructors don't inherit it follows that if you want do this
at all (in Java) you /cannot/ use an explicit constructor in the shared code.
(One more example of how explicit constructors cause fragility.)

Following that thought, the nearest you can get is by refactoring to split the
creation of the new object into something that the subclass can override. For
instance, you could make use of the built-in clone() operation, like:

class Base
implements Cloneable
{
Base plus(Base operand)
{
// idiotic try/catch elided for clarity
Base retval = (Base)(this.clone());
retval.value += operand.value;
return retval;
}
}

And then, in the subclass you can override add() to return a Derived, if you
want:

class Derived
extends Base
{
Derived plus(Base operand)
{
return (Derived)(super.plus(operand));
}
}

-- chris
 
D

Daniel

If you think about it you'll see that this is impossible. You want to do two
incompatible things at once

- inherit the code from the superclass

- have that inherited code do something different

There /are/ languages which work like that (where inherited stuff is not merely
inherited but redefined in the subclass), but Java doesn't have the right kind
of type system for that.

The real problem is that the code which creates a new instance does not refer
to the (runtime) class of "this" but the compile-time class where the code is
defined. Since constructors don't inherit it follows that if you want do this
at all (in Java) you /cannot/ use an explicit constructor in the shared code.
(One more example of how explicit constructors cause fragility.)

Following that thought, the nearest you can get is by refactoring to split the
creation of the new object into something that the subclass can override. For
instance, you could make use of the built-in clone() operation, like:

class Base
implements Cloneable
{
Base plus(Base operand)
{
// idiotic try/catch elided for clarity
Base retval = (Base)(this.clone());
retval.value += operand.value;
return retval;
}
}

And then, in the subclass you can override add() to return a Derived, if you
want:

class Derived
extends Base
{
Derived plus(Base operand)
{
return (Derived)(super.plus(operand));
}
}

-- chris

Thanks for the ideas. I like the idea of assigning the object
creation to a construct that can pick the appropriate constructor at
runtime (like the clone method) as oppose to to using the constructor,
which, as Chris pointed out, is doomed to use the base class code even
if the calling instance is of derived type.

I would still be interested as to whether there are any design
patterns or generics tricks that I could use to accomplish similar
means without having to change or add any code to the derived classes
at all. Not an urgent request or anything, just curious (not that it
being urgent would change things from other posters' POVs :)).

I appreciate everyone's help!

- Daniel
 
P

Piotr Kobzda

Daniel said:
Any suggestions/insights?

Try the following:

abstract class Base<T extends Base<T, Q>, Q extends Quantity> {
protected int value;

public Base(int value) {
this.value = value;
}

protected abstract T newInstance(int value);

public T plus(T b) {
return newInstance(value + b.value);
}
}

class Derived1 extends Base<Derived1, A> {
public Derived1(int value) {
super(value);
}

protected Derived1 newInstance(int value) {
return new Derived1(value);
}
}


piotr
 
D

Daniel

Try the following:

abstract class Base<T extends Base<T, Q>, Q extends Quantity> {
protected int value;

public Base(int value) {
this.value = value;
}

protected abstract T newInstance(int value);

public T plus(T b) {
return newInstance(value + b.value);
}
}

class Derived1 extends Base<Derived1, A> {
public Derived1(int value) {
super(value);
}

protected Derived1 newInstance(int value) {
return new Derived1(value);
}
}

piotr

Awesome. I'm not sure I understand exactly why that works but I know
some good Generics sources I can consult first. Thanks.
 

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

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top