Decorators v Inheritance: Forcing subclass to call super() ?

Discussion in 'Java' started by Michael Strorm, Apr 17, 2005.

  1. Hi,

    I have some classes that are designed such that the subclass
    implementations of foo() *must* call the super class implementation of
    foo().

    What is the best way of forcing this? I read somewhere that this is
    poor design; but constructors not only allow it, they *require* it!

    One solution I read is to use a decorator class, but this sounds like
    gross overkill, and would probably make things even more error-prone.

    Any thoughts?.. all help appreciated, thanks.

    - MS
     
    Michael Strorm, Apr 17, 2005
    #1
    1. Advertising

  2. (Michael Strorm) writes:

    > I have some classes that are designed such that the subclass
    > implementations of foo() *must* call the super class implementation of
    > foo().


    This cannot be enforced (virtual methods and all that), only
    documented for the developer, with ominous warnings about what would
    happen if the rule isn't followed. Remember to use the terms "warts"
    and "first-born son", they always go well with such things. <g>

    Basically your only option is to make foo() final.

    (I don't know how far they intend to go with 1.5's annotations, but
    this looks like a candidate for an annotation like this:

    @Retention(RetentionPolicy.CLASS)
    @Target(ElementType.METHOD)
    public @interface MustCallSuperMethod {
    }

    This would then be checked by the compiler.

    The problem is that a subclass author could "forget" to add that
    annotation, meaning subclasses one level further down don't have to
    call the superclass method.

    > What is the best way of forcing this? I read somewhere that this is
    > poor design; but constructors not only allow it, they *require* it!


    Constructors are not virtual, and are called in a special way
    (invokespecial instruction) different from other methods
    (invokevirtual, invokestatic). Also, the call to the superclass
    constructor is inserted by the compiler.
     
    Tor Iver Wilhelmsen, Apr 17, 2005
    #2
    1. Advertising

  3. Michael Strorm wrote:
    > What is the best way of forcing this? I read somewhere that this is
    > poor design; but constructors not only allow it, they *require* it!


    Yes, it is bad design, you can't force the use of your class in that
    way. You superclass should be robust, and should work as long as an
    overridden method keeps the contract of the original method. And
    regarding the behavior of constructors, they are not methods.

    You probably have broken up some algorithm in a poor way. So you would
    need to go back a few steps and have a look at what you actually want to do.

    > One solution I read is to use a decorator class, but this sounds like
    > gross overkill, and would probably make things even more error-prone.


    Decorator? Do you need *dynamically* attached additional behavior? If
    not, this is simply the wrong pattern.

    Consider some redesign, using template and hook methods.

    /Thomas
    --
    The comp.lang.java.gui FAQ:
    ftp://ftp.cs.uu.nl/pub/NEWS.ANSWERS/computer-lang/java/gui/faq
     
    Thomas Weidenfeller, Apr 18, 2005
    #3
  4. Thomas Weidenfeller <> wrote in message news:<d3vmah$emm$>...
    > Michael Strorm wrote:
    > > What is the best way of forcing this? I read somewhere that this is
    > > poor design; but constructors not only allow it, they *require* it!

    >
    > Yes, it is bad design, you can't force the use of your class in that
    > way.


    I guessed that much; but if it were possible, would it be a good idea
    to use the feature?

    > You superclass should be robust, and should work as long as an
    > overridden method keeps the contract of the original method.


    That's a good point, but consider this; for the overridden method to
    keep the contract of the original method would either require lots of
    cut-and-paste code from the original, or calling the super method
    anyway.

    > You probably have broken up some algorithm in a poor way. So you would
    > need to go back a few steps and have a look at what you actually want to do.


    It's a tree check. All nodes need to check themselves and their
    parent; non-leaf nodes are subclassed, and need to check their
    children recursively. The solution is to either C&P or to call the
    super() method.

    > > One solution I read is to use a decorator class, but this sounds like
    > > gross overkill, and would probably make things even more error-prone.

    >
    > Decorator? Do you need *dynamically* attached additional behavior? If
    > not, this is simply the wrong pattern.


    I don't remember what this was; I thought about this having posted the
    message, and it does seem a bit weird.

    - MS
     
    Michael Strorm, Apr 18, 2005
    #4
  5. Tor Iver Wilhelmsen <> wrote in message news:<>...
    > (Michael Strorm) writes:
    >
    > > I have some classes that are designed such that the subclass
    > > implementations of foo() *must* call the super class implementation of
    > > foo().

    >
    >
    > Basically your only option is to make foo() final.


    I don't understand how that would force the subclass method
    (Subclass.foo()) to call the super method (super.foo() AKA
    Superclass.foo()). If you're suggesting that the subclass would have
    its own, differently-named method (e.g. Subclass.fooExtend()) that
    would call the final super.foo(), then that doesn't work.

    What I want is to use dynamic dispatch to automaticaly call the right
    version of foo(); making foo() final would require either:-

    * lots of un-OO class-checking in Superclass.foo(), *OR*
    * calling different methods depending on the object type; again,
    very non-OO


    > The problem is that a subclass author could "forget" to add that
    > annotation, meaning subclasses one level further down don't have to
    > call the superclass method.


    They could make it recursive? Anyway, I don't know enough about Java
    to say what they should and shouldn't do...

    > Constructors are not virtual, and are called in a special way
    > (invokespecial instruction) different from other methods
    > (invokevirtual, invokestatic). Also, the call to the superclass
    > constructor is inserted by the compiler.


    Any reason the compiler couldn't enforce that super() was called
    somewhere within a given method if it had been marked accordingly?
    That deals with the problem at an early stage in the compilation, and
    the runtime needs know nothing about it.

    - MS
     
    Michael Strorm, Apr 18, 2005
    #5
  6. Michael Strorm

    Virgil Green Guest

    Michael Strorm wrote:
    > Tor Iver Wilhelmsen <> wrote in
    > message news:<>...
    >> (Michael Strorm) writes:
    >>
    >>> I have some classes that are designed such that the subclass
    >>> implementations of foo() *must* call the super class implementation
    >>> of foo().

    >>
    >>
    >> Basically your only option is to make foo() final.

    >
    > I don't understand how that would force the subclass method
    > (Subclass.foo()) to call the super method (super.foo() AKA
    > Superclass.foo()). If you're suggesting that the subclass would have
    > its own, differently-named method (e.g. Subclass.fooExtend()) that
    > would call the final super.foo(), then that doesn't work.


    If the method is final, subclasses can't override it (though they could
    overload it), but the method is available as part of the interface to an
    object of the subclass. This means that any call of the method would
    automatically be a call of the supertype's method.

    > What I want is to use dynamic dispatch to automaticaly call the right
    > version of foo(); making foo() final would require either:-
    >
    > * lots of un-OO class-checking in Superclass.foo(), *OR*
    > * calling different methods depending on the object type; again,
    > very non-OO


    From your suggestion that class-checking would be required, I assume you
    want to force a call to the supertype *and* you want to do additional
    processing that is unique to the subtype. Correct?

    This came to mind, but I haven't thought a lot about it. Perhaps your
    supertype has a public final method that calls an abstract implemention.
    Subclasses would be expected to implement the abstract method, but would not
    be allowed to override the public final method. Code follows, and I'm eager
    to see how it gets picked apart.

    public class TestImpl {

    public static void main(String[] args) {
    BB b = new BB();
    b.mydo();
    }
    }

    abstract class AA {
    public final void mydo() {
    System.out.println("mydo");
    mydoimpl();
    }
    abstract protected void mydoimpl();
    }

    class BB extends AA {
    protected void mydoimpl(){
    System.out.println("mydoimpl");
    }
    }

    Programmers who subclass AA are forced to provide a mydoimpl()
    implementation of some sort. They can't provide a mydo() implementation that
    overrides the superclass (but could overload it).

    The first problem I see is that there is nothing to force the programmer to
    keep the mydoimpl() method protected. They could expose it as public.

    Anyway, that's just what I thought of at the moment.

    --
    Virgil
     
    Virgil Green, Apr 18, 2005
    #6
  7. Michael Strorm

    P.Hill Guest

    Michael Strorm wrote:
    > It's a tree check. All nodes need to check themselves and their
    > parent; non-leaf nodes are subclassed, and need to check their
    > children recursively. The solution is to either C&P or to call the
    > super() method.


    It seems to me that Virgil Green's solution of
    (1) make the primary method final,
    but
    (2) having an extra place to add some more functionality,
    goes very well in this case.

    final boolean checkFamilyTree() {
    checkSelf();
    result = checkMother();
    if ( result == false ) return result;
    return checkChildren();
    }

    /**
    * ONLY OVERRIDE THIS METHOD IF WORKING WITH POLYGAMIST FAMILIES :)
    */
    boolean checkMother() {
    mother.checkSelf();
    }

    /**
    * Override this method when you have something to do further down the
    tree.
    * the default implementation does nothing and assume all is well.
    */
    boolean checkChildren() {
    return true;
    }

    But given all that, isn't checking down and up at each node
    redundant? If you check mom as a child of grandma, then
    check grandma, mom and child when checking mom,
    then check mom as the parent of child, then child, you've
    checked mom THREEE times.

    Also, why do I need multiple types in a tree, I certainly
    have done these kind of things with a little salting of non-OO
    and have one type with potential for NULL

    boolean checkMom() {
    // no problem, if no mother, aka the root node.
    if (mother == null) return true;
    mother.checkSelf();
    }

    boolean checkChildren() {
    if (children == null ) return true;
    Iterator iChild = children.iterator();
    while ...
    }

    Not so ugly is it?

    -Paul
     
    P.Hill, Apr 18, 2005
    #7
  8. Michael Strorm

    Dale King Guest

    Tor Iver Wilhelmsen wrote:
    > (Michael Strorm) writes:
    >
    >
    >>I have some classes that are designed such that the subclass
    >>implementations of foo() *must* call the super class implementation of
    >>foo().

    >
    >
    > This cannot be enforced (virtual methods and all that), only
    > documented for the developer, with ominous warnings about what would
    > happen if the rule isn't followed. Remember to use the terms "warts"
    > and "first-born son", they always go well with such things. <g>
    >
    > Basically your only option is to make foo() final.
    >
    > (I don't know how far they intend to go with 1.5's annotations, but
    > this looks like a candidate for an annotation like this:
    >
    > @Retention(RetentionPolicy.CLASS)
    > @Target(ElementType.METHOD)
    > public @interface MustCallSuperMethod {
    > }
    >
    > This would then be checked by the compiler.
    >
    > The problem is that a subclass author could "forget" to add that
    > annotation, meaning subclasses one level further down don't have to
    > call the superclass method.


    You could make it inherited, but the bigger issue is that it is too easy
    to violate this. Would the following code pass the compiler:

    if( false )
    {
    super.method();
    }

    It calls the super method but in unreachable code. While it is obvious
    to the compiler that this is unreachable, it is not difficult to make
    code unreachable that the compiler could not figure out.

    So basically we are still at the fact that it is pretty much unenforceable.
     
    Dale King, Apr 19, 2005
    #8
  9. Michael Strorm

    Guest

    Re: Decorators v Inheritance: Forcing subclass to call super() ?

    This basically calls for use of the template method design pattern.

    foo() in the superclass should be final. it's implementation should
    invoke something like
    beforeFoo()
    foo code....
    afterFoo()

    where before and after are the template methods and are designed to be
    overridden. They may be abstract in the superclass.

    the subclass implementation will put all the code that comes before
    calling foo in the before etc.
     
    , Apr 19, 2005
    #9
  10. "P.Hill" <> wrote in message news:<d4167o$nfm$>...

    > It seems to me that Virgil Green's solution of
    > (1) make the primary method final,
    > but
    > (2) having an extra place to add some more functionality,
    > goes very well in this case.


    Mmm... this seems to be creating a growing list of methods as we move
    down the subclasses, each having different names, making OO difficult
    (?)

    > But given all that, isn't checking down and up at each node
    > redundant?


    No, I'm just checking the children and the immediate parent. The check
    was for the integrity of the tree, and only does the immediate parent
    and immediate children for a given node; and this *did* catch a bug
    (see 'Why isn't there a comparator for equals()', this group, also
    17/4/05).

    > Also, why do I need multiple types in a tree


    Because the entire program is based around a tree where certain types
    can only have certain types of children and parents, do certain
    things, and so on. To only have one type would make enforcing this
    extremely difficult (IMHO).

    > boolean checkMom() {
    > // no problem, if no mother, aka the root node.
    > if (mother == null) return true;
    > mother.checkSelf();
    > }
    >
    > boolean checkChildren() {
    > if (children == null ) return true;
    > Iterator iChild = children.iterator();
    > while ...
    > }


    This is pretty much what I'm doing at present; leaf-node types don't
    bother checking their children, but do themselves and parents;
    non-leaf types extend this to include child-checks (direct link, and
    recursive subtree check).

    - MS
     
    Michael Strorm, Apr 20, 2005
    #10
  11. Re: Decorators v Inheritance: Forcing subclass to call super() ?

    It's an interesting idea. Bearing in mind my brain has temporarily
    filled up, I'm not sure if it suits my needs, but I think it does.

    The major question is whether the overhead, and increase in code
    complexity is worth it. In this case, I think I'll stick with keeping
    it simple for this app, but it's worth bearing in mind.

    BTW, I think that's the template pattern; oddly, I also heard about
    this in the other thread I started in this group ("Why isn't there a
    comparator for equals() ?"), but for a distinctly different purpose.

    - MS
     
    Michael Strorm, Apr 20, 2005
    #11
  12. Re: Decorators v Inheritance: Forcing subclass to call super() ?

    Michael Strorm wrote:
    > BTW, I think that's the template pattern; oddly, I also heard about
    > this in the other thread I started in this group ("Why isn't there a
    > comparator for equals() ?"), but for a distinctly different purpose.


    You heard it in this thread, too (Message-ID
    <d3vmah$emm$>), but you did chose to
    ignore it. To me this sounds very much as if you are just after
    arguments to keep your current sub-optimal design, instead of
    considering something more robust. Well, thanks for wasting my time.


    /Thomas

    --
    The comp.lang.java.gui FAQ:
    ftp://ftp.cs.uu.nl/pub/NEWS.ANSWERS/computer-lang/java/gui/faq
     
    Thomas Weidenfeller, Apr 20, 2005
    #12
  13. Re: Decorators v Inheritance: Forcing subclass to call super() ?

    Thomas Weidenfeller <> wrote in message news:<d44vaj$97v$>...
    > Michael Strorm wrote:
    > > BTW, I think that's the template pattern; oddly, I also heard about
    > > this in the other thread I started in this group ("Why isn't there a
    > > comparator for equals() ?"), but for a distinctly different purpose.

    >
    > You heard it in this thread, too (Message-ID
    > <d3vmah$emm$>), but you did chose to
    > ignore it.


    Strange. I replied to that particular message, and responding to most
    of the points within. I'm not sure how that was possible if I
    "ignored" what you said.

    Firstly, you did mention the template; I didn't recognise the name, so
    I had it at the back of my head to investigate later. I later found
    out what it was (turned out the template was essentially what most
    people were suggesting, and something I'd inadvertantly "invented"
    myself not so long ago). The one that stuck in my head was from the
    other thread because it was using the same pattern to solve a
    different problem.

    > To me this sounds very much as if you are just after
    > arguments to keep your current sub-optimal design, instead of
    > considering something more robust.


    Secondly, why is my design sub-optimal?
    To use the template, the parent class would have to be abstract, and
    thus I could not create instances of it.

    Are you claiming that *any* class hierarchy where we wish to expand
    the behaviour of a concrete instantiable class, but *still* benefit
    from the behaviour defined in the parent is "sub-optimal"?

    The bottom line is that I did not "ignore" your advice, I read it and
    realised that whilst the pattern may have uses, it wasn't what I was
    looking for (see previous paragraph).

    > Well, thanks for wasting my time.


    That wasn't my intention; but it's for you to judge whether your time
    was wasted or not.

    - MS
     
    Michael Strorm, Apr 20, 2005
    #13
    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. Guest

    super.super.super how?

    Guest, Feb 19, 2005, in forum: Java
    Replies:
    24
    Views:
    10,793
    Darryl Pierce
    Feb 24, 2005
  2. jstorta
    Replies:
    3
    Views:
    447
    jstorta
    Feb 20, 2006
  3. Arien Malec

    PEP 318 decorators are not Decorators

    Arien Malec, Aug 13, 2004, in forum: Python
    Replies:
    11
    Views:
    572
    Arien Malec
    Aug 16, 2004
  4. Richard Szopa

    super, decorators and gettattribute

    Richard Szopa, Jan 12, 2008, in forum: Python
    Replies:
    19
    Views:
    672
    Richard Szopa
    Jan 15, 2008
  5. S.Volkov
    Replies:
    2
    Views:
    222
    S.Volkov
    Mar 12, 2006
Loading...

Share This Page