-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Integrate converters from java8-compat [ci: last-only] #7458
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Yes I think so, it's way to easy to use the wrong one and not understand why it's not working, there should either be only one JavaConverters that brings everything with it, or two objects with different names. |
|
There are a number of decisions to be made about naming.
Opinions welcome, I'll try to bring this together in a consistent way. |
e3d9d6e to
c4a55cc
Compare
|
I started adding commits for the stream converters. As suggested in our team meeting, i made the The reasons for this choice:
The |
|
Hum, I don't like this bit about the streams. Java collections are one thing, we've implemented them. Function converters, well, we haven't implemented Java's function types, but we could do it. Streams, that's another story. It's a big chunk of code. It's unlikely that we'll implement them in Scala.js anytime soon, if ever. That means that this PR is reintroducing in the standard library APIs that will compile in Scala.js but won't link, because of missing transitive classes. This is one of the sources of confusion most often seen in Scala.js. I was looking forward to a future with a standard library that compiles iff it links (e.g., with |
|
I understand your position. The thinking behind this PR: Scala provides interop with Java out of the box. But in 2.12 we ship integration only with traditional Java collections, even though we require the Java 8 runtime. We should keep our interop up to date with the (core) platform, and not fall (stay) behind. |
aad1a31 to
7f9db09
Compare
|
Pushed a few changes to ensure conversions between primitive arrays, steppers, java streams and accumulators don't box. I used https://github.com/google/allocation-instrumenter for that, test code here: https://gist.github.com/lrytz/900dcc6aba5479ae615098bb0d74b1ee. |
2655a87 to
848c86d
Compare
|
The core of this PR is done now
Function and option converters are the same as in java8-copmpat. For the stream integration there are a few differences in the design, I'll point them out in the summary below. Details about stream integration:
It would be good to get reviewing going for the parts that are done so far, and of course I'd be very happy if someone is motivated to help me finishing this up :) |
|
How about adding |
|
That works for me, I didn't have a good reason to pick one over the other so far. |
|
@lrytz - Do you need help finishing this up? It looks like you've made great progress so far, so you're probably the best situated to wrap up the more intricate of the remaining steps. But I still mostly remember how the code works, so I could also try if I get the time. |
|
@Ichoran this would be a good PR for you to adopt. Lukas is on leave. |
|
In the mean time, I've done a quick rebase |
This ensures that mapping an Int=>Int over an IntAccumulator produces another IntAccumulator (not an AnyAccumulator). Also override some operations in specialized accumulators to profit from function specialization.
|
scabot doesn’t see beyond 100 commits
|
|
@Ichoran for me, this is ready to go. I pushed the fix to Should we merge? It would unblock some projects in the community build. |
|
FWIW, I just tested this PR with Scala.js, and
|
|
@lrytz - Sounds good. I didn't get to the tree stepper thing last night, but I'll at least file a bug report and maybe fix it tonight. |
With changes mostly coming from scala/scala#7458
With changes mostly coming from scala/scala#7458
Avoid unexpected class casts due to potential misuse in subclasses of the following cunning trick, which allowed for centralized implementation of common factory methods, assuming the right overrides are provided in subclasses: `protected type IterableCC[X] = CC[X] @uncheckedVariance` Risk of not overriding correctly illustrated by https://gist.github.com/lrytz/fe09791208969f07e211c5c8601db125. It's basically an encoding of MyType, which is only sound under pretty severe restrictions, which are not enforced by the compiler. Instead, we mix in a default implementation of the various factory methods whenever we are in a trait where the collection's type is known (and of the regular shape CC[A] or MapCC[K, V]). It would be nice if we could conditionally mix in this trait into the *Ops traits whenever `C =:= CC[A]`, but we don't have that kind of inheritance (private inheritance would be nice too, I guess, since the `*FactoryDefaults` traits don't really add much utility to the public signature of these collection classes). While we're at it, also add an `empty` method at the top of the hierarchy to facilitate the switch to dotty's for comprehensions (since we want the stdlibs between Scala 2 & 3 to be the same, and 2.14 will try to only make backwards compatible changes from 2.13). Motivated by the intersection of scala#7458, scala#7929, scala#7800 (better refchecks and compiling with dotc revealed part of the problem) 🤯 Co-authored-by: Lukas Rytz <[email protected]>
Add Java/Scala converters for options, function types and Java stream, as known from the java8-compat library. Rearrange the existing collection converters to fit into the new scheme.
Naming overview:
scala.jdkwith objectsCollectionConverters(classic Java collections, similar tocollection.JavaConvertersin 2.12),StreamConverters,FunctionConvertersandOptionConvertersOptionConverters.toJava(Some("hi")). These methods are recommended when writing Java code.XConverterhas a nested objectOpsproviding extension methods (asJava,toScala, etc). Using these extension methods is recommended when writing Scala code.as...when a wrapper is created (collection converters),to...when a new independend object is created (options)o.asJavacreates the most specific possible Java type foro. Other possible target types can be created witho.asJavaXNote that the split between explicit conversions and extension methods (in
Ops) is new. In 2.12,JavaConverterscontained both. Also the function converters in java8-compat mixes them up. We decided to split this systematically now.Function converters
java8-compat provided full-named explicit conversions (now available as
FunctionConverters.asJavaDoubleUnaryOperator, for example) and only two extension methods:asJavaandasScala. TheasJavaextension method creates the most specialized possible Java function type.If a different Java function type is required, java8-compat required to fall back on the explicit conversion. Here, we instead add additional extension methods for the cases where a more generic version than
asJavais available, for example((x: Int) => x > 0).asJavaFunction.Option converters
Trivial
Collection Converters
Functionality is the same as in 2.12. The extension methods have been renamed for simplicity. Now,
asJavais always avaliable and creates a wrapper for the most common and specialized Java type. Conversions to other Java types have longer extension method names (asJavaDictionary).scala.collection.convert.ImplicitConversionsis deprecated (no replacement, use extension methods).collection.JavaConvertersis deprecated in favor of the newCollectionConverters.Stream Converters
scala.collection.Stepper[A]is small interface that provides iterator-like methodshasStepandnextStep. Steppers are specialized for Int, Long and Double (like Java Streams), so consuming a primitive collection with a Stepper doesn't box the elements. Steppers can be converted tojava.util.Spliterator,java.util.Iteratorandscala.IteratorIterableOncegets astepper[S](shape: StepperShape[S]): Svirtual method (In java8-compat, this was an extension method). TheStepperShapeensures that collections ofInt/Long/Doubleproduce primitive steppers.IndexedSeqOpsoverridesstepperto returnS with EfficientSplit.stepper: Stepperget aasJavaSeqStreamextension methodstepper: Stepper with EfficientSplitget aasJavaParStreamextension methodstepper,asJavaSeqStreamandasJavaParStreamextension methodscollection.convert.Accumulatorcollection type is added, similar toUnrolledBuffer, but with hand-specializedInt/Long/DoubleAccumulatorand a genericAnyAccumulatorsubclasses.List[Int]to anIntAccumulatorfor processing a parallel stream. (Converting to anArray[Int]is also a good option).AccumulatorextendsIterable(in java8-compat, the collection was not integrated into the hierarchy). Converting acollection.to(Accumulator)automatically builds a primitive accumulator for primitive element types (java8-compat has anaccumulateextension methods to convert from Scala collections).toScalaextension method that works the same as thetomethod in collections. (java8-compat has anaccumulateextension method to convert to an Accumulator. This is now done with.toScala(Accumulator).)MapOpsgetskeyStepperandvalueSteppervirtual methods. They can be overridden in subclasses to return stepperswith EfficientSplit.MapOpsgetsasJavaSeqKeyStream/asJavaSeqValueStreamandasJavaParKeyStream/asJavaParValueStreamextension methodsDuration Converters
Convert between Java and Scala duration types, straightforward
Future Converters
...
TODO
Done
asJavaSeqStreamto onlyseqStream(and similar for all stream conversions)?, No, keep theasJavapart (decided on team meeting)Accumulatorclasses in packagescala.collection.convert? Yes, the main use case is parallel building, so it's really useful for Streams interop (decided on team meeting)scala.jdk? Yes (decided on team meeting)..iterator.opwould do the same)Non-blockers