The Artima Developer Community
Sponsored Link

Java Design Issues
A Conversation with Ken Arnold, Part VI
by Bill Venners
October 14, 2002

<<  Page 2 of 5  >>


Bill Venners: In Effective Java, Bloch offered a good example in which the addAll method in class HashSet calls add on itself. A subclass attempts to track the total number of objects added to the set by counting the objects passed to both addAll and add, but it doesn't work as expected because of addAll's self-use. If someone passes three objects to addAll, the total number of objects increments by six, not three, because addAll calls add three times.

Bloch suggests that the addAll method should document its use of the add method. Therefore, designing for inheritance presents the problem: if I document a method's self-use, then that method must always use itself in that way. Documenting self-use restricts future implementation changes.

Ken Arnold: You can say the method has the option to do something without saying it will definitely do it, in some cases. But in other cases, you want to say: When I need a certain piece of internal data, I will call this method to get it. You want to document that, because you want subclasses to override the method and return a subtype of what you expect. That method's purpose is enabling subclasses to return subtypes. But, again, that is a matter of protected methods.

You certainly don't want to do things that set up sharp edges for subclassers. Yes, you can set things up so that if someone overrides something, an unexpected event occurs. Say you are the designer and implementer of a class, and at some point in the code you call the method foo. If you are unpleasantly surprised when a subclass overrides foo and does something unexpected, it seems to me there are two possibilities.

The first possibility is that the person who subclassed foo didn't obey foo's contract. Instead, he overrode foo and did something wrong; in which case, that is the subclasser's problem. He shouldn't override equals to return true only if the square root of one is the same as the other. That is just not what the equals method means. You can't prevent people from making that kind of mistake, so it is not your fault.

The other possibility is that your use of foo isn't properly defined in its contract. You might be using foo in a way that relies on something about your internal details that you don't describe, so other people interpret it incorrectly. In principle, I can see that kind of problem happening. But in either case, one party or the other has done something wrong.

This will also happen when methods are called during the construction phase. From the constructor, you are in a state where various things haven't been initialized. So you probably have to note which methods the class calls on itself during construction, because the methods have to be prepared for the list never having been created as opposed to having assumed it was created.

Bill Venners: Or as you said, saying that these methods may be called by the constructor, so subclassers need to make sure calling the methods during construction will work.

Ken Arnold: Or the constructor needs to make sure that the normal preconditions for calling are, in fact, set up. Although you can't do that with the subclass's own data, which is where things get really complex.

<<  Page 2 of 5  >>

Sponsored Links

Copyright © 1996-2018 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use