Make static typing work for you

9

Java is statically typed and this pervades the design and code written in it (regardless of whether you think that is a good thing). If you try to subvert this using reflection, you are working against the language and losing the major benefits of static typing, such as the ability to refactor, compile-time type checking, etc.

Which leads me to a code smell that I’ve seen mentioned a couple times recently and resonated with me due to some stuff I’ve seen in code bases I’ve worked in. In Java, any time you are putting Java class (or more rarely method) names in strings, you are making type information invisible to the compiler, and thus losing the benefits of static typing.

That doesn’t mean you should never do this. But it does mean that it should set off red flags and alarms and the decision to use reflection and store class names in strings should be made very deliberately and with an understanding of the consequences. First preference is to avoid using reflection at all. Second preference is to instead use com.foo.Bar.class or bar.getClass().

One place where class names show up that I think is unavoidable (and worth the consequences) is the case of delayed loading. Sometimes, you want to use a plugin-like system and delay loading of classes, either because you want to dynamically choose dependencies or because you want to hide the loading of dependencies inside a custom classloader. In either case, you can’t refer directly to the class as a Class as that would cause it to be loaded at the point of reference.

I dimly recall running into a similar use case with method names when implementing a dynamic proxy at some point in the distant past that was intercepting only certain calls to a target, based on method name. Given that there is no .method equivalent to .class, I don’t think there is any way to avoid referencing the method by name in this case. The only weird idea I can think of is maybe to define an interface containing just the methods that you wanted to check by name, then do a check to see whether the incoming method name was in that other interface’s methods. Of course, the best idea would have been to avoid using the dynamic proxy in the first place, but it was unavoidable at the time.

There is an interesting tangent to this involving annotations, which I will blog separately.

Comments

9 Responses to “Make static typing work for you”
  1. Be careful on your terminology – strong typing doesn’t mean the same thing as static typing. Ruby and Lisp are strongly-typed languages, but automated refactoring tools for those aren’t as good as for Java.

    I think the use case of a dynamic proxy results from some other inflexibilities. For example, given a List, you might want to add some code to its size() implementation, but you can’t, so a dynamic proxy works out to be the easiest solution.

    It would be better if you had a way of replacing the implementation of a certain method, just for one object, say, list#size={return whatever;};

  2. Alex says:

    I think I’m incapable of remembering which of static/strong typing I mean to be talking about. I tried to say the right thing, but I think I goofed. I’ll change to say “static”.

    Mixin capability would definitely be great to have, but would not have helped in the use case I’m talking about. Having the ability to modify only a particular method would have been perfect, though.

  3. Scott Bale says:

    Alex, in light of this post how do you feel about IoC containers like Spring? A component depends only on an interface, and in some config file there is a concrete classname as a string, an instance of which is injected into the component at runtime. Do you prefer IoC not going so far as to pull classnames into files like this?

  4. Alex says:

    In general, I do not like putting system configuration in external XML files. However, Spring does not require you to do this (it’s merely the most common way to configure a Spring app). You can also do Spring configuration in code or through a mixture of styles. It may be less of an issue with Spring, even in the XML case, if the Spring IDE plugins are aware and can pick up breakages/refactorings. I’m not sure if that’s the case or not.

    Some frameworks like Guice use no external configuration files and take as a principle that you should do the configuration through code (mostly annotations) that avoid specifying class names in strings.

    I’ve done my own dependency injection and configured through code, which I generally prefer. My general preference is that configuration occur in code unless it truly needs to be reconfigurable dynamically without a recompile. That’s likely a very small percentage of your app.

  5. Scott Bale says:

    Thanks. I’ve been working on a servlet project where I’m doing something similar in the deployment descriptor: I’ve got a bunch of components that can be assembled into a servlet, and I do that in the DD by specifying concrete classnames. It’s worked pretty well in that the IDE (IntelliJ) is smart enough to include these strings in refactorings. My goal wasn’t dynamic reconfiguration without recompile, so maybe there’s a better way. In any case the DD felt like the natural place to put this information since so much configuration info lives there anyway.

  6. Kishore Senji says:

    I guess it also depends whether the application is customized at the client side or not. If the product needs to be customized by client services then having IoC wired up by configuration files will be much easier for client service guys to not depend on Engineering to customize a service in the field rather than changing java files.

    If the application is a website or a solutions based, then wiring services using annotations or using code is better for all the advantages mentioned in this post.

  7. @Ricky:

    “Be careful on your terminology – strong typing doesn’t mean the same thing as static typing. Ruby and Lisp are strongly-typed languages,”

    The biggest problem with typing terminology is that people don’t distinguish between reference typing and object typing. In Java objects are static typed and references ar static typed. In some languages, especially dynamic languages, references are dynamic, they can change or are not typed at all. The same goes for objects, which can by dynamic typed (JS might be an example) or static typed (I think Python falls in this category). Ruby has static typed objects, but they can be changed, so someone can argue they are dynamic typed too. People often call static/static systems strong and dynamic/static and dynamic/dynamic systems weak (The combination static/dynamic doesn’t work).

  8. Sorry for all the typos :-)

    And poeple often think that languages with static references always look like Java where you have to declare those. Other languages with static references can infer them from the programm and developers don’t need to declare them (think Haskell, Scala). But I think it’s a good practice to declare them, this documents the developers intent and most developers don’t like to document their code. So every documentation the compiler forces on developers, is a good thing :-)

Trackbacks

Check out what others are saying about this post...
  1. [...] To me, one of the things that Java is really good at it is static typing. If you’re going to use Java to build your system, especially Java 5+ with generics and annotations, you should leverage the heck out of it. Otherwise, why are you using Java anyways? My feeling is that Guice was created in this spirit. [...]