Discussions

News: Interview with Ken Arnold on Java Design Issues

  1. Interview with Ken Arnold on Java Design Issues (31 messages)

    Artima.com has published an interview with Ken Arnold, in which he claims that marking a class or method final is a radical thing to do, that industrial strength classes should use clone and Cloneable despite it being a "real mess," that copy constructors can truncate types, and that marker interfaces are sometimes appropriate.

    Read Interview with Ken Arnold on Java Design Issues

    Here's an excerpt:

    I am not fond of copy constructors. In fact, I'm not very fond of constructors at all. The problem is that the code that creates the object with a constructor is defining the object's type. In all other operations, the code that uses an object effectively only defines that the object is at least a certain type. Constructors are an exception to that rule. I don't think that exception should exist.

    What do you think of the comments that Ken made?

    Threaded Messages (31)

  2. in reference to the constructor issues... this might sound odd as its been 4 or 5 years since of touched Delphi, but one feature that i thought was "cool" in that language was the concept of virtual constructors. i can barely remember what it was all about now but you could construct a class (with arguments) w/o knowing the expicit type of the class you were creating.

    you can do similar things now in java with reflection but it is still a lot of work.

  3. My C++ is a little rusty but I remember the copy constructor being:
    - not inheritable
    - defined automatically(using a shallow copy) if not explicitly implemented in a given class

    This removes the problem expressed in the article. This would be a relatively easy addition to the language...but existing code could break.
  4. <sartoris>
     My C++ is a little rusty but I remember the copy constructor being:
    - not inheritable
    - defined automatically(using a shallow copy) if not explicitly implemented in a given class
    </sartoris>

    Correct.

    <sartoris>
    This removes the problem expressed in the article.
    </sartoris>

    I don't think it does. What Ken is saying is that usually, when you invoke a method on an instance of "ParentClass", it doesn't really matter if the effective type of your object is "SubClassOfParentClass".

    The only exception to this rule is when you invoke a constructor, because you are explicitly naming the class you are instantiating.

    Hence the recommendation to use

    - Factory methods to create new instances
    - clone() to create copies of your objects

    which enable polymorphism.

    --
    Cedric

  5. <Cedric >
    Hence the recommendation to use

    - Factory methods to create new instances
    - clone() to create copies of your objects

    which enable polymorphism.
    <Cedric >

    Factories are great especially for frameworks. I would distinquish between frameworks and applications. let's say you are writing a test and you need to instantiate an object of concrete type, unless you are testing a factory method and even then you probably need to compare result with the real thing that probably will be created by ctr.



  6. I agree with Oleg's distinction between framework and application developers, as I've written a lot of both types of code and seen the different issues as the codebase evolves.

    In my view using final methods is often best in frameworks. Frameworks exist to handle workflow in a standard and (hopefully) correct manner. Application developers working with them _should_ be constrained in how they subclass those classes. Overriding concrete methods isn't a great way of extending behavior anyway: there are better alternatives, such as implementing abstract methods, and using the Strategy design pattern and delegation.

    In application code, final methods are less useful
    (although still worth considering).

    I think the performance issue (any tiny gain from final methods) is irrelevant in J2EE applications.
  7. To add to Rod's comments on often different use of inheritance in frameworks and applications.
    Framework and library providers often invest time to make code reusable, most examples of design patterns are from frameworks (at least in GoF and POSA books). But in application development Inheritance often used as an OO way of copy and paste. Library guys do it too sometimes like Stack that extends Vector :)
    Composition requires more work.
    Copy and paste is faster but subtle bugs can sneak in.
  8. "in reference to the constructor issues... this might sound odd as its been 4 or 5 years since of touched Delphi, but one feature that i thought was "cool" in that language was the concept of virtual constructors."



    I'm a real delphi fan, and I also think that virtual constructor and virtual static class is quite very useful. But I'm also find that virtual constructor make the compiler fail to check if I've completely implement all the abstract method if the object is always created from based-class virtual constructor. I'm not sure if it's good or bad, I've learned to live with and without it.
  9. What do you think of the comments that Ken made?


    May be he should use a factory? 8-/

  10. "...that marker interfaces are sometimes appropriate"

    That's one of the reasons why I'd like the metadata specs (JSR 175 & 181) to join java mainstream. I think that interfaces like serializable would be implemented using this compiletime metadata annotations. You wouldn't have to construct an extra type for every 'marker'.

    And the metadata facility would be more general; it would extend to methods etc.
  11. I definately agree on this one.
    It just seems to be a cleaner way of doing things.
    Marker interfaces have done their job, but it seems a bit like a hack. Being able to tag classes/methods/etc with metadata will be great. We have seen some of the benefits via XDoclet and co... add the ability to easily get access to the metadata via reflection and we will see a lot of things possible
  12. The question I always have about metadata annotations is the impact on development. Doesn't it break type safety? Does anyone have a reference to any conversations or explanations on how durable a system becomes after using metadata annotations?

    Thanks
    weo
  13. The interviews with Ken have been a lot of fun to read. It's good to see that some people still have opinions and are willing to express them in colorful ways. We should get Ken Arnold and Roger Sessions together on a Jini vs. (oh wait, there's nothing like that in .NET but I'm sure you can do the same thing with COM+ because that's what Java was copied from!) debate.

    Peace,

    Cameron Purdy
    Tangosol, Inc.
    Coherence: Easily share live data across a cluster!
  14. "We should get Ken Arnold and Roger Sessions together on a Jini vs. (oh wait, there's nothing like that in .NET but I'm sure you can do the same thing with COM+ because that's what Java was copied from!) debate. "

    That is not even funny. One of the things that is still good about this site is the absense of Mr. Sessions "unbiased" opinions.
  15. Roger Session is such a moron and contributed NOTHING, actually worth than nothing, to the computing community.

    No one should be in the same room with him.
  16. Also posted (and prettier to read :-)) at http://www.freeroller.net/page/cbeust/20021017


    Ken says:

    <<
    You should mark things final only if you have a good reason
    >>

    I couldn't agree more. I found that very often, programmers adopt the opposite position: if they can't find a good reason why their class should be subclassed, they will mark it (or its methods) final. This is compounded by the fact that in the early days of Java, it was strongly recommended to use final whenever possible for performance reasons. It is amazing to see that even now, this trend persists, while it doesn't make sense any more.

    It's interesting to see that this same problem was already plaguing C++, where a lot of over-zealous programmers were quick to put most of their interface in private sections. Who has never written "#define private public" can throw the first stone.

    Avoid final unless you are positively, categorically, darn sure and confident that it would be a bad idea for anyone to subclass your class (or that there are dire security issues at stake).

    <<
    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.
    >>

    I agree with Josh: this is a flaw in the design of the HashSet class. You should be very careful when you reuse a public method of your own class. Typically, instead of having addAll() call add(), I would factor out the common code of these two methods in a private one.

    This is something I have seen very often in EJB land: developers having an overloaded ejbCreate() call another ejbCreate() and wondering how come their bean gets inserted twice in the table.

    Another related pattern that I have been promoting heavily around me is the use of a private init() method. This is a lesson I learned from C++, which delineates clearly the distinction between allocation and initialization, while Java blurs it. Since Java doesn't allow default arguments, it is not uncommon to see several constructors overloaded that call each other. I would argue that the proper way to implement such a class would be something like:

    public MyClass(int n) {
      init(n, "default");
    }

    public MyClass(int n, String name) {
      init(n, name);
    }

    private void init(int n, String name) {
     //
    }

    This code also uses a good principle learned from C++ as well: avoid calling public methods from your constructors.

    Follow this pattern, and your classes will be much easier to subclass.

    <<
    I am not fond of copy constructors. In fact, I'm not very fond of constructors at all.
    >>

    This is probably a bit extreme, but I totally see where Ken is coming from. I have been involved in a pretty heavy Swing application lately, and from day one, I have worked hard to ban "new J" from our code. Okay, in English now. I simply mean that Swing objects should never be created except in one main factory class. Whenever you need a Swing object, call a factory method. The performance hit is minor, and it will allow you to evolve as your Swing application receives more and more constraints.

    Note that this issue has nothing to do with look and feel and everything to do with evolutivity. For example, what if at some point, you decide that you want to add a FocusOutListener to all the textfields in your application? Or that you want all your labels to be displayed in HTML? Or you want to hook a help mechanism in all your TextAreas?

    Back to Ken's point: yes, I believe that new should be use very sparingly in your applications for that very reason. The caller should never decide the concrete type of what it needs: all it wants is an object that will satisfy certain requirements. That's what interfaces are for, and that's why the recent IDE plug-in frameworks go to great lengths to expose only interfaces to their clients.

    <<
    If you look at a method contract, you'll see that not everything can be spelled out in the programming language.
    >>

    I couldn't agree more, and that's what JSR 175 is addressing. We have been making great progress lately, stay tuned, I am confident that you will like what you will see.

    --
    Cedric
    http://beust.com/weblog

  17. ---
    This is compounded by the fact that in the early days of Java, it was strongly recommended to use final whenever possible for performance reasons. It is amazing to see that even now, this trend persists, while it doesn't make sense any more.
    ---

    Another example of this kind of perversion is interfaces. People got the idea that interfaces were slow, so they didn't use them even when they should. Even people at JavaSoft did that. At one point I pushed hard at someone who should be using interfaces and he said "they're slow". I said "so fix that". Within days, it was just as fast to call interface methods as class methods. But until then he and others were simply content to live with bad designs because of minimal performance improvements.

    ---
    I agree with Josh: this is a flaw in the design of the HashSet class. You should be very careful when you reuse a public method of your own class. Typically, instead of having addAll() call add(), I would factor out the common code of these two methods in a private one.
    ---

    Well, it isn't really a flaw. If you subclass HashSet to make add do something special, you'd clearly like it if any use of addAll would just use your special add. It's more a matter of clarity -- tell people you are using it.

    Another example of this is the Reader and Writer classes, which define which methods you *must* override, and which are used by others unless you override them for efficiency. This is (I think) good design.

    Ken
  18. <<If you look at a method contract, you'll see that not everything can be spelled out in the programming language.
    >>

    I couldn't agree more, and that's what JSR 175 is addressing. We have been making great progress lately, stay tuned, I am confident that you will like what you will see.
    >>

    I believe Ken was talking about semantics here, and the metadata of 175 (or .NET) is a kind syntax, not semantics. Like the current elements of Java syntax--types, fields, methods, and so on--semantics can be attached to metadata.

    Semantics means meaning. Semantics exists in people's brains. People who have a semantic understanding of something can capture, express, and communicate that understanding in various ways: by talking to people, writing specifications, creating JavaDoc, defining conformance tests.

    Metadata lets people apply semantic meaning to software in ways very orthogonal to the type hierarchy. Tools written by programmers who understand the metadata semantics can then grab the metadata syntax and do special things with the constructs annotated by the metadata. That's how I would describe the usefulness of metadata. It doesn't get rid of the syntax/semantics split. Metadata just gives us another useful way to apply semantics to code.
  19. Cedric Beust wrote:
    > This is compounded by the fact that in the early days of
    > Java, it was strongly recommended to use final whenever
    > possible for performance reasons. It is amazing to see that
    > even now, this trend persists, while it doesn't make sense
    > any more.

    Can you expand on that, Cedric? My understanding of final was that it allowed scope for an optimising compiler to de-virtualise or inline method calls. Without final that optimisation could only be made be a jit-ing VM, which takes processing at runtime.

    Is that still the case, or was my understanding wrong in the first place?

        /david
  20. <david>
    Can you expand on that, Cedric? My understanding of final was that it allowed scope for an optimising compiler to de-virtualise or inline method calls. Without final that optimisation could only be made be a jit-ing VM, which takes processing at runtime.

    Is that still the case, or was my understanding wrong in the first place?
    </david>

    No, you are right, that's exactly what 'final' enables. What I am saying is that it used to matter a few years ago with

    - older JVM's
    - subpar JIT implementations
    - slower CPU's

    but that now, the use of final has more drawbacks than advantages. For enterprise-class applications, the fact that the compiler can inline methods is not as important as the ability to make your classes evolve. And I feel that 'final' gets in the way of maintenance and evolution (personal opinion).

    In general, what I dislike about 'final' is that it impacts both the design and the performance of your application, and that's usually the sign of an "overly overloaded" (;-)) keyword.

    That being said, I was chatting with a friend last night who is doing Java for embedded devices, and 'final' does matter for this kind of work.

    Your kilometrage may vary.

    --
    Cedric


  21. <Cedric >
    but that now, the use of final has more drawbacks than advantages. For enterprise-class applications, the fact that the compiler can inline methods is not as important as the ability to make your classes evolve. And I feel that 'final' gets in the way of maintenance and evolution (personal opinion).
    <Cedric >

    It might make sense to distinguish between library providers and application programmers
    Josh Bloch recommendation on using final I believe is for library providers. And your recommendation is for application programmers.
  22. Ken Arnold just taught me more about programming and design in 20 minutes than I have learned in the past 6 months of study. That guy is a legend.
  23. I think Ken Arnold makes some great points. In particular, he raises three issues that never seem to get the attention they deserve:
    - "You should design your protected interface as carefully as you design your public interface." Some coding standards, and a lot of developers, seem to automatically make instance variables protected, to make classes easier to extend. I think this is usually a big mistake. It makes it easy for subclasses to break superclass behavior by directly working with variables, while delivering little real gain in extensibility. It's also a mistake to make implementation methods protected without good reason: classes should conceal their own dirty washing, not confuse developers subclassing them. Inheritance shouldn't be a white-box operation; it's just another way of working with a class, which should define a neat contract. Protected visibility also allows access from all classes in the same package, something we don't always want.
    - "In fact, I'm not very fond of constructors at all. The problem is that the code that creates the object with a constructor is defining the object's type." Hear hear, again. Also, reliance on constructors means we can't use JavaBeans, which are great, and poses a problem for use of reflection.
    - Shallow/deep copy issue and clone mess. This is a common cause of bugs, and Ken makes some good comments.

    The only issue I disagree with Ken on is the use of final. I agree that final classes are seldom useful. However, I think that final methods can be very very useful. Consider the Template Method design pattern. When implementing it, it is often best to make the public method that handles workflow in the abstract superclass final, while subclasses implement protected abstract methods. This ensures that the workflow cannot be corrupted by rogue subclasses. The UML Reference Manual refers to this kind of use of final.I think that overriding a method is dangerous, and best avoided in most cases.

    I've written a lot of framework code, and I've found that avoidance of protected and use of final as I've described doesn't reduce extensibility, when applied with commonsense.

    I discuss these issues (and many others) in a lengthy chapter on design practice in my new book Expert One-On-One J2EE Design and Development (Wrox).
  24. One wonders what Ken thinks about the fact that you have to explicitly declare methods virtual in C# before you can override them...
  25. <jamie>
     One wonders what Ken thinks about the fact that you have to explicitly declare methods virtual in C# before you can override them...
    </jamie>

    I don't think there is one good answer to this question. C++ does it that way too and both approaches work fine, as long as you are aware of the consequences of what you are doing.

    --
    Cedric
  26. I totally disagree with Arnold[ Go to top ]

    The problem with the net - you can't really trust every article you read and you must be careful - applies very much
    to Arnold's article. It's a shame that most people believe every word said in the articles like this. In short - arguments mentioned in it are wrong! When I read the Joshus Bloch's excellent book, I was first sceptic but later understood his explanations of every item he states. (only)some comments to Arnolds interview:

    <arnold>
    You should never use final - the use of it is radical.
    </arnold>
    Why the use of final is "radical"? It's not! If you are in the (normal/typical) project and in some later point in the project you need to subclass a final class, all you have to do is to 1) make the final class _eligible_ to be inherited (read the Bloch book if you don't know what I mean...) and 2) remove the final-keyword. The use of final absolutely has nothing to do with optimization (expect in rare occasions).

    There are other ways of re-using the existing APIs - a great example is the collection API of Java 2: Adapter classes designed to be extendable and separate interfaces. No direct inheritance of (Arnold mentioned) HashSet is ever needed.

    <arnold>
    String class is an example of a wrong use of final-keyword
    </arnold>
    Yeah, I also thought so when I made my first Java-programs few years ago :). String is final for good reason: it's considered as a _base_ type and it's finality allows the use of string-constants ("myString") and the use of string-pools. The Java-security is also based on String finality. What if Sun want's to add some methods to non-final String-class? Well- it's not possible in a backward compatible way since somebody has likely defined the very same method in his/her subclass (which most likely works in a _little_ different way or returns different results).

    <arnold>
    copy-constructors are bad - use Cloneable
    </arnold>
    Huh, this is a very bad statement (has Arnold really worked in Sun sometimes?). You are _very_ likely to end up in the hard-to-debug bugs if you use Cloneable-interface in the inheritance hierarchies (yes, read you Bloch for more info). In the collection API you can make a copy of (m)any collection-type(s) by passing it as a parameter to some other Collection type (like new ArrayList(mySet)). Whats the problem?


    Huh, I don't really have time to comment the whole article. Summa summarum: the Ken Arnold's article is worth nothing and I recommend you to read the excellent book "Effective Java" by Joshua Bloch and use his items every day. Even Gosling recommends the book.



  27. I totally disagree with Arnold[ Go to top ]

    Interesting points, Janne...

    >> remove the final-keyword <
    I think Arnold was implying that the users of your class would not have access to the source code (or at least would not be the same people as the maintainers of the source code). Hence, simply removing the final keyword wouldn't be an option. You're right that the normal/typical project probably wouldn't need to be as careful.

    >> In the collection API you can make a copy of (m)any collection-type(s) by passing it as a parameter to some other Collection type (like new ArrayList(mySet)). Whats the problem? <
    I think this is very different than either copy constructors or clone. What the collection API lets you do is easily populate one collection object with the contents of another one; that's something that's very useful, but it's not the same as making a copy. In your example (constructing an ArrayList with a set) you're completely changing the behavior--for one thing, the order of iterator() just went from undefined to defined.

    Arnold's whole point is that you shouldn't need to know the subtype of an object to be able to create a copy of it (where the definition of "copy" includes all behavior being the same). He also says "I think clone is a real mess"... it's not that Clonable/clone() doesn't have it's problems, but I'd definitely agree with him that copy constructors are *not* the answer to this problem.
  28. I totally disagree with Arnold[ Go to top ]

    <<
    Why the use of final is "radical"? It's not! If you are in the (normal/typical) project and in some later point in the project you need to subclass a final class, all you have to do is to 1) make the final class _eligible_ to be inherited (read the Bloch book if you don't know what I mean...) and 2) remove the final-keyword.
    >>

    You can't always remove final in practice. One situation I brought up to Josh Bloch in which he agreed it is impractical is in a distributed system that is sharing code. This happens all the time in Jini, for example. You often can't bring down an entire system so that you can upgrade all nodes. So you upgrade one node at a time. If you try to remove a final in this situation, then you have some nodes that think a class is final and others that don't, all trying to share code with each other. That doesn't quite work.

    Josh Bloch also made it clear that "Document for inheritance or disallow it" was a "deliberate overstatement." I think he primarily wanted to get people thinking about this issue, not to get everybody suddently to declare everything final. Read what Josh said himself here:

    http://www.artima.com/intv/bloch12.html
  29. I totally disagree with Arnold[ Go to top ]


    <quote>
    2) remove the final-keyword.
    </quote>

    Good one. You don't always have the source of the libraries you use.

    --
    Cedric
  30. <final>
    Arnold talks about special (Jini mostly) situations. I don't know much about Jini; _must_ you extend classes when using it? Expecially classes you don't have the source code of? How can you guarantee that the extended classes work? If you don't replace any methods and you are 100% certain that the extended class does not change, there is no problem though.. but again; most of situations (outside Jini anyway) you shouldn't left the classes non-final if you want to make them robust. This concerns especially the library- developers- if you want to allow people to reuse your classes by extending them, always design you classes for inheritance, otherwise you the final- keyword.

    For Joe: Bloch also says: "If you look at our APIs, you'll see that there are a bunch of them that are neither designed for inheritance nor do they disallow it. For example, Hashtable isn't designed for inheritance, but doesn't disallow it. And in fact, people do subclass it. They do override methods, and they do produce garbage. "

    </final>


    <cloning>
    Arnold says that cloning is better than using copy-constructor. Most of the time, you never need to copy an object that you don't know exact type of. However, if the API is well-designed as is the case in the collections-API, you can do even that. For example, you have _any_ implementation of Collection- interface and you still can pass it as a parameter to ArrayList- constructor. Now you say: "but you must know that it's an instance of Collection" - yes I do since I'm considering the "collection-subclass" to implement the Collection- interface. Anyway - my point is that Arnold should not recommend the use of Clonable-interface since it's broken and very difficult to implement right. And almost all the times you can achieve the same effect by using other means such as copy-constructor. If you must use the Cloneable well then you must :) - I never had need to use it.
    </cloning>
  31. I totally disagree with Arnold[ Go to top ]

    <Janne Nyk?nen >
    Huh, I don't really have time to comment the whole article. Summa summarum: the Ken Arnold's article is worth nothing and I recommend you to read the excellent book "Effective Java" by Joshua Bloch and use his items every day. Even Gosling recommends the book.
    </Janne Nyk?nen >

    This is a really stupid comment. Ken Arnold is one of the big names in the field. This is short interview with him and he speaks candidly and if you are a typical Java programmer with no experience with better Java technologies like JavaSpaces and jini you may not understand everything he says.

    <Janne Nyk?nen >
    The problem with the net - you can't really trust every article you read and you must be careful - applies very much
    to Arnold's article. It's a shame that most people believe every word said in the articles like this.
    </Janne Nyk?nen >

    I don't think any of the comments made showed that people believed his every word whatever that is supposed to mean. But people take what Ken seriously because of who he is and what he says not because it is just posted on the net.

    Ask Joshua Bloch what he thinks of what Arnold says. I think you will find he agrees with it more then you do.


  32. I totally disagree with Arnold[ Go to top ]

    <david>
    Arnold is one of the big names in the field and that's why people listen to him
    </david>

    It's same for me who the man is or what he has earlier done - his arguments are not convincing in the interview.

    <david>
    Ask Joshua Bloch what he thinks of what Arnold says. I think you will find he agrees with it more then you do
    </david>

    Yes, I definitely should. Would be very interesting to hear his opinions. Seems to me that Arnold and Bloch disagree in most points though (just re-read the both interviews..).