overriding method with different return type

Discussion in 'Java' started by Paul J. Lucas, Apr 10, 2004.

  1. A given class Base has an nested class ParamBlock. Another class, Derived,
    derived from Base also has a nested class ParamBlock. Derived's ParamBlock
    is derived from Base's ParamBlock. In code:

    class Base {
    protected static class ParamBlock { /* ... */ }

    protected Base( ParamBlock pb ) {
    paramBlock_ = pb;
    }

    public ParamBlock param() {
    return paramBlock_;
    }

    protected ParamBlock paramBlock_;
    }

    class Derived extends Base {
    protected static class ParamBlock extends Base.ParamBlock {
    int value;
    protected ParamBlock( int v ) {
    value = v;
    }
    }

    Derived( int value ) {
    super( new ParamBlock( value ) );
    }

    public ParamBlock param() { // illegal: wants Base.ParamBlock
    return (ParamBlock)paramBlock_;
    }
    }

    public class Test {
    public static void main( String args[] ) {
    Derived d = new Derived( 42 );
    System.out.println( d.param().value );
    }
    }

    I want Base's param() to return a reference to Base.ParamBlock and Derived's
    param() to return a reference to Derived.ParamBlock. I am NOT looking for
    polymorphism. If I call param() on an instance of a Base, I want
    Base.ParamBlock; if I call param() on an instance of a Derived, I want
    Derived.ParamBlock; that's it.

    However, altering the return type of an inherited method in Java is illegal.
    The equivalent code in C++ (below) is perfectly legal since param() isn't
    virtual.

    How can I get what I want in Java? I tried declaring param() final but that
    didn't work.

    - Paul

    P.S.: Here is the equivalent (and legal) C++ code:

    class Base {
    protected:
    class ParamBlock { /* ... */ };

    Base( ParamBlock *pb ) : paramBlock_( pb ) {
    }

    ParamBlock *const paramBlock_;
    public:
    ParamBlock* param() const {
    return paramBlock_;
    }
    };

    class Derived : public Base {
    protected:
    class ParamBlock : public Base::paramBlock {
    public:
    int value;

    ParamBlock( int v ) : value( v ) {
    }
    };
    public:
    Derived( int value ) : Base( new ParamBlock( value ) ) {
    }

    ParamBlock* param() const {
    return static_cast<ParamBlock*>( paramBlock_ );
    }
    };

    int main() {
    Derived d( 42 );
    int i = d.param()->value;
    return 0;
    }
     
    Paul J. Lucas, Apr 10, 2004
    #1
    1. Advertising

  2. Paul J. Lucas

    fox_fire Guest

    The reason Java is this way is because client classes that don't know a
    Base is a true Base or just a Derived in a Base reference. They might call
    param thinking to get a Base.paramBlock back and get a
    Derived.paramBlock.

    It looks like you tried to rename the Derived's inner class to the same
    name as the Base's inner class in order to get it to work. You are
    avoiding the bigger problem. You can't use a method of your superclass and
    throw out some garbage that client's don't expect. If you want to return
    an object of Derived's inner class, give the method a different name.
     
    fox_fire, Apr 11, 2004
    #2
    1. Advertising

  3. fox_fire <> wrote:
    > The reason Java is this way is because client classes that don't know a
    > Base is a true Base or just a Derived in a Base reference. They might call
    > param thinking to get a Base.paramBlock back and get a
    > Derived.paramBlock.


    It doesn't matter since a Derived.ParamBlock is-a Base.ParamBlock.

    > It looks like you tried to rename the Derived's inner class to the same
    > name as the Base's inner class in order to get it to work.


    That fact is actually irrelevant. I did it for consistency.
    I'm writing a compiler that emits Java code.

    > You are avoiding the bigger problem. You can't use a method of your
    > superclass and throw out some garbage that client's don't expect.


    I'm not doing that. There is no garbage. There is no way for
    anything "bad" to happen. Again, equivalent code in C++ is
    legal (and rightly so). Java is just being overly picky.

    > If you want to return an object of Derived's inner class, give the method a
    > different name.


    That's problematic for users of my compiler. I want users to
    be able to say:

    alpha.param().value

    or:

    beta.param().value

    and not either of:

    alpha.alphaParam().value
    beta.betaParam().value

    Both of those are needlessly verbose.

    - Paul
     
    Paul J. Lucas, Apr 11, 2004
    #3
  4. Paul J. Lucas

    Chris Uppal Guest

    Paul J. Lucas wrote:

    > I want Base's param() to return a reference to Base.ParamBlock and
    > Derived's param() to return a reference to Derived.ParamBlock.


    That will be legal in 1.5 (you can try out the beta to confirm).

    Be aware, however, that it is not implemented only by "relaxing" the rules of
    the language (since the JVM doesn't support the change), but by making the Java
    compiler automatically emit forwarding methods.

    -- chris
     
    Chris Uppal, Apr 11, 2004
    #4
  5. Chris Uppal <-this.org> wrote:
    > Paul J. Lucas wrote:
    >
    >> I want Base's param() to return a reference to Base.ParamBlock and
    >> Derived's param() to return a reference to Derived.ParamBlock.

    >
    > That will be legal in 1.5 (you can try out the beta to confirm).


    About time.

    > Be aware, however, that it is not implemented only by "relaxing" the rules of
    > the language (since the JVM doesn't support the change)


    What the JVM does or does not support is irrelevant as far as
    "relaxing" goes. As a user of Java, I couldn't care less that
    Java just so happens to use a JVM on most implementations. An
    implementation of Java can choose to compile directly to
    machine code (e.g., gcj). From a pure Java language point of
    view, the JVM is, again, irrelevant.

    > but by making the Java compiler automatically emit forwarding methods.


    That shouldn't be necessary. In C++, when a non-virtual
    function in a derived class with the same name as one in a base
    class whose signature (including return-type) does not match
    that of the base, it "shadows" the one in the base making it as
    if it has a different name entirely.

    I don't see why what would require a change in the JVM since
    all the compiler has to do is internally mangle the name.

    - Paul
     
    Paul J. Lucas, Apr 11, 2004
    #5
  6. Paul J. Lucas

    Chris Uppal Guest

    Paul J. Lucas wrote:

    > As a user of Java, I couldn't care less that
    > Java just so happens to use a JVM on most implementations.


    <shrug/> Your loss. Most of Java (the platform)'s more interesting features
    are crucially dependant on, and defined by, the JVM.

    -- chris
     
    Chris Uppal, Apr 12, 2004
    #6
    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. Pradeep Kumar
    Replies:
    29
    Views:
    1,053
    Dale King
    Apr 15, 2006
  2. sandy
    Replies:
    3
    Views:
    13,926
    Roedy Green
    Nov 15, 2005
  3. ctor
    Replies:
    13
    Views:
    589
    Howard
    Mar 9, 2006
  4. Koszalek Opalek

    Overriding a class method with an object method

    Koszalek Opalek, Jul 2, 2007, in forum: Perl Misc
    Replies:
    8
    Views:
    156
    -berlin.de
    Jul 6, 2007
  5. Marco Buttu
    Replies:
    3
    Views:
    149
    Marco Buttu
    Oct 7, 2013
Loading...

Share This Page