-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add missing IArray operations #11354
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
Add missing IArray operations #11354
Conversation
e86d821
to
79743c7
Compare
79743c7
to
d5dcb7b
Compare
fabcb58
to
16b2ed7
Compare
library/src/scala/IArray.scala
Outdated
@@ -102,7 +100,7 @@ object opaques: | |||
|
|||
/** Flattens a two-dimensional array by concatenating all its rows | |||
* into a single array. */ | |||
extension [T](arr: IArray[T]) def flatten[U: ClassTag](using T => Iterable[U]): IArray[U] = | |||
extension [T](arr: IArray[T]) def flatten[U: ClassTag](using asIterable: T => Iterable[U]): IArray[U] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are against adding new implicit conversions should we simplify the definitions of flatMap
, WithFilter.flatMap
, flatten
, unzip
, unzip3
, transpose
?
For this one the alternative is to define it as
extension [T](arr: IArray[Iterable[T]]) def flatten: IArray[T] = ...
We could also add an overload for
extension [T](arr: IArray[IArray[T]]) def flatten: IArray[T] = ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll need an implicit conversion from IArray[T]
to Iterable[T]
anyway, because I can to be able to give IArray
s in the flatMap
methods of List
and other collections.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the conversion be to Iterable[T]
or directly to immutable.ArraySeq[T]
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
immutable.ArraySeq
sounds reasonable to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This allowed me to remove many redundant operations. See the second commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with using Conversion
instances is that you get a feature warning.
there were 1 feature warning(s); re-run with -feature for details
If you run with -feature
you get something like this
|Use of implicit conversion given instance genericWrapAnyRefIArray in object IArray should be enabled
|by adding the import clause 'import scala.language.implicitConversions'
|or by setting the compiler option -language:implicitConversions.
|See the Scala docs for value scala.language.implicitConversions for a discussion
|why the feature should be explicitly enabled.
To prevent this you can use an old-style implicit def. Or, alternatively, change checkImplicitConversionUseOK
to make a special case for conversions coming from IArray
. But the second alternative requires a discussion what the policy wrt implicit conversions should be. So I think it's easiest for now to simply revert to implicit defs for the conversions here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean flatMap
as in the following example?
for
x <- List(1, 2)
y <- IArray(1, 2)
yield ...
For this, we do not need the implicit conversion. Actually it did not work without the implicit conversion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used implicit def
s and aligned the implementation with the one for Arrays
001b436
to
a61aeea
Compare
a61aeea
to
85b699e
Compare
library/src/scala/IArray.scala
Outdated
|
||
/** Conversion from IArray to immutable.ArraySeq */ | ||
extension [T](arr: IArray[T]) def toSeq: immutable.ArraySeq[T] = | ||
immutable.ArraySeq.unsafeWrapArray(arr.asInstanceOf[Array[T]]) | ||
given genericWrapIArray[T](using DummyImplicit): Conversion[IArray[T], scala.collection.immutable.ArraySeq[T]] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the DummyImplicit
s, here and below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I don't I get an error at call site
[error] -- [E007] Type Mismatch Error: library/src/scala/runtime/TupleXXL.scala:26:18
[error] 26 | while i < es.length do
[error] | ^^
[error] |Found: (TupleXXL.this.es : IArray[Object])
[error] |Required: ?{ length: ? }
[error] |Note that implicit extension methods cannot be applied because they are ambiguous;
[error] |both object IArray in package scala and given instance genericWrapIArray in object IArray provide an extension method `length` on (TupleXXL.this.es : IArray[Object])
Maybe they should be placed in Predef as are the ones for Arrays. But adding them to stdLibPatches/Predef.scala
crashed the compiler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoided this with implicit def
library/src/scala/IArray.scala
Outdated
*/ | ||
@SerialVersionUID(3L) | ||
sealed abstract class IArrayBuilder[T] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hum, now that I see it here, I don't think it's the right place for this one, in fact. ArrayBuilder
is a top-level class in scala.collection.mutable
, even though Array
is in scala.*
. By analogy, IArrayBuilder
should also be a top-level class in scala.collection.mutable
(yes, mutable
, like StringBuilder
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to scala.collection.mutable
library/src/scala/IArray.scala
Outdated
/** A companion object for array builders. | ||
*/ | ||
object IArrayBuilder { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be a way to re-use array builders here. I believe there is an operation where you create a builder by using an existing builder and adding a post-processing step. In this case the post-processing step would be simply asInstanceOf[IArray[T]]
. Can we use that one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could still have specialized versions for each primitive type, but we would not need to manually re-implement all the methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed! This should probably be as easy as
@inline def makeIArrayBuilder[T: ClassTag]: Builder[T, IArray[T]] =
mutable.ArrayBuilder.make[T].mapResult(r => r: IArray[T])
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reimplemeted IArrayBuilder
and moved it to scala.collection.mutable
.
c687c65
to
b26da40
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM other than the dangerous import, and possibly using mapResult
for the builder.
* @tparam T type of the elements for the array builder, with a `ClassTag` context bound. | ||
* @return a new empty array builder. | ||
*/ | ||
@inline def make[T: ClassTag]: IArrayBuilder[T] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I take it that using mapResult
didn't work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It works, but the signature must be Builder[T, IArray[T]]
and it adds an extra indirection.
This would mean that we do not have the efficient addAll(xs: IArray[T])
and (xs: IArray[T], offset: Int, length: Int)
on that builder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we could also have addAll(xs: Array[T])
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have 2 options:
- Return
IArrayBuilder[T]
- Larger code
- Efficient
add
forIArray
/Array
- Possible to create a specialized
IArrayBuilder[T]
for primitive types
- Return
Builder[T, IArray[T]]
- Trivial code
- In-efficient
add
forIArray
/Array
- Impossible to create a specialized
Builder[T, IArray[T]]
for primitive types
I'm inclined to have the IArrayBuilder[T]
for performance reasons. Otherwise, we might see applications that use the ArrayBuilder
and then cast it to IArray
(or use IArray.unsafeFromArray
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Impossible to create a specialized Builder[T, IArray[T]] for primitive types
Hum, that's not the case. If you go through ArrayBuilder.make[T]
followed by a mapResult
, you will receive the specialized ArrayBuilder
, which will create a specialized Array[T]
, and the only thing is that is going to be cast to an IArray[T]
at the end of the day, which even when not specialized is a no-op. So we would definitely have the specialized builders for IArray
s.
Now we couldn't have addAll
specialized for IArray
and Array
, that's true. However addAll
is virtually never used on Builder
s.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue was alluding to is that the result of mapResult
does not have an overload of addAll
that receives Arrays.
But if it is almost never used I will remove this.
ee9f4aa
to
ad7ab97
Compare
b6899a5
to
46c0540
Compare
These call use `java.lang.System.arraycopy` to add the elements
* @param it the iterable collection | ||
* @return an array consisting of elements of the iterable collection | ||
*/ | ||
def from[A : ClassTag](it: IterableOnce[A]): Array[A] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this intended to return an Array
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ouch. Nope.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll fix it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #11387
ClassTag
from existing operations that did not need themIArrayOps.WithFilter
andIArrayBuilder
TODO
IArray
sstartsWith
(removed default parameters)flatMap
,WithFilter.flatMap
,flatten
,unzip
,unzip3
,transpose
.WithFilter
andIArrayBuilder
?Left for later