Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

Why is Map.keys returning a Collection and not a Set ? #6063

Closed
davidfestal opened this issue Mar 2, 2016 · 9 comments
Closed

Why is Map.keys returning a Collection and not a Set ? #6063

davidfestal opened this issue Mar 2, 2016 · 9 comments

Comments

@davidfestal
Copy link
Contributor

No description provided.

@gavinking
Copy link
Contributor

Fixed.

@davidfestal
Copy link
Contributor Author

Thanks !

gavinking added a commit that referenced this issue Mar 5, 2016
gavinking added a commit that referenced this issue Mar 5, 2016
@gavinking gavinking reopened this Mar 5, 2016
@gavinking
Copy link
Contributor

This fix has now been moved to the 6063 branch.

@gavinking gavinking modified the milestones: 1.3, 1.2.2 Mar 5, 2016
@ePaul
Copy link
Contributor

ePaul commented Mar 13, 2016

This looks like a non-backwards-compatible change – not for consumers, but for implementers of the interface. Whoever did refine this method (e.g. because there was a more efficient implementation) declaring the return type as Collection<Key> now has a class which doesn't compile anymore.

I don't know enough about binary compatibility to be sure, but from afar it looks like it is compatible neither for consumers nor for implementors on the JVM (because the erased return type is part of the signature).

@gavinking
Copy link
Contributor

So, given the version number upgrade, I would advocate that we put this on the table for 1.3.0.

It's a break to BC, but one that I still insist is pretty minor. WDYT?

@gavinking gavinking modified the milestones: 1.3.0, 1.4 Sep 1, 2016
@jvasileff
Copy link
Contributor

My only thought would be that I was hoping we'd get more bang for the buck with the next compatibility breaking release. I know there are other things that we probably don't have time for.

Regarding the Compatibility

  • This change would cause new modules calling keys on Maps produced by old modules to fail at runtime.

But also:

  • This change would cause old modules calling keys on Maps produced by new modules to fail at runtime.

And even:

  • This change would cause old modules calling keys on Maps produced by old modules to fail at runtime.

The second incompatibility is slightly surprising, since Correspondence.keys still has a return type of Collection, so any newly compiled class that satisfies Map will support both. But, it seems that bridge methods don't actually help here, since the bridge is on the class and not the interface, which doesn't know about the Collection returning alternative.

If we call the old binary below from within a new runtime, we get:

shared void callKeys(Map<Anything,Anything> map) {
    Correspondence<Nothing> corr = map;
    noop(corr.keys); // ok
    noop(map.keys);  // java.lang.NoSuchMethodError: ceylon.language.Map.getKeys()Lceylon/language/Collection;
}

and from the above, it follows that old binaries like this fail too:

noop(HashMap { 1 -> 1 }.keys); // java.lang.NoSuchMethodError: ceylon.language.Map.getKeys()Lceylon/language/Collection;

Finally, more surprisingly, even if the old binary were to first cast to Correspondence, it would still fail!

Correspondence<Nothing> corr = HashMap { 1 -> 1 };
noop(corr.keys); // java.lang.NoSuchMethodError: ceylon.language.Map$impl.getKeys()Lceylon/language/Collection;

The reason is that the old HashMap is using the new Map$impl at runtime, which doesn't have the method in question, since Map$impl doesn't implement Map, and therefore javac doesn't create a bridge for Collection's Object getKeys()!

public final class Map$impl<Key, Item> implements .java.io.Serializable { ... }

TL;DR: Pretty much anything involving Map.keys and old modules will fail.

@quintesse
Copy link
Contributor

quintesse commented Sep 1, 2016

@jvasileff paints a bleak picture for such a seemingly small change. Personally I don't think the breakage is worth the relatively small advantage the change brings.
Perhaps we could create a new bc-incompatible tag and keep issues marked like that around until we really break compatibility (like the one we have planned for the mix-ins) and then apply them all in one go?

@gavinking
Copy link
Contributor

gavinking commented Sep 2, 2016

Alright, fine, so not for 1.3.0. :-(

@gavinking gavinking removed this from the 1.4 milestone Aug 26, 2017
@gavinking
Copy link
Contributor

Done, finally.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants