Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > Decorators v Inheritance: Forcing subclass to call super() ?

Reply
Thread Tools

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

 
 
Michael Strorm
Guest
Posts: n/a
 
      04-17-2005
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
 
Reply With Quote
 
 
 
 
Tor Iver Wilhelmsen
Guest
Posts: n/a
 
      04-17-2005
http://www.velocityreviews.com/forums/(E-Mail Removed) (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.
 
Reply With Quote
 
 
 
 
Thomas Weidenfeller
Guest
Posts: n/a
 
      04-18-2005
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/...g/java/gui/faq
 
Reply With Quote
 
Michael Strorm
Guest
Posts: n/a
 
      04-18-2005
Thomas Weidenfeller <(E-Mail Removed)> wrote in message news:<d3vmah$emm$(E-Mail Removed)>. ..
> 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
 
Reply With Quote
 
Michael Strorm
Guest
Posts: n/a
 
      04-18-2005
Tor Iver Wilhelmsen <(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>...
> (E-Mail Removed) (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
 
Reply With Quote
 
Virgil Green
Guest
Posts: n/a
 
      04-18-2005
Michael Strorm wrote:
> Tor Iver Wilhelmsen <(E-Mail Removed)> wrote in
> message news:<(E-Mail Removed)>...
>> (E-Mail Removed) (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


 
Reply With Quote
 
P.Hill
Guest
Posts: n/a
 
      04-18-2005
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
 
Reply With Quote
 
Dale King
Guest
Posts: n/a
 
      04-19-2005
Tor Iver Wilhelmsen wrote:
> (E-Mail Removed) (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.
 
Reply With Quote
 
tzvika.barenholz@gmail.com
Guest
Posts: n/a
 
      04-19-2005
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.

 
Reply With Quote
 
Michael Strorm
Guest
Posts: n/a
 
      04-19-2005
"P.Hill" <(E-Mail Removed)> wrote in message news:<d4167o$nfm$(E-Mail Removed)>...

> 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
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Subclass of subclass Fab C++ 0 08-09-2012 09:54 AM
subclass a class in the namespace of the that subclass Trans Ruby 8 10-23-2008 07:24 AM
String subclass method returns subclass - bug or feature? S.Volkov Ruby 2 03-12-2006 06:46 PM
subclass has a variable that is subclass of same superclass jstorta Java 3 02-20-2006 08:42 PM
PEP 318 decorators are not Decorators Arien Malec Python 11 08-16-2004 06:38 PM



Advertisments