Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Converting Sets

5 views
Skip to first unread message

Roedy Green

unread,
Feb 2, 2012, 2:34:49 AM2/2/12
to
What is the cleanest way to do this conversion?

I have a Set<X>.
I want a Set<Y> where X implements Y.
--
Roedy Green Canadian Mind Products
http://mindprod.com
One of the most useful comments you can put in a program is
"If you change this, remember to change ?XXX? too".

Mayeul

unread,
Feb 2, 2012, 6:47:58 AM2/2/12
to
On 02/02/2012 08:34, Roedy Green wrote:
> What is the cleanest way to do this conversion?
>
> I have a Set<X>.
> I want a Set<Y> where X implements Y.

This conversion exactly as asked:

Set<X> setOfX = obtainSetOfX();
Set<Y> setOfY = new YourPreferredSetImplementation<Y>(setOfX);

or:

Set<X> setOfX = obtainSetOfX();
Set<Y> setOfY = new YourPreferredSetImplementation<Y>();
setOfY.addAll(setOfX);

Conversion of a Set<X> to a Set<? extends Y>, ensuring the Set contains
objects assignable to Y, but no new elements can be added to it:

Set<X> setOfX = obtainSetOfX();
Set<? extends Y> setOfY = setOfX;

Also, consider the possibility to build a Set<Y> and put X objects into
it, in the first place.

--
Mayeul

Roedy Green

unread,
Feb 2, 2012, 8:32:10 AM2/2/12
to
On Thu, 02 Feb 2012 12:47:58 +0100, Mayeul <mayeul....@free.fr>
wrote, quoted or indirectly quoted someone who said :

>Conversion of a Set<X> to a Set<? extends Y>, ensuring the Set contains
>objects assignable to Y, but no new elements can be added to it:
>
>Set<X> setOfX = obtainSetOfX();
>Set<? extends Y> setOfY = setOfX;

This what I was looking for , that did not require an element by
element copy.
Ah, but this this you created is NOT a Set<Y>. You cannot add
arbirary Y to it, just more X. I feel queasy. How could the compiler
keep track that setOfY could only contain X.

Mayeul

unread,
Feb 2, 2012, 10:06:24 AM2/2/12
to
On 02/02/2012 14:32, Roedy Green wrote:
> On Thu, 02 Feb 2012 12:47:58 +0100, Mayeul<mayeul....@free.fr>
> wrote, quoted or indirectly quoted someone who said :
>
>> Conversion of a Set<X> to a Set<? extends Y>, ensuring the Set contains
>> objects assignable to Y, but no new elements can be added to it:
>>
>> Set<X> setOfX = obtainSetOfX();
>> Set<? extends Y> setOfY = setOfX;
>
> This what I was looking for , that did not require an element by
> element copy.
> Ah, but this this you created is NOT a Set<Y>. You cannot add
> arbirary Y to it, just more X. I feel queasy. How could the compiler
> keep track that setOfY could only contain X.

It cannot. The compiler notices that setOfY is parametered with an
extends wildcard, and therefore does not know what exactly it can or
cannot contain.

Therefore, you cannot add anything to setOfY. But you can still add more
X to setOfX, and they point to the same object...

--
Mayeul

markspace

unread,
Feb 2, 2012, 12:21:13 PM2/2/12
to
On 2/2/2012 7:06 AM, Mayeul wrote:
> On 02/02/2012 14:32, Roedy Green wrote:

>> Ah, but this this you created is NOT a Set<Y>. You cannot add
>> arbirary Y to it, just more X. I feel queasy. How could the compiler
>> keep track that setOfY could only contain X.

>
> It cannot.


I think this is covered in Effective Java. Generics are a compile time
thing. If you want runtime, you have to roll your own (I don't know of
any classes in the API that allow you to have a runtime type parameter,
although I guess there may be some).

class MySet extends SomeSet {

Class type;

MySet( Class type ) { this.type = type; }

void add( Object o ) {
if( o instanceof type ) super.add( o );
}
}

I think is the above is the gist of how EJ handles it. Add a type token
(the "type" variable) and test for types as they are added. If you want
generics too, add them in:

class MySet<T> extends Set<T> {

Class<? extends T> type;

MySet( Class<? extends T> type ) { this.type = type; }

void add( T o ) {
if( o instanceof type ) super.add( o );
}
}

Not compiled, but I think that gives the right idea.

Daniel Pitts

unread,
Feb 2, 2012, 2:02:01 PM2/2/12
to
On 2/2/12 5:32 AM, Roedy Green wrote:
> On Thu, 02 Feb 2012 12:47:58 +0100, Mayeul<mayeul....@free.fr>
> wrote, quoted or indirectly quoted someone who said :
>
>> Conversion of a Set<X> to a Set<? extends Y>, ensuring the Set contains
>> objects assignable to Y, but no new elements can be added to it:
>>
>> Set<X> setOfX = obtainSetOfX();
>> Set<? extends Y> setOfY = setOfX;
>
> This what I was looking for , that did not require an element by
> element copy.
> Ah, but this this you created is NOT a Set<Y>. You cannot add
> arbirary Y to it, just more X. I feel queasy. How could the compiler
> keep track that setOfY could only contain X.
It does not. Instead, it prevents you from any add operation which
requires the type.

In other words, setOfY becomes somewhat "read-only" for typed
operations. You can still clear it, or sub-sets of it, but you can no
longer add *any* object to it, whatever type.

Jim Janney

unread,
Feb 2, 2012, 3:13:10 PM2/2/12
to
See checkedSet in java.util.Collections.

--
Jim Janney

markspace

unread,
Feb 2, 2012, 4:46:19 PM2/2/12
to
On 2/2/2012 12:13 PM, Jim Janney wrote:
> See checkedSet in java.util.Collections.
>

Oh sure, find some documentation that completely contradicts me!


Roedy Green

unread,
Feb 2, 2012, 7:29:09 PM2/2/12
to
On Thu, 02 Feb 2012 09:21:13 -0800, markspace <-@.> wrote, quoted or
indirectly quoted someone who said :

>I think this is covered in Effective Java. Generics are a compile time
>thing

Everything else in Java eventually seems obvious. Generics on the
other hand get weirder and weirder the more I learn. I think it was a
mistake to try to do generics purely at compile time. It is like
trying to do all types purely at compile time.

Have we gone down that road too far now that Java can never be fixed
with run-time generics info without starting over with some completely
different notation? Then serialisation could work, containers could be
allocated with the precise array type. You would not have so much
under-the-hood casting.

Perhaps it is time to read-read all the generics docs and see if they
make more sense now with some practical experience under my belt.

Daniel Pitts

unread,
Feb 2, 2012, 8:34:13 PM2/2/12
to
On 2/2/12 4:29 PM, Roedy Green wrote:
> On Thu, 02 Feb 2012 09:21:13 -0800, markspace<-@.> wrote, quoted or
> indirectly quoted someone who said :
>
>> I think this is covered in Effective Java. Generics are a compile time
>> thing
>
> Everything else in Java eventually seems obvious. Generics on the
> other hand get weirder and weirder the more I learn. I think it was a
> mistake to try to do generics purely at compile time. It is like
> trying to do all types purely at compile time.
That is exactly what Generics are.
>
> Have we gone down that road too far now that Java can never be fixed
> with run-time generics info without starting over with some completely
> different notation? Then serialisation could work, containers could be
> allocated with the precise array type. You would not have so much
> under-the-hood casting.
The point of generics is to add compile-time type safety. Runtime
"generics" is a contradiction to that. It might not have been
implemented in the "cleanest possible" way, but it tends to be good
enough for most non-reflective uses.

>
> Perhaps it is time to read-read all the generics docs and see if they
> make more sense now with some practical experience under my belt.
Yes, probably.

In particular, you want to understand what "<A extends B>" and
"<A super B>" mean when declaring generic types, and what "<? extends
B>", "<? super B>" and "<?>" mean when /using/ generic types.

Roedy Green

unread,
Feb 2, 2012, 9:25:28 PM2/2/12
to
On Thu, 02 Feb 2012 12:47:58 +0100, Mayeul <mayeul....@free.fr>
wrote, quoted or indirectly quoted someone who said :

>> I want a Set<Y> where X implements Y.
>
>This conversion exactly as asked:
>
>Set<X> setOfX = obtainSetOfX();
>Set<Y> setOfY = new YourPreferredSetImplementation<Y>(setOfX);

thanks. I have written an SSCCE to explain this in tedious detail.
See http://mindprod.com/jgloss/generics.html#CONVERTINGSETS

markspace

unread,
Feb 3, 2012, 5:12:46 PM2/3/12
to
On 2/2/2012 4:29 PM, Roedy Green wrote:

> Perhaps it is time to read-read all the generics docs and see if they
> make more sense now with some practical experience under my belt.


If you feel seriously that you need more explanation, try O'Reilly's
"Learning Java", third edition. It has one of the better explanations
of generics I've found. It's big book to buy just for the generics
section, but not really that much money in the grand scheme of things.
Can you imagine some other way to pay $40 - $50 and get someone to
explain a difficult programming concept? I can't.


markspace

unread,
Feb 3, 2012, 5:25:50 PM2/3/12
to
On 2/2/2012 6:25 PM, Roedy Green wrote:

> thanks. I have written an SSCCE to explain this in tedious detail.
> See http://mindprod.com/jgloss/generics.html#CONVERTINGSETS


From your example,

static void showDogs2( Set<? extends Dog> dogs )

Is the correct solution. This is exactly what wildcards were designed
for. You should learn the acronym that Joshua Bloch invented as a
mnemonic: PECS - Producer Extends, Consumer Super.

In this case, showDogs2 is a producer in the sense that within the
method body, the variable "dogs" produces dogs for output, but the
method body doesn't put any dogs into the set, or modify the set in anyway.

This

Set<? extends Dog> someDogs2 = someDalmatians;

Is wrong, in the sense that it's too hamstrung to be useful. As your
comments indicate, it's hard to work with, and doesn't really do what
you want either. As a corollary, this

static Set<? super Dog> makeSomeDogs() {...

would be broken for the same reason. You almost never want to return a
type with a wildcard. Just give the user an single type, it will do
what you wanted much better than the wildcard version.

static Set<Dog> makeSomeDogs() {...

Finally, where do you use the super wild card then? Something like this:

static void copy(Set<? extends Dog> from, Set<? super Dog> to) {...


Lew

unread,
Feb 4, 2012, 1:30:39 AM2/4/12
to
On Thursday, February 2, 2012 4:29:09 PM UTC-8, Roedy Green wrote:
> On Thu, 02 Feb 2012 09:21:13 -0800, markspace <-@.> wrote, quoted or
> indirectly quoted someone who said :
>
> >I think this is covered in Effective Java. Generics are a compile time
> >thing
>
> Everything else in Java eventually seems obvious. Generics on the
> other hand get weirder and weirder the more I learn. I think it was a
> mistake to try to do generics purely at compile time. It is like
> trying to do all types purely at compile time.

Nonsense. It's perfectly fine at compile time as far as it goes. You want to
catch bugs at compile time rather than run time.

If you want generics at run time then add a type token.

Doing all types at compile time is the whole point of a strongly-typed language like Java. (OK, not all, but as much as you can.)

> Have we gone down that road too far now that Java can never be fixed

If it were truly broken that'd be a good question.

> with run-time generics info without starting over with some completely
> different notation? Then serialisation could work, containers could be
> allocated with the precise array type. You would not have so much
> under-the-hood casting.

This is an ancient and tired debate. Java does compile-time only with generics.
Sadly, this forces the programmer to fully understand the type assertions they
wish to make, and thus write better code. What a shame.

> Perhaps it is time to read-read all the generics docs and see if they
> make more sense now with some practical experience under my belt.

Generics is tricky. No question. Its difficulty exactly matches that of
complete type analysis. Type analysis is tricky. No question. Its difficulty
matches that of programming. Programming is tricky. No question.

--
Lew

Lew

unread,
Feb 4, 2012, 1:33:06 AM2/4/12
to
markspace wrote:
> I think is the above is the gist of how EJ handles it. Add a type token
> (the "type" variable) and test for types as they are added. If you want
> generics too, add them in:

If you're using Java 5 or later, you not only want generics, you must use them
where the type is generic. Per EJ.

--
Lew

Lew

unread,
Feb 4, 2012, 1:32:25 AM2/4/12
to
On Friday, February 3, 2012 2:12:46 PM UTC-8, markspace wrote:
> On 2/2/2012 4:29 PM, Roedy Green wrote:
>
> > Perhaps it is time to read-read all the generics docs and see if they
> > make more sense now with some practical experience under my belt.

http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html

> If you feel seriously that you need more explanation, try O'Reilly's
> "Learning Java", third edition. It has one of the better explanations
> of generics I've found. It's big book to buy just for the generics
> section, but not really that much money in the grand scheme of things.
> Can you imagine some other way to pay $40 - $50 and get someone to
> explain a difficult programming concept? I can't.

--
Lew

Arne Vajhøj

unread,
Feb 4, 2012, 8:49:06 PM2/4/12
to
On 2/2/2012 8:34 PM, Daniel Pitts wrote:
> On 2/2/12 4:29 PM, Roedy Green wrote:
>> Have we gone down that road too far now that Java can never be fixed
>> with run-time generics info without starting over with some completely
>> different notation? Then serialisation could work, containers could be
>> allocated with the precise array type. You would not have so much
>> under-the-hood casting.
> The point of generics is to add compile-time type safety. Runtime
> "generics" is a contradiction to that.

That was the way it was decided to do it for Java.

But it did have to be that way.

And runtime check can certainly add to type safety!

Arne

Daniel Pitts

unread,
Feb 6, 2012, 3:55:23 PM2/6/12
to
Yes, I never said anything against that. I said generics were designed
to add compile-time type safety. Runtime type safety is a different issue.

Arne Vajhøj

unread,
Feb 6, 2012, 8:47:44 PM2/6/12
to
Java generics was designed that way. There are nothing in the
generics concept that says it has to be that way.

Arne


Daniel Pitts

unread,
Feb 6, 2012, 8:51:13 PM2/6/12
to
Person A: Look at this green grass.
Person B: But Roses are red!

We're talking about Java generics, not about the concept of "generic"
generics.

Arne Vajhøj

unread,
Feb 6, 2012, 8:57:21 PM2/6/12
to
The discussion was about whether runtime generics info could be added.

Limiting that discussion to current design choices does not make
much sense to me.

Arne



0 new messages