The Artima Developer Community
Sponsored Link

Weblogs Forum
Generics and Packages

14 replies on 1 page. Most recent reply: Jan 23, 2006 4:00 PM by Brian Goetz

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 14 replies on 1 page
Bruce Eckel

Posts: 874
Nickname: beckel
Registered: Jun, 2003

Generics and Packages (View in Weblogs)
Posted: Nov 10, 2005 9:30 AM
Reply to this message Reply
Summary
There appear to be some strange side effects on packages when using generics.
Advertisement

Consider the following file:

package code;

interface HasColor {
  java.awt.Color getColor();
}

class Dimension {
  int x, y, z;
}

class ColoredDimension<T extends Dimension & HasColor> {
  T item;
  ColoredDimension(T item) { this.item = item; }
  T getItem() { return item; }
  java.awt.Color f() { return item.getColor(); }
  int getX() { return item.x; }
}

When you run the compiler, you get the following error message:

GenericsAndPackages.java:17: x is not public in code.Dimension; cannot be accessed from outside package
  int getX() { return item.x; }
                          ^
1 error

Since all the code is in the same package, this is probably a bug. But with generics, it's always hard to tell.


Adam Kiezun

Posts: 4
Nickname: akiezun
Registered: Nov, 2005

Re: Generics and Packages Posted: Nov 10, 2005 9:47 AM
Reply to this message Reply
what's the real declaration of ColoredDimension again?
As posted, it makes no sense.

I think you mean
class ColoredDimension<T extends Dimension & HasColor>
but it's hard to tell.

In the case above, Eclipse's compiler is happy.

Bruce Eckel

Posts: 874
Nickname: beckel
Registered: Jun, 2003

Re: Generics and Packages Posted: Nov 10, 2005 11:42 AM
Reply to this message Reply
Oops. It's fixed now. Pesky angles and ampersands.

Kirk Brown

Posts: 3
Nickname: kdborg
Registered: Nov, 2005

Re: Generics and Packages Posted: Nov 10, 2005 12:56 PM
Reply to this message Reply
In this example, T, cannot be guaranteed to be in the same package. That is why the compilation error occurs.

Making the variable x public gives the correct scope.

Kirk Brown

Posts: 3
Nickname: kdborg
Registered: Nov, 2005

Re: Generics and Packages Posted: Nov 10, 2005 12:58 PM
Reply to this message Reply
..gives the visibility to make that allows the example to compile, I mean.

Terry Cube

Posts: 1
Nickname: tcube2002
Registered: Nov, 2005

Re: Generics and Packages Posted: Nov 10, 2005 2:14 PM
Reply to this message Reply
You always have really interesting topics but your examples are almost always unnecessarily confusing. They would be a lot more effective without methods like public java.awt.Color f(), or one of your previous posts with classes named "HasF" and "Manipulator4". A little more thoughtfulness on class and method naming would go a long way towards more clearly communicating the concepts you're talking about. Reading foo/bar example code is like looking at decompiled class files.

Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: Generics and Packages Posted: Nov 10, 2005 6:07 PM
Reply to this message Reply
The compiler is right, a class derived from Dimension does not have to be in the same package.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: Generics and Packages Posted: Nov 11, 2005 12:15 PM
Reply to this message Reply
> In this example, T, cannot be guaranteed to be in the same
> package. That is why the compilation error occurs.
>
> Making the variable x public gives the correct scope.

Why should that matter, though? It works if you get rid of the generic declarations:

interface HasColor {
  java.awt.Color getColor();
}
 
class Dimension {
  int x, y, z;
}
 
class ColoredDimension {
  Dimension item;
  Dimension getItem() { return item; }
  int getX() { return item.x; }
}


But item is still not guaranteed to be of a class declared in the package.

I'm not saying that you are wrong but there is something funny about this. Not matter where T is declared it must be an instance of Dimension, x is declared in Dimension and therefore should be accessible at the package level.

I suppose T could declare it's own x that ColorDimension cannot access but that shouldn't matter because ColorDimension won't know that. Even if a redefined x were avaialble on T, the erasure of T will ensure there is no way it could be accessed.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: Generics and Packages Posted: Nov 11, 2005 2:41 PM
Reply to this message Reply
Bruce, compiles without error. It is my feeling that this lends credence to the error being a bug:
interface HasColor {
  java.awt.Color getColor();
}
 
class Dimension {
  int x, y, z;
}
 
class ColoredDimension<T extends Dimension & HasColor> {
  T item;
  ColoredDimension(T item) { this.item = item; }
  T getItem() { return item; }
  java.awt.Color f() { return item.getColor(); }
  int getX() { return ((Dimension) item).x; }
}

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: Generics and Packages Posted: Nov 11, 2005 2:48 PM
Reply to this message Reply
interface HasColor {
  java.awt.Color getColor();
}
 
class Dimension {
  int x, y, z;
}
 
class ColoredDimension<T extends Dimension> {
  T item;
  ColoredDimension(T item) { this.item = item; }
  T getItem() { return item; }
  //java.awt.Color f() { return item.getColor(); }
  int getX() { return item.x; }
}


The above should also compile. If the compiler were right, why would this be OK?

Bruce Eckel

Posts: 874
Nickname: beckel
Registered: Jun, 2003

Re: Generics and Packages Posted: Nov 11, 2005 2:58 PM
Reply to this message Reply
> class ColoredDimension<T extends Dimension> {
> T item;
> ColoredDimension(T item) { this.item = item; }
> T getItem() { return item; }
> //java.awt.Color f() { return item.getColor(); }
> int getX() { return item.x; }
> }

Yes, that's correct, this only happens when you have multiple bounds. That's another reason it seems like it should be an error. I should have pointed that out in the posting.

Kirk Brown

Posts: 3
Nickname: kdborg
Registered: Nov, 2005

Re: Generics and Packages Posted: Nov 11, 2005 7:14 PM
Reply to this message Reply
An interesting deviation if you look at the interface HasColor. HasColor has no int variable named x. However, if you add an int x = 5; to the interface HasColor, the original problem compiles.

It would seem like a problem around visibility. Any class that extends Dim could change the visibility of x from package to private. Once that is done, ColoredDimension<> would not be able to see the variable x.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: Generics and Packages Posted: Nov 14, 2005 11:08 AM
Reply to this message Reply
> It would seem like a problem around visibility. Any class
> that extends Dim could change the visibility of x from
> package to private. Once that is done, ColoredDimension<>
> would not be able to see the variable x.

That's probably where this issue orignates but it doesn't seem to be a valid issue. If a class extends hasColor and shadows x such that it cannot be reached from the package, why should that keep me from reaching something in the package? If we get rid of the HasColor interface, we can still extend Dimension to shadow x but the compiler doesn't care. Why should it care when there are two super types? Why should the inability to see something that I shouldn't know about keep me from reaching something that I can reach and do know about?

Mohan Radhakrishnan

Posts: 7
Nickname: mindspace
Registered: Oct, 2005

Re: Generics and Packages Posted: Nov 16, 2005 12:28 AM
Reply to this message Reply
The following compiles in eclipse and prints '0'.

package com.test;
 
public class ColoredDimension<T extends Dimension & HasColor> {
 
		T item;
		ColoredDimension(T item) { this.item = item; }
		T getItem() { return item; }
		java.awt.Color f() { return item.getColor(); }
		int getX() { return item.x; }
		
	    public static void main (String[] parameters) {
	    	ColoredDimension<NewDimension> cd = 
	    			new ColoredDimension<NewDimension>( new NewDimension() );
	    	System.out.println( "[" + cd.getX() + "]" );
	    }
}
 
interface HasColor {
	  java.awt.Color getColor();
}
 
class Dimension {
	  int x, y, z;
}
 
class NewDimension extends Dimension implements HasColor{
	
	  int x = 5;
	
	  public java.awt.Color getColor(){
		  return java.awt.Color.RED;
	  }
}

Brian Goetz

Posts: 5
Nickname: briangoetz
Registered: Sep, 2005

Re: Generics and Packages Posted: Jan 23, 2006 4:00 PM
Reply to this message Reply
This does feel like a compiler bug, and I'm not sure what exactly the compiler is confused about, but in any case, there are some awfully questionable things going on in this code example, and the strange behavior goes away when you do something more sensible.

First, the name. ColoredDimension. This is not a "colored dimension", as it is neither a Dimension nor a HasColor. You could implement a ColoredDimension as such:

class ColoredDimension extends Dimension implements HasColor { ... }

with no generics at all.

What ColoredDimension really is is a "colored dimension holder." This may sound like a small nit, but it will be far far less confusing to anyone who wants to read the code (someone already commented on this.)

Second, the use of package-private variables here is extremely confusing. Dimension does not extend HasColor, so clearly you are expecting T to bind to a subclass of Dimension. But Dimension has not been designed for extension! Its fields are package-private, not protected. If you did this, or if Dimension provided getters, the problem goes away. (And clearly it should do one or the other -- the way Dimension works now is suitable only for toy examples.)

Flat View: This topic has 14 replies on 1 page
Topic: What's in a name ... Traits versus Interfaces Previous Topic   Next Topic Topic: M Clock 2.0


Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us