-
Notifications
You must be signed in to change notification settings - Fork 3.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
Right-bias Either #5135
Right-bias Either #5135
Conversation
Discuss! Some notes:
|
Can't you do something like |
@smarter the problem is the other case: If If you have e. g. |
I think the problem is if you want to introduce right-bias, you should also redefine sealed trait Either[+A, +B]
final case class Left[+A](a: A) extends Either[A, Nothing]
final case class Right[+B](b: B) extends Either[Nothing, B]
implicit class EitherOps[A, B](in: Either[A, B]) {
def flatMap[AA >: A, Y](f: B => Either[AA, Y]): Either[AA, Y] = in match {
case l @ Left (_) => l
case Right(b) => f(b)
}
def map[Y](f: B => Y): Either[A, Y] = in match {
case l @ Left (_) => l
case Right(b) => Right(f(b))
}
} |
@Sciss I agree with you, but this would break every single code base where someone wrote |
You could also safely use |
Why not deprecate |
@Sciss Might be possible. I just want to avoid making library author's lives who want to support 2.10-2.1x harder than necessary. |
I might have missed it, but it seems it's missing the
Oh wait, this is probably problematic... what to do when I wished Scala made the distinction between extracting tuples or case classes and guards or pattern matching. |
@EECOLOR |
* | ||
* {{{ | ||
* Right(12).right.foreach(x => println(x)) // prints "12" | ||
* Left(12).right.foreach(x => println(x)) // doesn't print |
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.
Right(12).foreach(x => println(x)) // prints "12"
Left(12).foreach(x => println(x)) // doesn't print
Updated! Things to discuss:
|
Here's a tiny nit-pick, when using right-biased either the most frequent path is generally the success path (i.e. the case Left (_) => _
case Right(_) => _ to case Right(_) => _
case Left (_) => _ because IIUC Scala will check each case sequentially. One of those things you'd never notice would can add up after a large number of calls. |
ea1d1c6
to
6af4b0a
Compare
@japgolly I flipped the checks in the |
@japgolly b/c "In the interest of efficiency the evaluation of a pattern matching expression may try patterns in some other order than textual sequence." I'd be interested in knowing whether the compiler does the right thing when there are just two choices. |
/rebuild |
e750f09
to
5cdb028
Compare
Added ScalaCheck tests. |
case Left(a) => this.asInstanceOf[Either[A, Y]] | ||
} | ||
|
||
/** Returns `None` if this is a `Left` or if the |
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.
"Returns 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.
Is this different from #5135 (comment)?
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 was referring to "Returns None
" in the doc comment. None
is an Option
. This method returns an Either
.
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.
Ah, I see, sorry. Looks like I fixed this in a later change.
Is a pattern match the best solution for implementing all these methods? It should compile to an instanceOf check but I would expect polymorphic dispatch to be faster still. |
My take on the discussion points:
|
re: warnings, have y'all tried https://github.com/ghik/silencer ? |
@SethTisue No, I haven't. In theory, it looks interesting. In practice, Scala.js cannot afford to have any Scala dependency besides Scala itself. Otherwise, we wouldn't be able to publish for new Scala versions as quickly as needed. Note that most of the ecosystem transitively depends on Scala.js being published at this point, so we need to stay very close to the root of the dependency graph. |
I wonder if we should delay the deprecation of community: how are y'all feeling about this? now that 2.12.0-RC1 has been out for a few weeks supporting 2.11/2.12 cross-building was one of our core promises for 2.12 in addition to the comments on this in the last 13 days, see also previous discussion back in June, beginning with #5135 (comment) |
I would rather not deprecate it immediately. The benefit of right-biasing need not come with such a heavy penalty of changing existing code and living with deprecation warnings. Yes, we'll be tied to .right and .left for longer, but the cost is relatively low if they are things that people don't want to use, and if people do want to use them, why are we taking them away so fast? |
+1 for delaying the deprecation until 2.13. This also has the benefit of giving us some time to consider what other changes (if any) we want to make to |
My 2 cents: Other than two, reported scalac issues, Is it not possible to have a standard "2.12 fwd compat" module for 2.10 and 2.11? And/or a backwards compat module for 2.12 so existing code works out-of-the-box? Or in other words, keep the change but have tools and strategies in place for easy migration. |
It's a shame, but I'm also in favour of postponing the deprecation. I'd like to see support for early migration to the new form though. |
Yep, seems to do the trick, nice one (I can stop creating impl package objects for these then) 👍 scala> import scala.util._
import scala.util._
scala> val e: Either[String, Int] = Right(1)
e: scala.util.Either[String,Int] = Right(1)
scala> e.map(_ + 1)
<console>:16: error: value map is not a member of scala.util.Either[String,Int]
e.map(_ + 1)
^
scala> import fs2._
import fs2._
scala> e.map(_ + 1)
<console>:19: error: value map is not a member of scala.util.Either[String,Int]
e.map(_ + 1)
^ |
we discussed this at a Scala team meeting as well. there seems to be a consensus that the deprecation should be delayed. I'll make a PR for 2.12.0-RC2 |
@SethTisue Thanks for the heads up. Is there a rough ETA for 2.12.0-RC2? And related to that, what would the advice be for a project like cats that has made some unpublished changes around this, but is yet to publish as 2.12.0-RC1? ie should it hold off on a 2.12.0-RC1 release or....? |
We plan to merge the last few RC2 PRs this week, and release next week,
|
👍 |
We're hoping to freeze it in the next couple days, so then there will be a nightly which is a release-candidate-candidate. If all goes well, RC2 could conceivably hit Maven Central next week sometime. Keep an eye on https://github.com/scala/scala/milestones/2.12.0-RC2
Unless there's a great deal of extra hassle involved, I would still strongly recommend everyone try to publish for 2.12.0-RC1 — especially a popular dependency like Cats. The best way to avoid having to do an RC3 (heaven forbid) is for everyone to be doing as much testing/publishing as possible now. |
for two reasons: * to facilitate warning-free cross-compilation between Scala 2.11 and 2.12 * because it's not clear that .swap is a good replacement for .left Either.right seems almost certain to be deprecated in 2.13. Either.left's future is uncertain; see discussion (and links to additional discussions) at scala#5135
* scala/scala#5135 - `Either` became right-biased in Scala 2.12 * scala/scala#6682 - `either.right` becomes a deprecated field with Scala 2.13 With Scala 2.13, it's no longer possible to test an `Either`'s right value using ScalaTest's `EitherValues` without getting a deprecating warning - ie writing: ``` either.right.value should be > 9 ``` will give you this on compile: ``` method right in class Either is deprecated (since 2.13.0): Either is now right-biased, use methods directly on Either ``` Given that `Either` is now right-biased, this change gives us the ability to write: ``` either.value should be > 9 ```
* scala/scala#5135 - `Either` became right-biased in Scala 2.12 * scala/scala#6682 - `either.right` becomes a deprecated field with Scala 2.13 With Scala 2.13, it's no longer possible to test an `Either`'s right value using ScalaTest's `EitherValues` without getting a deprecating warning - ie writing: ``` either.right.value should be > 9 ``` will give you this on compile: ``` method right in class Either is deprecated (since 2.13.0): Either is now right-biased, use methods directly on Either ``` Given that `Either` is now right-biased, this change gives us the ability to write: ``` either.value should be > 9 ```
There are no incompatible changes.
The only possibility of breakage that exists is when people have added
extension methods named map, flatMap etc. to Either in the past doing
something different than the methods added to Either now.
One detail that moved the scales in favor of deprecating LeftProjection
and RightProjection was the desire to have toSeq return
scala.collection.immutable.Seq instead of scala.collection.Seq
like LeftProjection and RightProjection do.
Therefore keeping LeftProjection and RightProjection would introduce
inconsistency.
filter is called filterOrElse because filtering in a for-comprehension
doesn't work if the method needs an explicit argument.
contains was added as safer alternative to
if (either.isRight && either.right.get == $something) ...
While adding filter with an implicit zero value is possible, it's
dangerous as it would require that developers add a "naked" implicit
value of type A to their scope and it would close the door to a future
in which the Scala standard library ships with Monoid and filter could
exist with an implicit Monoid parameter.