February 27, 2004

Static Import Surprises

There are some import static nuances that didn't come through in the Java 1.5 public review draft spec; I didn't understand them until I started writing actual code. First, remember that methods can be overloaded (and fields and member types can have the same name as a method) so import static can import more than one static member. It imports a name into the namespace, not any particular member. For example, this line imports the name sort:

import static java.util.Arrays.sort;

java.util.Arrays defines 19 different sort methods. The compiler performs method overload resolution with the imported name sort() just as well as it would for the qualified name Arrays.sort()

That isn't all that surprising, once you think about it. Now look at these lines of code. Illegal right?

import static java.util.Arrays.sort;
import static java.util.Collections.sort;

Actually, these lines are not illegal. The static sort() methods of these two utility classes have distinct signatures, and so these two import declarations do not introduce any namespace collisions, even though it looks like they do!

Another thing I found surprising is that you can import a static member, and then define a class that has a static member of the same name shadowing the imported member. For toplevel types, this must obviously be illegal, but it is okay for static member imports. Consider this code:

// Make "out" refer to System.out
import static java.lang.System.out;  

public class StandardOut {
    // Now we shadow the imported name
    static java.io.PrintStream out = System.err;  
    public static void main(String[] args) {
	// This line writes to System.err
	out.println("Hello, World");
    }
}

This isn't meant as criticism of static import; just an exploration of it. Static import is one of the more controversial new features of Java 1.5, but I think that overall, it is a good thing. The confusing thing about the code above is not the static import. It is the misleading line that assigns System.err to a field named "out" | TrackBack

Comments

Holy crap. I think I'll be forced to shoot the first developer who tries to use this shite on one of my projects ;-)

Posted by: Simon Harris at February 28, 2004 05:17 AM


The imports:
(import static java.lang.System.out;import static java.util.Arrays.sort; import static java.util.Collections.sort;) are NEVER used.
Any decent IDE would flag this.
Why dont you put on yor thinking cap and come up with an interesting example.

>"This isn't meant as criticism of static import;"
Static imports are evil.It was a STUPID idea.They are only usefull for obdfucating source code.

Posted by: Dum Example at February 28, 2004 03:24 PM

yeah, static imports are just confusing..don't see their added value..

to person above:
>Any decent IDE would flag this.
haha, which decent IDE suports java 1.5? Omnicore is the one that suports it..what's second decent one?

Posted by: nope at February 28, 2004 06:43 PM

Any decent IDE would flag un-used imports.

Posted by: Dum Example at February 28, 2004 07:39 PM

The anonymous "Dum Example" reader above has missed the point: it is surprising (at first) that importing a static member does not prevent you from defining another static member with the same name. The reason that this is surprising is that when you import a toplevel type, you cannot (obviously) define a toplevel type with the same name.

The fact that some IDEs flag unused imports is not relevant to my point here.

Posted by: David Flanagan at February 28, 2004 08:27 PM

David's example is fine and I don't see anything terribly surprising in the behavior. I like the new static imports. I think it will make a lot of code more readable and certainly more pleasant to write.

People who rely heavily on IDEs may not see any great benefit to this but they certainly won't be harmed.


Pat

Posted by: Pat Niemeyer at February 29, 2004 03:08 PM

import java.awt.Button;
//import org.eclipse.swt.widgets.Button;
>The anonymousreader above has missed the point.
I did not miss the point.I just thought your examples were un-interesting .I do not need Tiger to come up with with an example just as Stupid:

public class AnotherStupidExample {
class Button{}
}
//-------------------------------
>import static java.util.Arrays.sort;
>import static java.util.Collections.sort;
>Actually, these lines are not illegal.
Did you try using these methods?
Now that example is just as un-interesting.

Posted by: StupidExample at March 1, 2004 06:05 AM

DumExample/StupidExample:

Thoughtful comments on this blog are welcome, even from anonymous posters. Courtesy suggests, however, that you try to be less insulting in your comments.

Your comments have been fairly cryptic, but I gather that you think (1) static imports are a bad idea and (2) my examples are boring. If those are your only points, then you've made them and we're done.

To respond to your most recent comment, however:

Yes, I did try using the sort() method after importing it. If you import sort() from Arrays and Colletions, then you can indeed use the unqualified name sort to sort either an array or a List.

The example you give in your comment uses a member type to shadow a top-level type imported with a type import statement. This is similar to what I was demonstrating in my original post, but not the same. I was demonstrating that static import allows you to import a member type and then hide that type with another member type. This is surprising (at least a little) if you think of static import by strict analogy to the standard type import: when you import a toplevel type, you can't define another toplevel type with the same name. Thus, you might expect that when you import a static member, you would not be allowed to define another static member with the same name.

This is not a big deal. I did find it interesting enough to include an entry in my blog.

Now can we drop the "uninteresting" comments?

Posted by: David Flanagan at March 1, 2004 09:34 AM

Now, say you static import a bunch of CENTER fields (everyone should be cringing), obviously you'd have to qualify those, right? JButton.CENTER, FlowLayout.CENTER, the method that "CENTER" is being passed has no way of resolving which value of CENTER you meant.

Posted by: Guy at March 10, 2004 02:26 PM

Guy,

I believe (but have not tested) that the compiler will not let you do this. Unless you use a wildcard:

import static javax.swing.JButton.*;
import static java.awt.FlowLayout.*;

And if you do this, the compiler won't let you use CENTER without qualifying it with a typename.

The same is true about static import of methods if they have the same argument types as well as the same name.

Posted by: David Flanagan at March 10, 2004 09:49 PM

I think these experiments are most interesting. I can think of some good uses for import static (e.g. the import of the System.out-method you described above).

I can equally think of bad uses (e.g. the sort-thing described above). If you don't use an IDE, it will be damn hard to find which sort-method is used in the latter example. And even with an IDE, it gets really hard to understand what's happening.

Furthermore, for the first case, the "out" can easily be 'imported' in previous java-versions using the following statement:
PrintStream out = System.out;
So, for static member _variables_, nothing really changed. And static _methods_ look somewhat dangerous to me.

So I tend to conclude that using these static imports is not really a good idea. And IF you do, do so with extreme care :)

Posted by: DjiM at March 15, 2004 08:22 AM

You bring up an interesting point that I didn't consider before: actually being able to do the static import when it looks like you shouldn't be able to. Thanks for the insight!

Posted by: Rob Grzywinski at April 23, 2004 07:43 AM