Migrating methods in Collections

Ron Pressler ron at paralleluniverse.co
Mon Dec 21 20:50:21 UTC 2015

> On Dec 21, 2015, at 8:03 PM, Brian Goetz <brian.goetz at oracle.com> wrote:
> > I think people would be pretty ticked off if Map.get() just went away. 
> I think the response would be: "Those idiots decided to change their 
> libraries for their own reasons, I have no intention of ever 
> specializing my Map, and yet I have to change my code anyway."

But those same people would also consume an API which returns a List<int> and then find those same methods gone anyway. 

Although my suggestion would probably require a tool (a javac plugin?) to migrate sources, though. Go has “go fix”, but Java has had such a tool for a long time
 (I think James Gosling worked on it). I know I’m making my suggestion sound even scarier, but I think it beats adding a type system trick for the purpose of source compatibility (more on that later).

> Secondarily, while we might plan to do this to Collections in version N, 
> other generic libraries (including other JDK libraries) might wait until 
> N+3 to anyfy their own. Realistically this means we'd be forced to 
> expose whatever versioning mechanism we use here for general use -- 
> which seems at least as potentially confusing (and open to misuse) as 
> partial methods. 

I don’t know if it would be as confusing (I don’t think it would), but it may possibly also be used to solve the 64-bit index problem. 

> While a method-grained versioning mechanism seems like 
> it might solve a lot of problems (for example, we wouldn't have needed 
> to do default methods), so far, we've not seen any satisfactory theory 
> that we'd want to consider building on -- there have been many attempts 
> in the academic literature but I think method versioning in object 
> oriented systems is still an unsolved problem. So I'm wary this could 
> degenerate into something far worse than partial methods -- a bad 
> versioning system.

Default methods were also necessary for binary compatibility. I’m talking of something much simpler (like @AvailableUpTo(9)).

> Now, I don't want to devolve into premature syntax bikeshedding, but my 
> point is: I don't think the it is the concept that is fundamentally 
> confusing, its just that we will (in addition to convincing ourselves 
> that the model is sound, which is the task currently in front of us) 
> then additionally have to fit it into a syntactic expression that makes 
> sense to Java users. (Coming up with a good syntactic form is also 
> hard, so I want to first ensure we have a sound theoretical model before 
> taking on unnecessary additional work.)

Maybe. But partial methods are a clever deprecation mechanism that’s built into the type system. Not that I categorically oppose type-system cleverness (superation seems great), but source compatibility — which Java doesn’t always preserve and has a good mechanism to manage anyway — doesn’t seem like a good enough reason.
>> > 
> Partial methods also allow you to do this:
> interface List<any T> {
> <where T=int> default long sum() { ... }
> }
> which is not strictly related to migration. (Personally, I don't love 
> this as a feature, because it's weaker than it first appears (think: 
> "The Expression Problem"), and when you try to shore up these weaknesses 
> with a more powerful slicing mechanism like <where T extends Numeric> it 
> starts to get more complex 


> -- but this form of partial method is also 
> part of the current best approach we've got for being able to replace 
> IntStream with Stream<int>, which is easier in some ways, and harder in 
> others, than Collections.)

Is the goal to somehow make IntStream into Stream<int> or to deprecate IntStream? If the latter, I also see no reason why sum (but not other sensible operations) must be part of Stream<int>. In any event, a more general solution would be extension methods (I am not proposing we add those). 

> However (picking up the above syntactic form), would you find these 
> signatures terribly confusing?
> interface Stream<any T> {
> ...
> int sum(Stream<int> this);
> long sum(Stream<long> this);
> double sum(Stream<double> this);
> }

What about other numeric types? Maybe 

   BigInteger sum (Stream<BigInteger> this)

too? And what if users would be able to add their own numeric value types? It’s a weird way to add what are essentially extension methods, and on the wrong side of the expression problem as you noted. If, OTOH, we’d have a “numeric” interface on value types and integers (as I think John alluded to), that might make things better.

Also, it’s not so much a question of confusion as of “does it fit with the feel of Java?”


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/valhalla-spec-experts/attachments/20151221/af61c764/attachment-0001.html>

More information about the valhalla-spec-experts mailing list