Search

Categories

Links

Referers

JavaOne 2006 Slides

May 22 2006, 03:00:00 PM PDT »Java Comments [19]
I have uploaded the slides from the BOF Joe and I did on Best Practices With Generics and Other Java™ Platform 5.0 Language Features (BOF-0160)
Post a Comment:
Comments are closed for this entry.
Comments:

Hi,

Thanks for putting up the generics PDF!

I remain confused whether I could do better with the type signature of this function:
public static <E> E intern(E o)
Generic equivalent of String.intern(), for more immutable objects that we care about.
http://gallery.hd.org/_javadoc/org/hd/d/pg2k/svrCore/MemoryTools.html#intern(E)
I am not sure mainly because I seem to have to do lots of nasty things such as double casts "(E) (Object) o" to get the code to compile under 1.5. <p /> I've re-red Gilad's paper and remain not much wiser... <p /> Rgds
Damon

Posted by Damon Hart-Davis on May 23, 2006 at 06:37 AM PDT #

You have a slide that says "DON'T USE RAW TYPE" but there is no way in the javac compiler to verify that assertion.

A warning about using a raw type could be a great enhancement in javac.

Posted by Rémi Forax on May 23, 2006 at 08:30 AM PDT #

Rémi, this also came up during the BOF. See also RFE&nbsp;6228028. It it one of my favorites but it dropped of the radar for Mustang.

Posted by Peter von der Ahe on May 23, 2006 at 12:46 PM PDT #

Damon, I don't understand why you need the double casts. Could you show a small example?

Posted by Peter von der Ahe on May 23, 2006 at 12:49 PM PDT #

Hi, Follow the link above to the source (as HTML), but in any case here are the opening lines of the routine:
    public static <E> E intern(final E o)
        {
        if(o == null) { return(null); }

        // Default is to do nothing.
        E result = o;

        // Assume that String.intern() is sensible and efficient and robust
        // and allows GC of no-longer-used items in modern JVMs (1.4+)...
        // Assume that String values are very frequent intern()ees,
        // so check first for these, and handle as a short-cut.
        if(_USE_STRING_INTERN && (((Object)o) instanceof String))
            { return((E) (Object) (((String) (Object)o).intern())); }

        // Handle Internable objects...
        else if(((Object)o) instanceof Internable)
            {
...

Rgds
Damon

Posted by Damon Hart-Davis on May 23, 2006 at 11:33 PM PDT #

Damon, I still don't get the need for double casts. This compiles fine in 5.0:
    public static <E> E intern(final E o) {
        if (o instanceof String) {
            return (E) ((String)o).intern();
        } else if (o instanceof Internable) {
            // ...
        }
        return o;
    }

Posted by Peter von der Ahe on May 23, 2006 at 11:46 PM PDT #

Hi Peter,

Slightly embarassingly I can't get anything other than IDEA to complain now when I comment out the (Object) casts now... Bv( IDEA (4.5) still puts red squiggles all over the place but the 1.5.0_03 compiler on WinTel that I use for development is happy as Larry (and the output bytecodes look fine too, but then they always did).

If you will be so kind as to overlook this swerve, could you still find a moment to tell me if you think that the "public static <E> E intern(final E o) { ... }" signature is as tight/expressive as it should be?

Rgds
Damon

PS. Don't you have a home to go to? B^(

Posted by Damon Hart-Davis on May 24, 2006 at 12:29 AM PDT #

Damon, this is probably a bug in IDEA 4.5. We have reworked much of the generics support in 5.0, and this code is compilable in 5.0. BTW, you could avoid instanceof checks in many cases (when the type of parameter is statically known to be String) by making an overload.

Posted by 195.5.138.42 on May 24, 2006 at 02:04 AM PDT #

Hi,

Ah, kewl, overloading. I'd overlooked that! Thanks!

Damon

Posted by Damon Hart-Davis on May 24, 2006 at 02:57 AM PDT #

On your slide: Use of Type Tokens

...

class ServiceLoader<S> {

public static <S> ServiceLoader<S> load( Class<S> service);

public Iterator<S> iterator();

}

My question: I don't see your point yet?

There are two different type variables S with the same name. So you can use both with different actual types (intended?)

You are not allowed to write something like

class ServiceLoader<S> {

static Class<S> clazz; // wrong!

public static <S> ServiceLoader<S> load( Class<S> service) {

clazz= ...

}

...

}

So, what is this code snippet good for? Just to show that two type variables are unrelated and collide?

regards

esser

Posted by Esser on May 24, 2006 at 06:24 AM PDT #

Esser, the purpose of the ServiceLoader example is to illustrate how to use classes as type tokens.

However, it also illustrates that you should not always follow the example of the JDK engineers because there are two type variable declarations (see slide 8 and 9) which declare two different type variables that have the same name. This can lead to confusion.

Posted by Peter von der Ahe on May 24, 2006 at 11:28 AM PDT #

Damon, you may know that Al Gore invented a little thing called "The Internet". I can use this to access my blog from home ;-)

Regarding the signature, it seems fine. However, there may be some unexpected surprises for you. Presumably you expect that two objects that compare .equals have the same class. However, that may not be the case. I assume that you have an unchecked cast in the instanceof Internable case. This cast can "fail" but that will not be known immediately.

Posted by Peter von der Ahe on May 24, 2006 at 11:38 AM PDT #

Ok, but still there is a open question.

I thought, this code snippet should demonstrate a static class-token, to be used as a "constructor" for all instances of the same Type S of ServiceLoader<S>.

But you must solve the problem, that both parametrizations of S be in sync, i.e. same type.

How you can enforce this?

regards

Esser

Posted by 84.142.119.101 on May 24, 2006 at 11:46 AM PDT #

I'm not sure I understand the question. Would it your question change if the class looked like this:
class ServiceLoader<S> {
    public static <T> ServiceLoader<T> load(Class<T> service);
    public Iterator<S> iterator();
    ...
}
This is exactly the same class. However, the two different type variables have different names.

Posted by Peter von der Ahe on May 24, 2006 at 11:56 AM PDT #

SORRY! When I saw that slide, I thought you would have talked about the limitation of current generic java and a helpful idiom.

In your code Class<T> would not be useful, it is unrelated to S. So if you would use it as a factory for object of type S --> hopeless.

Actually the problem boils down to the question how to synchronize static type-variables with type-variables, declared for the class(in "wishfull generic java" -- NextGen -- no problem!) .

You cannot express any relationship between T and S (remark: same problem with constructor-chaining, calling a constructor with type-variables from another constructor with this(...) --> hopeless).

So I thought, you would have talked about problem and solution.

regards

esser

Posted by esser on May 24, 2006 at 04:13 PM PDT #

Hi Peter,

Only objects for which equals() really means equals() are allowed to carry the Internable marker interface, but if I did not have that stipulation you would be quite right.

I have propagated the generics flavour a little further into my code (and of course all my tests still pass *and* it seems to work), but I'll wait until I've moved the code to an IDE which stops confusing me by telling me I'm doing it all wrong before going any further!

BTW, with the overloading I am now resolving about 50% of the calls to specialised cases at compile time (avoiding some or all instanceof checks), thanks. In general I'm really interested in optimisations like this that help code that HotSpot doesn't have a chance to get to work on, eg expecially at start-up. I package with ProGuard to get some of those "static" optimisations, but a tiered compiler would help of course. B^>

Rgds (and thanks again),
Damon
PS. Good Ole Gore!

Posted by Damon Hart-Davis on May 25, 2006 at 06:37 AM PDT #

Damon, Let's say that you have Foo and a subclass of Foo, LoggingFoo. The only difference between Foo and LoggingFoo is that the latter logs certain calls. Now, an instance of Foo and an instance of LoggingFoo can be equal:
Foo foo = ...;
LoggingFoo log = ...;
assert foo.equals(log);
assert log.equals(foo);
foo = intern(foo);
log = intern(log); // class cast exception

Posted by Peter von der Ahe on May 25, 2006 at 11:16 AM PDT #

Hi again Peter,

Thanks for all the effort that you are putting into my performance quest! B^>

In my Foo.equals() I always have a "if(!(other instanceof Foo)) { return(false); }" to avoid possible strangenesses and asymmetries, ie I use quite a conservative notion of "equals()".

Or am I still missing something? (Most likely!)

Rgds
Damon

Posted by Damon Hart-Davis on May 26, 2006 at 04:19 AM PDT #

Hi (2),

Note that that in my assert()s at the end of my intern() I test both a.equals(b) and b.equals(a), so if I foolishly violate my conservative equals notion I should get an assertion during development...

Rgds
Damon

Posted by Damon Hart-Davis on May 26, 2006 at 04:26 AM PDT #

Java is a trademark of Sun Microsystems, Inc.
Copyright © 2006,2007 Peter von der Ahé