-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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 reverse
method to NonEmptyTuple
#13752
Conversation
library/src/scala/Tuple.scala
Outdated
@@ -185,6 +185,14 @@ object Tuple { | |||
*/ | |||
type IsMappedBy[F[_]] = [X <: Tuple] =>> X =:= Map[InverseMap[X, F], F] | |||
|
|||
/** Type of the reversed tuple */ | |||
@experimental | |||
type Reverse[X <: Tuple] <: Tuple = X match { |
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 should be more efficient
type Reverse[X <: Tuple] <: Tuple = X match { | |
type Reverse[X <: Tuple] = ReverseImpl[EmptyTuple, X] | |
@experimental | |
private type ReverseImpl[Acc <: Tuple, X <: Tuple] <: Tuple = X match { | |
case x *: xs => ReverseImpl[x *: Acc, xs] | |
case EmptyTuple => Acc | |
} |
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'm not wrong this will lead to the compilation error non-private type Reverse in object Tuple refers to private type ReverseImpl
.
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.
yes you are right, thank you, in this case maybe the implementation can be moved to a public object to avoid namespace pollution :/ or rename it ReverseOnto
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.
Speaking for myself, I'm ok with adding that extra type, but I don't think that type could be reusable anywhere else. So probably it's good to hear the opinions of other Tuple
contributors. What do you think, @nicolasstucki @anatoliykmetyuk?
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.
An alternative that seems to work is
type Reverse[X <: Tuple] = Fold[X, EmptyTuple, [A <: Tuple, Y] =>> Y *: A]
But it would be better if it would be
type Reverse[X <: Tuple] <: Tuple = Fold[X, EmptyTuple, [A <: Tuple, Y] =>> Y *: A]
Opened #13813 to track this issue
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.
Hm, I've tried a variant with Fold
and got (tried to compile after clean
):
[error] 209 | type Reverse[X <: Tuple] = Fold[X, EmptyTuple, [A <: Tuple, Y] =>> Y *: A]
[error] | ^
[error] |Type argument [A <: Tuple, Y] =>> Y *: A does not conform to upper bound [_, _] =>> Any
fedba9c
to
ab1a19f
Compare
library/src/scala/Tuple.scala
Outdated
* consisting all its elements. | ||
*/ | ||
@experimental | ||
inline def reverse[This >: this.type <: NonEmptyTuple]: Reverse[This] = |
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 work for any Tuple
library/src/scala/Tuple.scala
Outdated
@@ -185,6 +185,14 @@ object Tuple { | |||
*/ | |||
type IsMappedBy[F[_]] = [X <: Tuple] =>> X =:= Map[InverseMap[X, F], F] | |||
|
|||
/** Type of the reversed tuple */ | |||
@experimental | |||
type Reverse[X <: Tuple] <: Tuple = X match { |
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.
An alternative that seems to work is
type Reverse[X <: Tuple] = Fold[X, EmptyTuple, [A <: Tuple, Y] =>> Y *: A]
But it would be better if it would be
type Reverse[X <: Tuple] <: Tuple = Fold[X, EmptyTuple, [A <: Tuple, Y] =>> Y *: A]
Opened #13813 to track this issue
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 think if we apply the proposed changes, it's a good solution. I explained in #13813 why we can't do another approach with Fold
.
library/src/scala/Tuple.scala
Outdated
* consisting all its elements. | ||
*/ | ||
@experimental | ||
inline def reverse[This >: this.type <: NonEmptyTuple]: Reverse[This] = |
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.
inline def reverse[This >: this.type <: NonEmptyTuple]: Reverse[This] = | |
inline def reverse[This >: this.type <: Tuple]: Reverse[This] = |
@@ -9,5 +9,6 @@ object MiMaFilters { | |||
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.append"), | |||
ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#TypeReprMethods.substituteTypes"), | |||
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.quoted.Quotes#reflectModule#TypeReprMethods.substituteTypes"), | |||
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.reverse"), |
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.
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.reverse"), |
If dotty's team is interested in taking this, I'm happy to move on with any changes 👍 |
@bishabosha since you were commenting on this I'll ping you. Is this something worth pushing forward? it looks like @Decel is willing if it is. |
I think its worth having, @Decel would you like to try a second attempt? |
I think we must finish up here and
type Fold[Tup <: Tuple, R, Z <: R, F[_, _ <: Tuple] <: R] <: R = Tup match
case EmptyTuple => Z
case h *: t => F[h, Fold[t, R, Z, F]] I think 2 is the best option available. But we need to come up with a design for the helper. |
object Tuple:
@experimental
object Helpers:
@experimental
type ReverseImpl[Acc <: Tuple, X <: Tuple] <: Tuple = X match
case x *: xs => ReverseImpl[x *: Acc, xs]
case EmptyTuple => Acc |
Looks good. Would you like to commit it to the PR? The only other change I think should be is |
fwiw: this definition of type Reverse[X <: Tuple] <: Tuple = Helpers.ReverseImpl[EmptyTuple, X]
// ^ cannot combine bound and alias Am I missing something? |
We can't write type bounds on aliases: type Reverse[X <: Tuple] = Helpers.ReverseImpl[EmptyTuple, X] Since |
I've addressed the review comments, thanks for your tips and suggestions. CI is green, so this could be reviewed once again. |
@@ -447,6 +449,79 @@ object Tuples { | |||
} | |||
} | |||
|
|||
// Reverse for TupleXXL | |||
private def xxlReverse(xxl: TupleXXL): Tuple = { | |||
if (xxl.productArity == 22) { |
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 branch should be removed - TupleXXL should not be constructed unless its arity is 23+
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.
Yeah, indeed. Good call, thanks
Experimental definitions shouldn't make warnings in mima so you can remove those changes to MiMaFilters |
Actually, I tried that locally before pushing it to the remote branch, and MiMa didn't like it. |
I need someone else to advise here |
If we don't mention anyone from the Scala3 team, this PR will get stuck as it was earlier. We all spent quite a lot of resources to get to this point, so can you @bishabosha @ckipp01 please step into finding the right person to perform a final push? But yeah, it's not an urgent thing at all. |
@Kordyjan what is the MiMa policy for experimental definitions? |
They need to be listed in the MimaFilters. Everything looks good here! |
So, |
it can be released as experimental in a patch release |
Good to know! So, I will do the final ping and stop bothering people with this. |
library/src/scala/Tuple.scala
Outdated
* consisting all its elements. | ||
*/ | ||
@experimental | ||
inline def reverse[This >: this.type <: Tuple]: Reverse[This] = |
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 method should also be moved to the Tuple
trait, currently it is in NonEmptyTuple
"scala.quoted.Quotes.reflectModule.defnModule.ErasedFunctionClass", | ||
|
||
// New feature: reverse method on Tuple | ||
"scala.NonEmptyTuple.reverse", |
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 will be affected when you move reverse
to Tuple
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.
reverse
should be a member of the Tuple
trait to match its implementation
@bishabosha here we go (again)... |
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.
Ok looks good, sorry could we also have a test that checks e.g. that (1, true, "hello"). reverse
is typed as (String, Boolean, Int)
and try to do a git rebase instead of pull - otherwise looks good
done
could you accomplish a squash of commits when merging? |
In Scala 2, there is a method
swap
onTuple2
. In Scala 3, we could have it generalized version for any non-empty tuple as a whole.