Base class - Derived class interaction question

Discussion in 'Java' started by Daniel, Mar 11, 2007.

  1. Daniel

    Daniel Guest

    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?
     
    Daniel, Mar 11, 2007
    #1
    1. Advertising

  2. Daniel

    Chrisie Guest

    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.
     
    Chrisie, Mar 11, 2007
    #2
    1. Advertising

  3. Daniel wrote:
    > 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
     
    Patricia Shanahan, Mar 11, 2007
    #3
  4. Daniel

    Lew Guest

    Daniel wrote:
    >> 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;
    >> }


    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
     
    Lew, Mar 11, 2007
    #4
  5. Daniel

    Chris Uppal Guest

    Daniel wrote:

    > 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
     
    Chris Uppal, Mar 11, 2007
    #5
  6. Daniel

    Daniel Guest

    On Mar 11, 9:59 am, "Chris Uppal" <-
    THIS.org> wrote:
    > Daniel wrote:
    > > 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


    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
     
    Daniel, Mar 11, 2007
    #6
  7. Daniel

    Piotr Kobzda Guest

    Daniel wrote:

    > 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
     
    Piotr Kobzda, Mar 12, 2007
    #7
  8. Daniel

    Daniel Guest

    On Mar 12, 1:38 am, Piotr Kobzda <> wrote:
    > Daniel wrote:
    > > 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


    Awesome. I'm not sure I understand exactly why that works but I know
    some good Generics sources I can consult first. Thanks.
     
    Daniel, Mar 13, 2007
    #8
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. qazmlp
    Replies:
    1
    Views:
    590
    qazmlp
    Apr 10, 2005
  2. Replies:
    4
    Views:
    436
    Alf P. Steinbach
    May 23, 2007
  3. Replies:
    1
    Views:
    419
    myork
    May 23, 2007
  4. Replies:
    1
    Views:
    405
    Victor Bazarov
    May 23, 2007
  5. Replies:
    2
    Views:
    745
Loading...

Share This Page