'. '

Talk:Blogs:JaroslavTulach:Theory:LanguagesForEvolution

From APIDesign

Revision as of 09:34, 30 September 2008 by JaroslavTulach (Talk | contribs)
Jump to: navigation, search

Duck-typing

This is where Java's strong typing steps in your way. What about languages which do not have such strong typing? For example Ruby's duck-typing seems to sidestep this problem in a simple way - because there is no need for "abstract" in Ruby, this issue obviously does not exist there. The price you pay for this flexibility in Ruby in this case is that you should use introspection (xx.respond_to? :getHTMLTitle) to find out whether the object xx actually provides the method getHTMLTitle or not. However, if you have not used Ruby before, beware - Java programmers usually do hate it, just because it is not strong typed - they refuse the duck-typing just because it seems perverse to them. However, it is not so perverse once you get used to it. ;-)

-- an Anonymous Coward on 20:11, 21 September 2008

OK, let's accept the view that duck-typing really helps to solve the problem of enhancing an existing interface with String getHTMLTitle() method. What can users of such method do? Well, they need to check whether an object implements the method or not and either send the message or do something else:

// written in a pseudo language with "respond_to" operator:
title = null;
if (xx.respond_to? :getHTMLTitle) {
  title = xx.getHTMLTitle();
} else {
  title = "<b>" + xx.getDisplayName() + "</b>";
}

this is possible. However it does not contribute to the simplicity of API usage. The if statements are only likely to grow, they are spread all around the code base and after few releases the maintenance becomes a nightmare. Btw. in Chapter 6, Code Against Interfaces, Not Implementations, I show that similar nightmare can happen in Java:

public abstract class View {
  public abstract String getDisplayName();
}
public abstract class ViewVersion2 extends View {
  public abstract String getHTMLTitle();
}
 
title = null;
if (xx instanceof ViewVersion2) {
  title = ((ViewVersion2)xx).getHTMLTitle();
} else {
  title = "<b>" + xx.getDisplayName() + "</b>";
}

As can be seen, this style produced almost as bad code as the Ruby example above. The truth is that when evolving an interface, you most likely want to provide default implementation of getHTMLTitle to all existing and already written classes. The simplest trick to achieve that in Java is:

public abstract View/*version 2.0*/ {
  public abstract String getDisplayName();
  public String getHTMLTitle() {
    return "<b>" + getDisplayName() + "</b>";
  }
}

Only then you simplify life of your API clients. I'd bet that similar code can be rewritten to Ruby, without use of duck-typing. As such, I'd like to conclude that duck-typing does not simplify API evolution, at least not in this particular case. Looks like Languages Ready for Evolution are unlikely to benefit from duck-typing.

--JaroslavTulach 15:48, 22 September 2008 (UTC)

Modularity

If you would like to write a code which could use both the old version of the class (which does not provide some method) and the new version of the class (which provides that method), you would obviously end up with the code similar to "if (using_new_class) { use_provided_method } else { do_it_yourself }", which is not nice.

I think that the benefit of Ruby in this case is that you can seamlessly use the new version of the class with some legacy code which uses this class (with absolutelly no change needed for that legacy code). Of course only if the new version of the class would not break whatever the old version of the class has provided already. Adding new functionality is allowed.

If used with a proper versioning system (based for example on something like RubyGems' "gem 'library_name', '>= 3.1', '< 4.0'" attached to the client code), this could result in a quite nice approach to API evolution, couldn't it? The infrastructure would ensure that you would have a class with proper version available, so you could avoid writing the ugly code testing for availability of the methods you would like to use. On the other hand you would be obligated to increase the major version number of the library every time you introduce any backward-incompatible change to it. It would be nice to have such version numbers generated automatically, but because it is impossible to do it 100% correctly (think about semantic changes, time or memory effectiveness, etc.), letting the author of the library to assign the version numbers seems like a reasonable approach.


-- Anonymous, Sep 29, 2008

Re: benefit of Ruby. My whole point is that this is not really due to duck-typing. In fact I can rewrite the whole paragraph and use Java and it will still be true: I think that the benefit of Java in this case is that you can seamlessly use the new version of the class with some legacy code which uses this class (with absolutelly no change needed for that legacy code). Of course only if the new version of the class would not break whatever the old version of the class has provided already. Adding new functionality is allowed.

Re: proper versioning system. Exactly, proper versioning system is very important prerequisite for good API design. The JDK (up to version 6) suffers from not using versioning system, so do regular Java applications. On the other hand, this is not weakness of Java. NetBeans have its module system and there is OSGi. Both these systems allow to precisely express the required APIs together with their minimal version. They also support some kind of major incompatible version release. Similar to Gems, I guess. You are right that we are missing tools that would guarantee easy Upgradability of one version by another, so it is more or less matter of common sense and compatibility rules awareness of the library author.

I guess that, if TheAPIBook offers some knowledge not widely spread among the Java SE community, then it is the modularity, its use and benefits. The book propagates use of module architecture in Chapter 7, it describes few adventures when trying to make multiple versions of the same library co-exist with each other in Chapter 15 and finally it also shows the advantages of proper versioning for end of life policies in Chapter 19. I believe modularity is necessary component for modern applications in any language.

Thanks for your comments and I am looking forward to chat more. --JaroslavTulach 09:14, 30 September 2008 (UTC)

Personal tools
buy