right-biasing Either

2,068 views
Skip to first unread message

Jason Zaugg

unread,
May 14, 2012, 3:08:34 AM5/14/12
to scala-debate
(A follow-up from ticket SI-5793. [1])

Apologies in advance to any left-handers out there.

I propose (not that I'm the first) to right-bias Either. Concretely,
this means we would add map/flatMap etc directly to Either, rather
than going through RightProjection. RightProjection could probably
deprecated.

Is there any previous discussion on this? Any arguments against?

-jason

[1] https://issues.scala-lang.org/browse/SI-5793

Kevin Wright

unread,
May 14, 2012, 3:36:38 AM5/14/12
to Jason Zaugg, scala-debate
Tallying up those of us in Zeebox who would have directly benefitted from this, count me for +12 votes in favour.

--
Kevin Wright
mail: kevin....@scalatechnology.com
gtalk / msn : kev.lee...@gmail.com
vibe / skype: kev.lee.wright
steam: kev_lee_wright

"My point today is that, if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent": the current conventional wisdom is so foolish as to book that count on the wrong side of the ledger" ~ Dijkstra

√iktor Ҡlang

unread,
May 14, 2012, 4:49:01 AM5/14/12
to Kevin Wright, Jason Zaugg, scala-debate
Count me in for +1
--
Viktor Klang

Akka Tech Lead
Typesafe - The software stack for applications that scale

Twitter: @viktorklang

Jon-Anders Teigen

unread,
May 14, 2012, 5:19:58 AM5/14/12
to scala-debate
-1

The Unbiased Either is perfect for representing one of two values -
either the right or the left - without implying that one of them is
more "correct" than the other.

If there is bias towards right or left there is usually a good name
for that bias. For example Validation from Scalaz, and ParseResult
from the parser combinators. They are often fixed in one of the
parameters too, like Future.

That said, I do like the idea of a general right biased either, but I
really really don't want to sacrifice the unbiased one in in the
process.

/j

On May 14, 10:49 am, √iktor Ҡlang <viktor.kl...@gmail.com> wrote:
> Count me in for +1
>
> On Mon, May 14, 2012 at 9:36 AM, Kevin Wright <kev.lee.wri...@gmail.com>wrote:
>
>
>
>
>
>
>
>
>
> > Tallying up those of us in Zeebox who would have directly benefitted from
> > this, count me for +12 votes in favour.
>
> > On 14 May 2012 08:08, Jason Zaugg <jza...@gmail.com> wrote:
>
> >> (A follow-up from ticket SI-5793. [1])
>
> >> Apologies in advance to any left-handers out there.
>
> >> I propose (not that I'm the first) to right-bias Either. Concretely,
> >> this means we would add map/flatMap etc directly to Either, rather
> >> than going through RightProjection. RightProjection could probably
> >> deprecated.
>
> >> Is there any previous discussion on this? Any arguments against?
>
> >> -jason
>
> >> [1]https://issues.scala-lang.org/browse/SI-5793
>
> > --
> > Kevin Wright
> > mail: kevin.wri...@scalatechnology.com
> > gtalk / msn : kev.lee.wri...@gmail.com
> > <kev.lee.wri...@gmail.com>
> > twitter: @thecoda
> > vibe / skype: kev.lee.wright
> > steam: kev_lee_wright
>
> > "My point today is that, if we wish to count lines of code, we should not
> > regard them as "lines produced" but as "lines spent": the current
> > conventional wisdom is so foolish as to book that count on the wrong side
> > of the ledger" ~ Dijkstra
>
> --
> Viktor Klang
>
> Akka Tech Lead
> Typesafe <http://www.typesafe.com/> - The software stack for applications
> that scale
>
> Twitter: @viktorklang

Kevin Wright

unread,
May 14, 2012, 5:38:35 AM5/14/12
to Jon-Anders Teigen, scala-debate
Straight from the scaladoc:

"Represents a value of one of two possible types (a disjoint union.) Instances of Either are either an instance of Left or Right.

A common use of Either is as an alternative to Option for dealing with possible missing values. In this usage, scala.None is replaced with a Left which can contain useful information. Right takes the place of Some. Convention dictates that Left is used for failure and Right is used for success."

So we've already been advocating for quite some time that "right" is right, and that Either would typically be used *as though* it were biased.

I personally take the line that the established ScalaDoc is correct, and that the code should be modified to match it.  If "Right" is to take the place of "Some", then let's have the ability to map over it in exactly the same way - it would do wonders for my for-comprehensions!
--
Kevin Wright
mail: kevin....@scalatechnology.com
gtalk / msn : kev.lee...@gmail.com
twitter: @thecoda

√iktor Ҡlang

unread,
May 14, 2012, 6:06:58 AM5/14/12
to Jon-Anders Teigen, scala-debate
On Mon, May 14, 2012 at 11:19 AM, Jon-Anders Teigen <jte...@gmail.com> wrote:
-1

The Unbiased Either is perfect for representing one of two values -
either the right or the left - without implying that one of them is
more "correct" than the other.

If there is bias towards right or left there is usually a good name
for that bias. For example Validation from Scalaz, and ParseResult
from the parser combinators. They are often fixed in one of the
parameters too, like Future.

That said, I do like the idea of a general right biased either, but I
really really don't want to sacrifice the unbiased one in in the
process.

We're just talking about _adding_ methods, so if you want to continue using it as unbiased then that'd still be possible. I'm not all that for deprecating the rightPRojection since that'd give me the feeling of asymmetry, which just feels wrong to me.



--
Typesafe - The software stack for applications that scale

Twitter: @viktorklang

Daniel Sobral

unread,
May 14, 2012, 9:00:32 AM5/14/12
to Kevin Wright, Jon-Anders Teigen, scala-debate
On Mon, May 14, 2012 at 6:38 AM, Kevin Wright <kev.lee...@gmail.com> wrote:
> Straight from the scaladoc:
>
> "Represents a value of one of two possible types (a disjoint union.)
> Instances of Either are either an instance of Left or Right.
>
> A common use of Either is as an alternative to Option for dealing with
> possible missing values. In this usage, scala.None is replaced with a Left
> which can contain useful information. Right takes the place of Some.
> Convention dictates that Left is used for failure and Right is used for
> success."
>
>
> So we've already been advocating for quite some time that "right" is right,
> and that Either would typically be used *as though* it were biased.

Err, no. It says right before "A common use", so this does not
represent how Either should be used, but an example of how it is often
used. It does not preclude at all using Either as a union-replacement.
--
Daniel C. Sobral

I travel to the future all the time.

Kevin Wright

unread,
May 14, 2012, 11:32:33 AM5/14/12
to Daniel Sobral, Jon-Anders Teigen, scala-debate
Out of curiosity... How many examples can we come up with of Option being used in the wild, in a completely symmetric fashion that would suffer if it were to be biased?

Because I (for one) am *really* keen to just go the whole hog and have both Option and Either implement FilterMonadic, but wouldn't like to see this sort of thing cause a problem if there were obvious counter-examples in production somewhere!

Runar Bjarnason

unread,
May 14, 2012, 11:49:26 AM5/14/12
to scala-...@googlegroups.com
Yes, please.

Heiko Seeberger

unread,
May 14, 2012, 4:04:03 PM5/14/12
to scala-debate
On May 14, 2012, at 9:08 AM, Jason Zaugg wrote:

> (A follow-up from ticket SI-5793. [1])
>
> Apologies in advance to any left-handers out there.
>
> I propose (not that I'm the first) to right-bias Either. Concretely,
> this means we would add map/flatMap etc directly to Either, rather
> than going through RightProjection. RightProjection could probably
> deprecated.
>
> Is there any previous discussion on this? Any arguments against?

No arguments against. Vice versa, I frequently have the use case of treating Right as the right case and Left as the error case. Hence I always have to use Scalaz, which is not too bad per se and provides additional value (like applicative functors), but why not add this feature to the standard library?

Heiko

Chris Hodapp

unread,
May 14, 2012, 4:50:24 PM5/14/12
to scala-...@googlegroups.com
Why right-bias a class with an unbiased name like "Either" when the potential for creating a new class that doesn't have the wrong name exists?

Rex Kerr

unread,
May 14, 2012, 5:14:23 PM5/14/12
to Jason Zaugg, scala-debate
-1

I prefer unbiased Either.  If we wanted to provide an implicit conversion to Option (via right projection) I doubt I'd mind, but Either can be used (and I do use it) to store two alternative things without bias.  Adding bias will create a strong pressure for asymmetric code even though the conditions are symmetric.

If there is not an implicit conversion, I'd prefer a third class that was biased.  If we wanted to avoid stepping on the Scalaz names, "Excused" might work.

  --Rex

Kevin Wright

unread,
May 14, 2012, 5:16:18 PM5/14/12
to Chris Hodapp, scala-...@googlegroups.com
In a word... confusion!

Why create two types that do almost exactly the same thing, but one of them does it with a bit less ceremony in the overwhelmingly most common use-case?

I'm all for giving developers choice, but this seems to be taking it perhaps too far.  How can we possibly justify the maintenance burden of keeping two Either's around?  Not to mention the cognitive burden of having to explain the intricacies to new Scala users, especially those transitioning from Java.  I can just see it now:

"You should really use Maybe, not Either.  I know all the books in print right now don't even mention it yet, but you'll just have to trust me until you come to understand for-comprehensions better, and monads"

...Followed by the inevitable web search for monads and (more often than not) the resulting confusion followed by claims of Scala being too complicated and "academic". Then followed by the further inevitable repair of any damage so caused.

Even now, I still find myself fielding accusations of "but wasn't App deprecated?" - and that was a far simpler scenario, where we had two alternatives but one was deprecated.

If we're not keeping two variants around, then we should stick with the one we have, but fix it up to just do the Right Thing(tm).  It'll save a great deal of pain later!

Kevin Wright

unread,
May 14, 2012, 5:19:28 PM5/14/12
to Rex Kerr, Jason Zaugg, scala-debate
Is this-use case not better handled by a sealed marker trait and two subclasses for the symmetric alternatives?

√iktor Ҡlang

unread,
May 14, 2012, 5:32:43 PM5/14/12
to Kevin Wright, Rex Kerr, Jason Zaugg, scala-debate
... and change option to:

type Option[_] => Either[Unit,_]

;-)
--
Viktor Klang

Akka Tech Lead
Typesafe - The software stack for applications that scale

Twitter: @viktorklang

Erik Osheim

unread,
May 14, 2012, 5:35:00 PM5/14/12
to Rex Kerr, Jason Zaugg, scala-debate
On Mon, May 14, 2012 at 05:14:23PM -0400, Rex Kerr wrote:
> If there is not an implicit conversion, I'd prefer a third class that was
> biased. If we wanted to avoid stepping on the Scalaz names, "Excused"
> might work.

As a thought experiment, would you be OK with making Either biased as
Jason proposed, but introducing a new type that is unbiased? E.g.

sealed trait OneOf2[+A, +B]
sealed trait OneOf3[+A, +B, C+]
...
sealed trait OneOf22[...]

case class Item1[A](a:A) extends OneOf2[A, Nothing] with OneOf3[A, Nothing, Nothing] ...
case class Item2[B](b:B) extends OneOf2[Nothing, B] with OneOf3[Nothing, B, Nothing] ...
case class Item3[C](c:C) extends OneOf3[Nothing, Nothing, C] ...
case class Item4[D](d:D) extends OneOf4[Nothing, Nothing, Nothing, D] ...
...
case class Item22[A, B, ... V](a:A, b:B, ... v:V) extends OneOf22[..., V]

I tend to use sealed traits to handle this kind of symmetric
disjunction. The thing that's nice about something like OneOf versus
Either is that the name generalizes well to 21 variants you might want.

That said, I tend to use sealed traits instead of Either, so I'm mostly
bikeshedding. But I think that having a balanced OneOfN might be a bit
nicer than Either, since the pattern's a bit more general.

-- Erik

Kevin Wright

unread,
May 14, 2012, 5:40:23 PM5/14/12
to √iktor Ҡlang, Rex Kerr, Jason Zaugg, scala-debate
I already do something like that anyway :)

Spurned by jealousy for node.js, my latest project is written in a completely asynchronous style.  For me, "Either" is named "Future", and it's nicely right balanced...

In fact, it's *so* asynchronous that it may even get written one of these days!

Alec Zorab

unread,
May 14, 2012, 5:56:25 PM5/14/12
to Kevin Wright, √iktor Ҡlang, Rex Kerr, Jason Zaugg, scala-debate
I heard someone already wrote it and called it Akka...

missingfaktor

unread,
May 14, 2012, 6:02:36 PM5/14/12
to Rex Kerr, Jason Zaugg, scala-debate
On Tue, May 15, 2012 at 2:44 AM, Rex Kerr <ich...@gmail.com> wrote:
-1

I prefer unbiased Either.  If we wanted to provide an implicit conversion to Option (via right projection) I doubt I'd mind, but Either can be used (and I do use it) to store two alternative things without bias.  Adding bias will create a strong pressure for asymmetric code even though the conditions are symmetric.

If there is not an implicit conversion, I'd prefer a third class that was biased.  If we wanted to avoid stepping on the Scalaz names, "Excused" might work.

  --Rex


+1, except I think { Attempt, Success, Failure } would be better names to go for. (I think Validation is not a particularly good name as it describes only one case such a data type can be used for.)


On Mon, May 14, 2012 at 3:08 AM, Jason Zaugg <jza...@gmail.com> wrote:
(A follow-up from ticket SI-5793. [1])

Apologies in advance to any left-handers out there.

I propose (not that I'm the first) to right-bias Either. Concretely,
this means we would add map/flatMap etc directly to Either, rather
than going through RightProjection. RightProjection could probably
deprecated.

Is there any previous discussion on this? Any arguments against?

-jason

[1] https://issues.scala-lang.org/browse/SI-5793




--
Cheers,

Rex Kerr

unread,
May 14, 2012, 6:03:06 PM5/14/12
to Kevin Wright, Jason Zaugg, scala-debate
Of course it's not better to use a sealed marker trait.  That's considerably more boilerplate.  In some cases it's worth it to not have to deal with the left/right thing, but only _some_.  Of course I can always write my own Either.  (And I can write my own right-biased Either, also.)

What about just adding an "opt" method to Either that is right-biased and gives you an option?  This is a lot more compact than .right.toOption.

Or maybe I would like to see which methods exactly are being proposed for addition.  There are
  foreach(f: B=>Unit): Unit
  // right.foreach

  map[D](f: B=>D): Either[A,D]
  // right.map

  flatMap[C>:A,D](f: B=>Either[C,D]): Either[C,D]
  // right.flatMap

  mapOr[C>:A,D](wrong: => C)(f: B => Option[D]): Either[C,D]
  // right.flatMap(x => f(x).toRight(wrong))

  collectOr[C>:A,D](wrong: => C)(pf: PartialFunction[B,D]): Either[C,D]
  // right.flatMap(x => pf.lift.apply(x).toRight(wrong))

  rescue[D>:B](f: A => Option[D]): Either[A,D]
  // fold(l => f(l).map(o => Right(o)).getOrElse(Left(l)), r => Right(r))
   
  reject[C>:A](f: B => Option[C]): Either[C,B]
  // fold(l => Left(l), r => f(r).map(o => Left(o)).getOrElse(Right(r)))

  toOption: Option[B]
  // right.toOption

which all seem highly useful to me.  I'd actually be more interested in the change if we were going to add a really robust set of methods so that Either would be as generally powerful as Option (without having to left/right to get something usable).  (Might be good to add iterator/toList also.)  Bias with only minimal utility is much less interesting.

  --Rex

Kevin Wright

unread,
May 14, 2012, 6:23:22 PM5/14/12
to Rex Kerr, Jason Zaugg, scala-debate
Right-bias is not about being able to quickly convert to an Option, it's about being able to chain a sequence of operations, each of which takes the right output of the previous operation and yields an either.

Most especially, it's about being able to do so in the context of a for-comprehension.


Implicit conversion to Option wouldn't help here, it would actually harm.  Comprehensions like this should output either the Right result of the processing sequence, or the Left failure from whichever step ran into problems.  If converted to an Option then we'd be forced to either throw errors as exceptions, or to simply discard failures and simply know that something didn't work as expected - neither choice is especially appealing.


Deprecating Either in favour of a different name makes sense, but it then leaves us with a lot of source to be updated, and a lot of existing documentation (books, articles, etc.) that is no longer valid.

Tony Morris

unread,
May 14, 2012, 6:30:57 PM5/14/12
to scala-...@googlegroups.com
Some history. I wrote scala.Either.

Originally, it was Right-biased. A peer convinced me to remove the bias,
partly because abstracting on the type constructor was not something
that regular scala libraries do, and unlike Haskell, Scala type
constructors can be rearranged on the fly, therefore, there appeared to
be no real advantage. I agreed.

I have since regretted it, given that there are other advantages than
those I dismissed at the time. I vote +1 for this proposal.

--
Tony Morris
http://tmorris.net/


Rex Kerr

unread,
May 14, 2012, 10:16:37 PM5/14/12
to Kevin Wright, Jason Zaugg, scala-debate
On Mon, May 14, 2012 at 6:23 PM, Kevin Wright <kev.lee...@gmail.com> wrote:
Right-bias is not about being able to quickly convert to an Option, it's about being able to chain a sequence of operations, each of which takes the right output of the previous operation and yields an either.

Most especially, it's about being able to do so in the context of a for-comprehension.

Fair enough.  But if this is the only thing it can do, I'm not sure it's worth it.  You can do the chaining clumsily (i.e. by putting in a .right as a separator between all your normal calls) everywhere except for comprehensions.  So the idea is that a for-comprehension is worth more than the symmetry.  Maybe.

I think the maybe could be turned into a clear win _if_ extra functionality was provided for the most common use cases, and these involve _not just_ flatMap but the other methods I wrote down below.  Namely:

  (1) If my option (or partial function) fails, I want to put an error in Left
  (2) I want to try to recover from some fraction of the Left cases
  (3) I want to throw away some fraction of the Right cases

If something like this is included also, then I'd agree: we've gained something important.  Simply not having to write out the desugared version of the for loop seems like not much of a win to me given that things like
  Either[Either[IllegalArgumentException,IOException], DataSet]
  Either[IllegalArgumentException, Either[BigInt, Formula]]
will no longer make so much sense.

  --Rex

Lee Mighdoll

unread,
May 15, 2012, 2:37:59 AM5/15/12
to Rex Kerr, Kevin Wright, Jason Zaugg, scala-debate
Most especially, it's about being able to do so in the context of a for-comprehension.

Fair enough.  But if this is the only thing it can do, I'm not sure it's worth it.  
 
+1 for for comprehensions.  They enable a code style that's very clear, and really a nice scala selling point when compared to more mainstream languages.  Let's make for comprehensions shine.  

Note that in for comprehensions the existing Either implementation isn't just extra boilerplate to pick a projection on every line.  Definitions don't work.  

As is, I don't think we can recommend using Either to our teams today, certainly not without bunch of caveats and extra explanation.  That argues we ought fix the existing Either, rather than pick a new class.

And I don't think there'd be much cost to the change.  There'd be little mental shift required of the community if the right side of the Either gets blessed.  I'll guess that the vast majority of existing Either users mentally associate Either with the asymmetric use case already (even as we appreciate the nifty symmetry of the existing design).  Think Either, and I bet most think of a tool for dealing with Left(error) and Right(result).  

+1 for biasing Either in 2.10

Jason Zaugg

unread,
May 15, 2012, 2:44:25 AM5/15/12
to l...@underneath.ca, Rex Kerr, Kevin Wright, scala-debate

missingfaktor

unread,
May 15, 2012, 3:06:03 AM5/15/12
to Jason Zaugg, l...@underneath.ca, Rex Kerr, Kevin Wright, scala-debate

Heather Miller

unread,
May 15, 2012, 4:25:18 AM5/15/12
to Jason Zaugg, l...@underneath.ca, Rex Kerr, Kevin Wright, scala-debate
This comes from discussions with Twitter several months ago during the evolution of the Futures library. Apparently, Twitter heavily uses Try internally, they have a couple of years of experience with it and attest that it results in much simpler, more readable, and less accident-prone (wrt swapping Left and Right) code. As a result, on their end, they require that Futures use Try over Either. So, during a few discussions here, Martin was in favor of introducing Try to the stdlib and using them with the Futures library, as, arguably, Twitter's Futures library has to be the most battle-tested Scala Futures library out there.

However, since the Akka folks solidified their API before scala.concurrent was finalized, that decision was reversed. So, the signatures in scala.concurrent still involve Either, but there exists an extractor which allow one to use Trys as well.

So, usage like: 

val f = future{0}

f onComplete {
  case Success(v) => println(v)
  case Failure(e) => println("Exception")
}

is still possible.

Since it's a small step towards unifying more Futures libraries (as Twitter is an important user, likewise with a lot of valuable experience), it's been agreed for a bit that Try will likely stick around. 

Though, a bottom-line here is, of course, that Try can be used outside of the context of Futures.

-- 
Heather Miller
Doctoral Assistant
EPFL, IC, LAMP

Heather Miller

unread,
May 15, 2012, 4:39:21 AM5/15/12
to Jason Zaugg, l...@underneath.ca, Rex Kerr, Kevin Wright, scala-debate
To copy/paste a tidbit of motivation here:
We introduced `Try` a while back along with SIP-14 (Futures). `Try` is analogous to `Either` with the exception that it's success-biased. That is, Either is symmetric, it has two type parameters that are wrapped (symmetrically) in either `Left` or `Right`. In general, by convention, `Either` can be used to represent a "successful" or a "failed" result, by representing some generic type in its right projection, and a subtype of Throwable in its left projection. However, this is by convention only, one can of course swap these projections (whether accidentally or purposefully) or one can represent two successful values in each projection if they so desire.

`Try`, on the other hand, is parameterized only on one type, with this success/failure use case in mind. That is, the successful case is wrapped in `Success` (parameterized on T) while the failed case is a `Throwable` wrapped in `Failure`.

`Try` comes from Twitter, who use it frequently in their codebase (see twitter/util on github), and who have found that it results in more readable and less error-prone code for this success/failure use case of `Either`.
-- 
Heather Miller
Doctoral Assistant
EPFL, IC, LAMP

missingfaktor

unread,
May 15, 2012, 4:56:23 AM5/15/12
to Heather Miller, Jason Zaugg, l...@underneath.ca, Rex Kerr, Kevin Wright, scala-debate
Why is Failure specialized on Throwable? It could/should be type-parametrized IMO. Throwable seems like an unnecessary restriction.
--
Cheers,

Kevin Wright

unread,
May 15, 2012, 5:01:42 AM5/15/12
to Heather Miller, Jason Zaugg, l...@underneath.ca, Rex Kerr, scala-debate
I want to have my cake and eat it too!  A right-biased disjoint union in which I can parameterise the type of BOTH sides.

Consider this example:


My rejection is NOT a Throwable, it doesn't incur the cost of building the stack trace for an exception, and it additionally carries the value that caused the failure to occur.

Yes, I know that I were to use Try I could create my own Throwable/Exception type and have it carry whatever other values I care for.  But that's just removing ceremony from one place only to hand it back in another, likely sacrificing performance in the process.

Rob Dickens

unread,
May 15, 2012, 7:49:46 AM5/15/12
to scala-debate, Kevin Wright, Heather Miller, Jason Zaugg, l...@underneath.ca, Rex Kerr
How about doing the following:

* leave Either as it is, since the name doesn't imply any bias
(although Right certainly does), and it looks like changing it would
only buy you definitions in for-comprehensions (and not having to add
.right)

* introduce a completely new class, Checked, having OK and KO as the
type constructors

* include support for combining Checked values in both a fail-fast and
fail-slow manner, including applicative-functor support (<*>
operator), similar to that which I describe here:

http://robsscala.blogspot.co.uk/2012/05/validating-multiple-values-at-once.html

Rob

Gary Pampara

unread,
May 15, 2012, 7:54:50 AM5/15/12
to Rob Dickens, scala-debate, Kevin Wright, Heather Miller, Jason Zaugg, l...@underneath.ca, Rex Kerr
Fixing a problem is better than working around it.

+1 for right-bias

√iktor Ҡlang

unread,
May 15, 2012, 8:02:45 AM5/15/12
to Rob Dickens, scala-debate, Kevin Wright, Heather Miller, Jason Zaugg, l...@underneath.ca, Rex Kerr
On Tue, May 15, 2012 at 1:49 PM, Rob Dickens <robcd...@gmail.com> wrote:
How about doing the following:

* leave Either as it is, since the name doesn't imply any bias
(although Right certainly does), and it looks like changing it would
only buy you definitions in for-comprehensions (and not having to add
.right)

* introduce a completely new class, Checked, having OK and KO as the
type constructors

* include support for combining Checked values in both a fail-fast and
fail-slow manner, including applicative-functor support (<*>
operator), similar to that which I describe here:

http://robsscala.blogspot.co.uk/2012/05/validating-multiple-values-at-once.html

That kind of thinking gave use java.util.Data and then java.util.Calendar, just sayin'.

Cheers,

Miles Sabin

unread,
May 15, 2012, 8:03:07 AM5/15/12
to Jason Zaugg, scala-debate
On Mon, May 14, 2012 at 8:08 AM, Jason Zaugg <jza...@gmail.com> wrote:
> (A follow-up from ticket SI-5793. [1])
>
> Apologies in advance to any left-handers out there.
>
> I propose (not that I'm the first) to right-bias Either. Concretely,
> this means we would add map/flatMap etc directly to Either, rather
> than going through RightProjection. RightProjection could probably
> deprecated.
>
> Is there any previous discussion on this? Any arguments against?

Also a +1 from me ...

Cheers,


Miles

--
Miles Sabin
tel: +44 7813 944 528
gtalk: mi...@milessabin.com
skype: milessabin
g+: http://www.milessabin.com
http://twitter.com/milessabin
http://underscoreconsulting.com
http://www.chuusai.com

Kevin Wright

unread,
May 15, 2012, 8:08:09 AM5/15/12
to Miles Sabin, Jason Zaugg, scala-debate
At the very least, as an interim solution, could we have a publicised and advocated import to enable this behaviour?


scala> implicit def doTheRightThing[A,B](x: Either[A,B]): Either.RightProjection[A,B] = x.right
doTheRightThing: [A, B](x: Either[A,B])Either.RightProjection[A,B]

scala> val one: Either[Int,String] = Right("Bippy")
one: Either[Int,String] = Right(Bippy)

scala> val two: Either[Int,String] = Left(42)
two: Either[Int,String] = Left(42)

scala> one map {_.toUpperCase}
res0: Product with Either[Int,java.lang.String] with Serializable = Right(BIPPY)

scala> two map {_.toUpperCase}
res1: Product with Either[Int,java.lang.String] with Serializable = Left(42)


Assuming, of course, that it could be done without any performance cost :)

Rex Kerr

unread,
May 15, 2012, 11:27:24 AM5/15/12
to Kevin Wright, Miles Sabin, Jason Zaugg, scala-debate
I might agree with at least adding an import.  (Especially if there was also a left-bias one could import.)

And I would _probably_ +1 the right-bias of Either as a whole (not just with an implicit) if I knew exactly what this meant.  Right now it seems like we're giving +1 for something like "justice"--who can be against justice (or kittens)?  But what exactly does it mean?

I'd rather show or reserve enthusiasm on the basis of an exact proposal (especially now that it's clearly established that the right-bias of Either would be widely accepted in principle).

In particular, I'm especially interested in how Option and Either are supposed to interact, in capabilities for recovering good states from error states and tossing away provisionally good states into error states, and in having complete (not partial) support for for-comprehensions.

For example, suppose we make Either look like RightProjection:

  val e: Either[Int,String] = Right("fish")
  for (x <- e.right if true) yield x

We get a deprecation warning about withFilter not existing, and with filter instead of getting the value we get neither an Option[String] nor an Either[_, String] but an Option[Either[Nothing,String]].  Wha?  That's not very helpful for composition.

As another example, suppose I look something up in a map:

  val m = Map("fish" -> true)
  e.right.map(m.get)

Now I have an Either[Int, Option[Boolean]].  This is probably not what I want, and it's certainly not what for wants:

  for (x <- e.right; y <- m.get(x)) yield y
  // type mismatch; found: Option[Boolean] required: Either[?,?]

You can get this to work longhand

  e.right.flatMap((m.get _) andThen {o => o.toRight(-1)})

but what a mess!

These sorts of issues are, I think, why Try has the semantics that it does.  Try can work properly for error handling; right-biased Either is still full of holes.  I am _not_ keen on right-biasing Either only to have it fall apart as soon as you try anything but the simplest things with it.

So I think we should try to find an implementation of right-biased Either that has good properties, and then decide whether or not this is what Either should become--not just ask for a right-biased either without knowing the implementation details.

  --Rex

OMURA, Shingo

unread,
May 15, 2012, 12:22:45 PM5/15/12
to scala-debate
I also vote +1.

Best regards,
--
Shingo Omura
Software Architect, Technical Translator / Writer
http://everpeace.github.com/


2012/5/16 Rex Kerr <ich...@gmail.com>:

Kevin Wright

unread,
May 15, 2012, 12:27:20 PM5/15/12
to Rex Kerr, Miles Sabin, Jason Zaugg, scala-debate
On 15 May 2012 16:27, Rex Kerr <ich...@gmail.com> wrote:
I might agree with at least adding an import.  (Especially if there was also a left-bias one could import.)

And I would _probably_ +1 the right-bias of Either as a whole (not just with an implicit) if I knew exactly what this meant.  Right now it seems like we're giving +1 for something like "justice"--who can be against justice (or kittens)?  But what exactly does it mean?

I'd rather show or reserve enthusiasm on the basis of an exact proposal (especially now that it's clearly established that the right-bias of Either would be widely accepted in principle).

In particular, I'm especially interested in how Option and Either are supposed to interact, in capabilities for recovering good states from error states and tossing away provisionally good states into error states, and in having complete (not partial) support for for-comprehensions.

For example, suppose we make Either look like RightProjection:

  val e: Either[Int,String] = Right("fish")
  for (x <- e.right if true) yield x

We get a deprecation warning about withFilter not existing, and with filter instead of getting the value we get neither an Option[String] nor an Either[_, String] but an Option[Either[Nothing,String]].  Wha?  That's not very helpful for composition.

Definitely not pleasant.  But also not an issue cased by biasing (or lack thereof), you'd get the same odd behaviour from both a biased Either and from an explicit right projection.

The correct behaviour in this case is probably best left for a later discussion.

 
As another example, suppose I look something up in a map:

  val m = Map("fish" -> true)
  e.right.map(m.get)

Now I have an Either[Int, Option[Boolean]].  This is probably not what I want, and it's certainly not what for wants:

  for (x <- e.right; y <- m.get(x)) yield y
  // type mismatch; found: Option[Boolean] required: Either[?,?]

You can get this to work longhand

  e.right.flatMap((m.get _) andThen {o => o.toRight(-1)})

but what a mess!


That one's clearer.  If Either is right-biased, then it makes much more sense to have an implicit conversion from Option[T] => Either[Nothing, T]

Unfortunately, Left takes a by-ref argument, and there are no instances of Nothing available to pass as this parameter.  If it was by-name, then I'd just use an exception.

implicit def optionIsRight[T](x: Option[T]): Either[Nothing,T] = x map {Right(_)} getOrElse {Left(sys.err("Option lifted to Either has no Left type"))}

... trying to retrieve such a value would then be directly analogous to trying to fetch the value out of a None

With access to the definition of Either + Left, we should be able to add a subclass of Left[Nothing] that could be used in exactly this scenario.

For now though, it can be faked.  But the type inference ain't so pretty:

scala> implicit def optionIsRight[T](x: Option[T]): Either[Unit,T] = x map {Right(_)} getOrElse {Left(())}
optionIsRight: [T](x: Option[T])Either[Unit,T]

scala> for (x <- e.right; y <- m.get(x)) yield y
res7: Either[AnyVal{def getClass(): java.lang.Class[_ >: Int with Unit <: AnyVal]},Boolean] = Right(true)


I'm still using .right of course.  That would go away if Either were biased.

Ryan Hendrickson

unread,
May 15, 2012, 12:53:20 PM5/15/12
to Kevin Wright, Rex Kerr, Miles Sabin, Jason Zaugg, scala-debate
> That one's clearer. If Either is right-biased, then it makes much more
> sense to have an implicit conversion from Option[T] => Either[Nothing,
> T]
>
> Unfortunately, Left takes a by-ref argument, and there are no instances
> of Nothing available to pass as this parameter. If it was by-name, then
> I'd just use an exception.

For this reason, and also because it's a type isomorphism, shouldn't you want Option[T] => Either[Unit, T] instead?





(please forgive me my corporate legal disclaimer)

----------------------------------------

This message is intended exclusively for the individual(s) or entity to
which it is addressed. It may contain information that is proprietary,
privileged or confidential or otherwise legally exempt from disclosure.
If you are not the named addressee, you are not authorized to read,
print, retain, copy or disseminate this message or any part of it.
If you have received this message in error, please notify the sender
immediately by e-mail and delete all copies of the message.

Runar Bjarnason

unread,
May 15, 2012, 12:58:22 PM5/15/12
to scala-...@googlegroups.com, Rex Kerr, Miles Sabin, Jason Zaugg


On Tuesday, May 15, 2012 12:27:20 PM UTC-4, Kevin Wright wrote:

And I would _probably_ +1 the right-bias of Either as a whole (not just with an implicit) if I knew exactly what this meant.  Right now it seems like we're giving +1 for something like "justice"--who can be against justice (or kittens)?  But what exactly does it mean?

It means it's easier to use in the overwhelmingly common case. And not the least bit more difficult to use in any other case.

 
 That one's clearer.  If Either is right-biased, then it makes much more sense to have an implicit conversion from Option[T] => Either[Nothing, T]

It should be Option[T] => Either[Unit, T].


scala> implicit def optionIsRight[T](x: Option[T]): Either[Unit,T] = x map {Right(_)} getOrElse {Left(())}
optionIsRight: [T](x: Option[T])Either[Unit,T]

scala> for (x <- e.right; y <- m.get(x)) yield y
res7: Either[AnyVal{def getClass(): java.lang.Class[_ >: Int with Unit <: AnyVal]},Boolean] = Right(true)


This happens because you are unifying Either[Int, Boolean] with Either[Unit, Boolean]. You need to first turn the Int into a Unit:

for (x <- e.left.map(_ => ()).right; y <- m.get(x)) yield y
                                          ^

Runar Bjarnason

unread,
May 15, 2012, 1:10:05 PM5/15/12
to scala-...@googlegroups.com, Rex Kerr, Miles Sabin, Jason Zaugg
That said, you can effectively right-bias Either on your own:


implicit def rightIsEither[E,A](e: Either.RightProjection[E, A]): Either[E, A] = e.e
implicit def eitherIsRight[E,A](e: Either[E, A]): Either.RightProjection[E, A] = e.right

implicit def optionIsRight[T](x: Option[T]): Either[Unit,T] = x map {Right(_)} getOrElse {Left(())}
// Either is already right-biased in this regard:
implicit def rightIsOption[E,A](e: Either[E, A]): Option[A] = e.toOption


Simon Ochsenreither

unread,
May 15, 2012, 1:14:33 PM5/15/12
to scala-...@googlegroups.com, Rob Dickens, Kevin Wright, Heather Miller, Jason Zaugg, l...@underneath.ca, Rex Kerr

That kind of thinking gave use java.util.Data and then java.util.Calendar, just sayin'.

I agree. I'm even pretty sure Option + Either + Try is not the end ... we probably have already similar stuff like that lying around somewhere in the library.
It is a bit unfortunate that it seems like the spring cleanup is getting bigger with every release. Compare the removal of scala.mobile (2.8) with scala.dbc + scala.actors + all the stuff Paul deprecated.

I would really like to get to a state where we have less deprecated items each release and not more.

Considering Try:

scala.util is a clear no-go: Why should something be included when it is still unclear where it actually belongs?

I don't want to appear that I'm against Try and in fact I would really love to see some direct comparison between Either-using Futures and Try-using Futures. I assume this will even come out in favour of Try in the long end.

But my point is really to have a look at the whole picture of similar features, so that when enthusiasm for SIP-14 wears of, we don't have yet another class/package in dire need of deprecation.

Rex Kerr

unread,
May 15, 2012, 1:53:48 PM5/15/12
to Kevin Wright, Miles Sabin, Jason Zaugg, scala-debate
On Tue, May 15, 2012 at 12:27 PM, Kevin Wright <kev.lee...@gmail.com> wrote:

On 15 May 2012 16:27, Rex Kerr <ich...@gmail.com> wrote:
I might agree with at least adding an import.  (Especially if there was also a left-bias one could import.)

And I would _probably_ +1 the right-bias of Either as a whole (not just with an implicit) if I knew exactly what this meant.  Right now it seems like we're giving +1 for something like "justice"--who can be against justice (or kittens)?  But what exactly does it mean?

I'd rather show or reserve enthusiasm on the basis of an exact proposal (especially now that it's clearly established that the right-bias of Either would be widely accepted in principle).

In particular, I'm especially interested in how Option and Either are supposed to interact, in capabilities for recovering good states from error states and tossing away provisionally good states into error states, and in having complete (not partial) support for for-comprehensions.

For example, suppose we make Either look like RightProjection:

  val e: Either[Int,String] = Right("fish")
  for (x <- e.right if true) yield x

We get a deprecation warning about withFilter not existing, and with filter instead of getting the value we get neither an Option[String] nor an Either[_, String] but an Option[Either[Nothing,String]].  Wha?  That's not very helpful for composition.

Definitely not pleasant.  But also not an issue cased by biasing (or lack thereof), you'd get the same odd behaviour from both a biased Either and from an explicit right projection.

The correct behaviour in this case is probably best left for a later discussion.

Are you sure that's wise?  You said

Right-bias is not about being able to quickly convert to an Option, it's about being able to chain a sequence of operations, each of which takes the right output of the previous operation and yields an either.

Most especially, it's about being able to do so in the context of a for-comprehension.

and here I'm seeing that one of the common nontrivial use-cases is broken.  If we don't do this correctly now, then we may well have to go through another two releases of deprecation and change before we get something that's pleasant to use.  I'm not saying Either is better as it is--but you wouldn't so often run into this with Either because you don't expect it to work well with for-comprehensions.

If we're going to make the change, let's do it right the first time.

 
With access to the definition of Either + Left, we should be able to add a subclass of Left[Nothing] that could be used in exactly this scenario.

This essentially changes Left(x) into Option (i.e. Right, Left, NoneLeft), or makes Either into AtMost1of2 instead of an Exactly1of2.  We should think carefully about this--my sense is that breaking the contract that a Left(x) actually has an x is too big of a change to make.
 
For now though, it can be faked.  But the type inference ain't so pretty:

scala> implicit def optionIsRight[T](x: Option[T]): Either[Unit,T] = x map {Right(_)} getOrElse {Left(())}
optionIsRight: [T](x: Option[T])Either[Unit,T]

scala> for (x <- e.right; y <- m.get(x)) yield y
res7: Either[AnyVal{def getClass(): java.lang.Class[_ >: Int with Unit <: AnyVal]},Boolean] = Right(true)


I'm still using .right of course.  That would go away if Either were biased.

I agree; that's pretty ugly, but at least it's honest.  It would look nicer as
  Either[ Either[Int,Unit] , Boolean ]
but I guess this is just another argument for proper union types (or for the unbiased flavor of Either, or for something like Shapeless).

  --Rex

Rex Kerr

unread,
May 15, 2012, 2:18:19 PM5/15/12
to Runar Bjarnason, scala-...@googlegroups.com
On Tue, May 15, 2012 at 12:58 PM, Runar Bjarnason <runar...@gmail.com> wrote:


On Tuesday, May 15, 2012 12:27:20 PM UTC-4, Kevin Wright wrote:

And I would _probably_ +1 the right-bias of Either as a whole (not just with an implicit) if I knew exactly what this meant.  Right now it seems like we're giving +1 for something like "justice"--who can be against justice (or kittens)?  But what exactly does it mean?

It means it's easier to use in the overwhelmingly common case. And not the least bit more difficult to use in any other case.

Agreed.  But it means something else also, which I think is important: those "any other cases" will come up a lot more often now.

Right now, there's a very simple approximation that one can use to understand how to combine Either with for comprehensions:
  "Either doesn't work with for-comprehensions."

Well, disappointing, but at least it's simple.

After a change that makes Either act like RightProjection, the approximation becomes:
  "Either works with for-comprehensions as long as you just chain eithers and don't use any ifs"
 
which is not at all obvious until you try it out and it doesn't work.  (It also doesn't work with collections as it stands.)

Small increases in actual capability that are paid for by moderate amounts of confusion and disappointment are usually not worth it.


 
 That one's clearer.  If Either is right-biased, then it makes much more sense to have an implicit conversion from Option[T] => Either[Nothing, T]

It should be Option[T] => Either[Unit, T].


scala> implicit def optionIsRight[T](x: Option[T]): Either[Unit,T] = x map {Right(_)} getOrElse {Left(())}
optionIsRight: [T](x: Option[T])Either[Unit,T]

scala> for (x <- e.right; y <- m.get(x)) yield y
res7: Either[AnyVal{def getClass(): java.lang.Class[_ >: Int with Unit <: AnyVal]},Boolean] = Right(true)


This happens because you are unifying Either[Int, Boolean] with Either[Unit, Boolean]. You need to first turn the Int into a Unit:

for (x <- e.left.map(_ => ()).right; y <- m.get(x)) yield y
                                         ^

One could do this, but then you throw away the original error which you may not have wanted to do.  If that's what you wanted,

  for (x <- e.right.toOption; y <- m.get(x)) yield y

seems simpler.

Anyway, at this time I think my point is only that right-biasing Either should be done carefully and properly, not just by throwing map and flatMap onto Either and calling it good.

  --Rex

Matthew Pocock

unread,
May 15, 2012, 3:01:22 PM5/15/12
to Rex Kerr, Runar Bjarnason, scala-...@googlegroups.com
Can I throw my 2 penith worth behind keeping Either as the unbiassed product type and adding (if needed) an explicit biassed product with filter/map/... and two type constructors with names that clearly signal which is the success value and which is the failure value? I find the idea of using Either.Left for failure and Either.Right for success to be an obfuscated hack, precisely because the type constructors are called Left and Right, not Failure and Success. If the type is intended to be used with clear semantics then, by the ghost of Church, name the type after those semantics.

Matthew
--
Dr Matthew Pocock
Integrative Bioinformatics Group, School of Computing Science, Newcastle University
skype: matthew.pocock
tel: (0191) 2566550

Jan Vanek

unread,
May 15, 2012, 3:16:06 PM5/15/12
to scala-...@googlegroups.com
On 15.05.2012 21:01, Matthew Pocock wrote:
Can I throw my 2 penith worth behind keeping Either as the unbiassed product type and adding (if needed) an explicit biassed product with filter/map/... and two type constructors with names that clearly signal which is the success value and which is the failure value? I find the idea of using Either.Left for failure and Either.Right for success to be an obfuscated hack, precisely because the type constructors are called Left and Right, not Failure and Success. If the type is intended to be used with clear semantics then, by the ghost of Church, name the type after those semantics.


+1
Jan

Raoul Duke

unread,
May 15, 2012, 3:21:19 PM5/15/12
to scala-...@googlegroups.com
On Tue, May 15, 2012 at 12:16 PM, Jan Vanek <j3v...@googlemail.com> wrote:
> Either.Left for failure and Either.Right for success to be
> an obfuscated hack, precisely because the type constructors are called Left
> and Right, not Failure and Success. If the type is intended to be used with
> clear semantics then, by the ghost of Church, name the type after those
> semantics.
> +1

+1 to the +1, here-here for sanity/usability/clear naming.

Runar Bjarnason

unread,
May 15, 2012, 3:24:33 PM5/15/12
to scala-...@googlegroups.com
Either is already right-biased to some extent, and this proposal just takes it further. The arguments for are all basically "it's bloody useful", and the arguments against are all basically "feelings! naming!" There is no way that anybody is relying on the fact that Either is not biased, for anything other than emotional comfort. Having two Eithers with no essential difference is the worst of both worlds.

If anything, adding the biased methods will make the library more consistent and less surprising. Products are already right-biased, so why not coproducts?

scala> (1, 2) map (_ + 1)
res0: (Int, Int) = (1, 3)

Oh, and since we're bikeshedding, there are some good reasons why products should be left-biased instead, but that's already too late.

Jason Zaugg

unread,
May 15, 2012, 3:33:31 PM5/15/12
to Runar Bjarnason, scala-...@googlegroups.com
On Tue, May 15, 2012 at 9:24 PM, Runar Bjarnason <runar...@gmail.com> wrote:
> If anything, adding the biased methods will make the library more consistent
> and less surprising. Products are already right-biased, so why not
> coproducts?
>
> scala> (1, 2) map (_ + 1)
> res0: (Int, Int) = (1, 3)
>
> Oh, and since we're bikeshedding, there are some good reasons why products
> should be left-biased instead, but that's already too late.

That's actually only the case with an import from a scalaz.

-jason

Runar Bjarnason

unread,
May 15, 2012, 3:36:11 PM5/15/12
to Jason Zaugg, scala-...@googlegroups.com
That's actually only the case with an import from a scalaz.

Oh. I might have known. In that case, we might flip the bias to be consistent with State. :)




Matthew Pocock

unread,
May 15, 2012, 4:49:06 PM5/15/12
to Runar Bjarnason, scala-debate


On 15 May 2012 20:42, Runar Bjarnason <runar...@gmail.com> wrote:

To be clear, my objection to ever-further biassing of Either is that the names are wrong. People understand intent of code through the names.

Well, that is a mistake. They should understand it through the types. Either is an extremely general kind of thing, so there is not going to be one good name that captures all intents. But the type certainly does.

 
A type that uses names that are clearly linked to their intended semantics doesn't seem to me to be at all about vague feelings of goodness. It is absolutely central to people being able to understand code.

Adding the following to the Scaladoc might do the trick: "By convention, the Left case may represent failure and the Right case may represent success." 

But now Either is not 'an extremely general kind of thing', but something with features added specifically designed for capturing failure and success. You can't intuit this from ether the names Left/Right, or from a cursory inspection of the types, especially with how fat these interfaces are already. I know it is obvious to you, but you are not someone coming to the code with fresh eyes.

Let's pretend we don't know the history of Either/Left/Right. I give you these two types:

trait Sum2[A, B]
case class Sum2_Left[A, B](a: A) extends Sum2[A, B]
case class Sum2_Right[A, B](b: B) extends Sum2[A, B]

trait Try[A, B]
case class Failure[A, B](a: A) extends Try[A, B]
case class Success[A, B](b: B) extends Try[A, B]

Now, any programmer, whatever their background, will be able to intuit that Sum2 is the symmetrical sum type, and Try is success-biassed. Sum2 is your 'general kind of thing' and Try is your right-biassed version of Either. The only reason I can see to think differently is if you have years of experience with FP where Either is overloaded to fulfil both these roles.

I strongly believe that it is very important for names in code to meaningfully represent to people what the thing is representing. Either explicitly uses neutral language, so should be modelling something neutral. If you want something with success/fail semantics, you should have a type with explicit names.

Anyway, I think we're just saying the same opposing things over and over at this point, so I'll leave it to others to chime in.

M

Runar Bjarnason

unread,
May 15, 2012, 4:54:10 PM5/15/12
to Matthew Pocock, scala-debate
On Tue, May 15, 2012 at 4:49 PM, Matthew Pocock <turingate...@gmail.com> wrote:

trait Sum2[A, B]
case class Sum2_Left[A, B](a: A) extends Sum2[A, B]
case class Sum2_Right[A, B](b: B) extends Sum2[A, B]

trait Try[A, B]
case class Failure[A, B](a: A) extends Try[A, B]
case class Success[A, B](b: B) extends Try[A, B]

They are the exact same type.



I strongly believe that it is very important for names in code to meaningfully represent to people what the thing is representing.

It depends on what you think is important in general. Strong beliefs and names are not particularly important to me.



Jason Zaugg

unread,
May 15, 2012, 5:03:52 PM5/15/12
to Rex Kerr, Kevin Wright, Miles Sabin, scala-debate
On Tue, May 15, 2012 at 5:27 PM, Rex Kerr <ich...@gmail.com> wrote:
> So I think we should try to find an implementation of right-biased Either
> that has good properties, and then decide whether or not this is what Either
> should become--not just ask for a right-biased either without knowing the
> implementation details.

Here's a starting point:

https://github.com/retronym/scala/compare/topic/either

I took the methods from right projection (other than filter, which is
troublesome in for comprehensions), and moved them to Either.

-jason

Tony Morris

unread,
May 15, 2012, 5:22:48 PM5/15/12
to scala-...@googlegroups.com
On 16/05/12 02:27, Kevin Wright wrote:
> That one's clearer. If Either is right-biased, then it makes much more
> sense to have an implicit conversion from Option[T] => Either[Nothing, T]
I think you mean Either[Unit, T] which is the isomorphism you are
alluding to.

Either[Nothing, T] ~= T

--
Tony Morris
http://tmorris.net/


Tony Morris

unread,
May 15, 2012, 5:24:40 PM5/15/12
to scala-...@googlegroups.com
On 16/05/12 02:53, Ryan Hendrickson wrote:
> For this reason, and also because it's a type isomorphism, shouldn't you want Option[T] => Either[Unit, T] instead?
Yes.

Moreover you'd want Option[T] <=> Either[Unit, T] where <=> denotes
bijection. Rather than an implicit, I'd simply prefer library support
for isomorphisms -- much easier to work with then.

In any case, I think that is all beside the point of right-biasing Either.

Tony Morris

unread,
May 15, 2012, 5:27:42 PM5/15/12
to scala-...@googlegroups.com
It perhaps should be noted that right-biasing Either and the idea of
using Either for error-handling should not be conflated. Either says
nothing about error-handling -- it is trivial summation and nothing
more. That someone might use it in its specialised form or perhaps even
specialise it one type argument (Try), is beside the point of the need
to right-bias Either. We should not conflate these things in discussion.

Tony Morris

unread,
May 15, 2012, 5:30:19 PM5/15/12
to scala-...@googlegroups.com
I should imagine the proposal is to throw all that is on RightProjection
onto Either and call it good.

And if I could have my way, there would be a crap-ton more useful
libraries on there too, but I don't think that's the proposal.

Tony Morris

unread,
May 15, 2012, 5:32:56 PM5/15/12
to scala-...@googlegroups.com
On 16/05/12 05:01, Matthew Pocock wrote:
> Can I throw my 2 penith worth behind keeping Either as the unbiassed
> product type and adding (if needed) an explicit biassed product with
> filter/map/... and two type constructors with names that clearly signal
> which is the success value and which is the failure value? I find the idea
> of using Either.Left for failure and Either.Right for success to be
> an obfuscated hack, precisely because the type constructors are called Left
> and Right, not Failure and Success. If the type is intended to be used with
> clear semantics then, by the ghost of Church, name the type after those
> semantics.
>
> Matthew

Scalaz does this with Validation, but it is not a monad and so does not
have flatMap.

I agree another data type is warranted, but with careful consideration,
we could unify them all with some nice library design with implicits --
just sayin'!
Tony Morris
http://tmorris.net/


Matthew Pocock

unread,
May 15, 2012, 5:33:51 PM5/15/12
to Runar Bjarnason, scala-debate
On 15 May 2012 21:54, Runar Bjarnason <runar...@gmail.com> wrote:


It depends on what you think is important in general. Strong beliefs and names are not particularly important to me.


I don't expect you to take anything on board on the basis of my strong belief ;) However, names are important to the average coder though, and standard libraries are intended to be understandable to and used by the average coder and the casual user. 

Types are not where coding begins and ends. There is a gap to be bridged between the code and the coder's understanding. Names are part of this bridge.

Tony Morris

unread,
May 15, 2012, 5:35:19 PM5/15/12
to scala-...@googlegroups.com
I have not seen in the proposal where Either now becomes biased toward
failure or success. Right-biasing Either does not cause this.

Matthew Pocock

unread,
May 15, 2012, 5:35:53 PM5/15/12
to tmo...@tmorris.net, scala-...@googlegroups.com


On 15 May 2012 22:32, Tony Morris <tonym...@gmail.com> wrote:

I agree another data type is warranted, but with careful consideration,
we could unify them all with some nice library design with implicits --
just sayin'!


Yeah, I agree with both your points. Conflation is a poor-man's isomorphism.

Matthew Pocock

unread,
May 15, 2012, 5:38:15 PM5/15/12
to tmo...@tmorris.net, scala-...@googlegroups.com
On 15 May 2012 22:35, Tony Morris <tonym...@gmail.com> wrote:
>
I have not seen in the proposal where Either now becomes biased toward
failure or success. Right-biasing Either does not cause this.

Perhaps this is where I am confused then. Every example of right-biassed Either I've seen is framed in terms of success and failure. I have seen zero examples of it being used in some other way. Perhaps a compelling example of using a right-biassed Either where left doesn't model failure and right success would convince me that this is a worthy change.

M
 

--
Tony Morris
http://tmorris.net/


Rex Kerr

unread,
May 16, 2012, 4:10:39 PM5/16/12
to Jason Zaugg, Kevin Wright, Miles Sabin, scala-debate
I propose this as an alternative, with more favorable use characteristics than Try or right-biased Either.  The naming ("Has") is a little quirky because I was trying to avoid using any existing names.

Either is an awkward fit because of the clumsiness of the isomorphism between Option[X] and Either[Unit,X]; to get around this, there are three subclasses: Yes[X], Plea[T], and No.
  Yes[X] - the success type, like Right[X] or Some[X]
  Plea[T] - an excuse for why things didn't work, like Left[T]
  No - it didn't work and you have no idea why, like None

Has is _very strongly right-biased_ (yes-biased).  Although a subset of methods are defined for Plea, if you want to work in left-biased mode (plea-biased), use swap.

Code is here: http://pastebin.com/TV1NKy5b

Here's a short example of one way to use it:

  def negativeParse(s: String) = {
    for (d <- Has.catchAll(s.toDouble) if !d.isNaN) yield -d
  }


I'm not suggesting that we turn Either into this, but I think something like this is the level to which we should aspire for a solution to right-biased sum types in the Scala core library (where e.g. the power of the rest of the Scalaz library cannot be relied upon).

I'm happy to translate examples from Try or Either (incl. right-biased Either in RightProjection formulation) to Has; they will generally get easier or more flexible or both.  (If not, maybe I'll add a few of the methods that I'm missing presently (flatten, catchMap, ...?).  The one thing that Try does that Has does not is _almost_ consistently catch exceptions as they occur.  (collect doesn't, for some odd reason--shouldn't like 146 be Try[U](...) instead of Success[U](...)?.)

  --Rex

Jason Zaugg

unread,
May 17, 2012, 11:04:12 AM5/17/12
to Rex Kerr, Kevin Wright, Miles Sabin, scala-debate
On Wed, May 16, 2012 at 10:10 PM, Rex Kerr <ich...@gmail.com> wrote:
> I propose this as an alternative, with more favorable use characteristics
> than Try or right-biased Either.  The naming ("Has") is a little quirky
> because I was trying to avoid using any existing names.

That looks quite useful. Naming the constructors is probably the hardest part :)

If I understand it correctly, it's isomorphic to Either[Option[A], B],
which is nice in that it allows for a useful filter method.

Perhaps we could take a similar approach for Either:

class Either[A, B] {
def filter[AA](f: B => Boolean)(implicit ev: A =:= Option[AA]):
Either[A, B] =
this match {
case l @ Left(_) => l
case r @ Right(b) => if (f(b)) r else Left(None)
}

// scalaz style
def filter[AA](f: B => Boolean)(implicit M: Monoid[A]): Either[A, B]
= this match {
case l @ Left(_) => l
case r @ Right(b) => if (f(b)) r else Left(M.zero)
}
}

I would suggest to deprecate/rename the current filter methods in left
and right projection first.

> I'm not suggesting that we turn Either into this, but I think something like
> this is the level to which we should aspire for a solution to right-biased
> sum types in the Scala core library (where e.g. the power of the rest of the
> Scalaz library cannot be relied upon).
>
> I'm happy to translate examples from Try or Either (incl. right-biased
> Either in RightProjection formulation) to Has; they will generally get
> easier or more flexible or both.  (If not, maybe I'll add a few of the
> methods that I'm missing presently (flatten, catchMap, ...?).  The one thing
> that Try does that Has does not is _almost_ consistently catch exceptions as
> they occur.  (collect doesn't, for some odd reason--shouldn't like 146 be
> Try[U](...) instead of Success[U](...)?.)

Try is a different beast altogether, I think its transparent exception
handling is dangerous and currently inconsistent. See my comments here
[1]

-jason

[1] https://github.com/scala/scala/commit/7d206f3c73#src/library/scala/util/Try.scala

Rex Kerr

unread,
May 17, 2012, 11:32:14 AM5/17/12
to Jason Zaugg, Kevin Wright, Miles Sabin, scala-debate
On Thu, May 17, 2012 at 11:04 AM, Jason Zaugg <jza...@gmail.com> wrote:
On Wed, May 16, 2012 at 10:10 PM, Rex Kerr <ich...@gmail.com> wrote:
> I propose this as an alternative, with more favorable use characteristics
> than Try or right-biased Either.


If I understand it correctly, it's isomorphic to Either[Option[A], B],
which is nice in that it allows for a useful filter method.

Correct--isomorphic, but without the awkwardness of nested containers.
 

Perhaps we could take a similar approach for Either:

class Either[A, B] {
 def filter[AA](f: B => Boolean)(implicit ev: A =:= Option[AA]):
Either[A, B] =
    this match {
       case l @ Left(_) => l
       case r @ Right(b) => if (f(b)) r else Left(None)
    }

This requires you to load your Lefts with Options, which is a bit of a pain, but yes, at least filter would work.
 

I would suggest to deprecate/rename the current filter methods in left
and right projection first.

I'm not sure they're terribly useful as is, so I'd support that anyway.
 

> The one thing
> that Try does that Has does not is _almost_ consistently catch exceptions as
> they occur.  (collect doesn't, for some odd reason--shouldn't like 146 be
> Try[U](...) instead of Success[U](...)?.)

Try is a different beast altogether, I think its transparent exception
handling is dangerous and currently inconsistent. See my comments here
[1]

The Try[U] apply method transparently catches exceptions so flatMap is consistent.  Collect is the only odd-man-out that I saw.  (Well, and filter; if your predicate throws an exception, you're out of luck.)

I agree that catching Throwable instead of Exception is dangerous.  That is almost never the right thing to do.  I don't suppose we can change that, though, because I bet Twitter relies upon it somewhere.  I would much prefer if we could change it to only catch Exception (or to re-throw ControlThrowable at least--that would be okay, wouldn't it?).

  --Rex

Ivan Todoroski

unread,
May 17, 2012, 11:36:48 AM5/17/12
to Jason Zaugg, Rex Kerr, Kevin Wright, Miles Sabin, scala-debate
On 17.05.2012 17:04, Jason Zaugg wrote:
> On Wed, May 16, 2012 at 10:10 PM, Rex Kerr <ich...@gmail.com> wrote:
>> I propose this as an alternative, with more favorable use characteristics
>> than Try or right-biased Either. The naming ("Has") is a little quirky
>> because I was trying to avoid using any existing names.
>
> That looks quite useful. Naming the constructors is probably the hardest part :)
>
> If I understand it correctly, it's isomorphic to Either[Option[A], B],
> which is nice in that it allows for a useful filter method.

It's also very similar to Lift's Box class:

http://www.assembla.com/spaces/liftweb/wiki/Box

So there is at least one precedent of someone needing a "three-state
Option" badly enough to create it and use it in their framework.

Anyway, I just wanted to mention that it seems be a commonly needed
pattern, I don't know if it has much bearing on the discussion about
right-biasing Either (of which I have no opinion one way or another).

Chris Marshall

unread,
May 17, 2012, 1:36:52 PM5/17/12
to tmo...@tmorris.net, scala-...@googlegroups.com
Scalaz's Validation does have flatMap. 

Welcome to Scala version 2.9.2 (Java HotSpot(TM) Server VM, Java 1.6.0_18).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import scalaz._; import Scalaz._
import scalaz._
import Scalaz._

scala> "1".success[Exception] flatMap (_.parseInt)
res0: scalaz.Validation[Exception,Int] = Success(1)

Or...

scala> for {
     | s <- "1".success[Exception]
     | i <- s.parseInt
     | }
     | yield i
res1: scalaz.Validation[Exception,Int] = Success(1)

It just doesn't have a "default" implicit monad (viewable by the lack of >>=)

scala> "1".success[Exception] >>= (_.parseInt)
<console>:14: error: could not find implicit value for parameter b: scalaz.Bind[[α]scalaz.Validation[Exception,α]]
              "1".success[Exception] >>= (_.parseInt)
                                     ^


...unless you import it, of course:

scala> import Validation.Monad._
import Validation.Monad._

scala> "1".success[Exception] >>= (_.parseInt)
res3: scalaz.Validation[Exception,Int] = Success(1)

Chris

> Date: Wed, 16 May 2012 07:32:56 +1000
> From: tonym...@gmail.com

Tony Morris

unread,
May 17, 2012, 6:09:37 PM5/17/12
to Chris Marshall, scala-...@googlegroups.com


On May 18, 2012 3:36 AM, "Chris Marshall" <oxbow...@hotmail.com> wrote:
>
> Scalaz's Validation does have flatMap. 

This will be fixed. Please assume it doesn't.

Tim Pigden

unread,
May 18, 2012, 2:49:28 AM5/18/12
to Tony Morris, Chris Marshall, scala-...@googlegroups.com
sorry Tony, what will be "fixed"?
Are you changing the behaviour of Validation significantly?

Chris Marshall

unread,
May 18, 2012, 4:49:39 AM5/18/12
to tmo...@tmorris.net, scala-...@googlegroups.com
I'll assume by "fixed", you mean "deprecated, with a clear migration strategy"


Date: Fri, 18 May 2012 08:09:37 +1000
Subject: RE: [scala-debate] right-biasing Either
From: tmo...@tmorris.net
To: oxbow...@hotmail.com
CC: scala-...@googlegroups.com

Jason Zaugg

unread,
May 18, 2012, 4:56:17 AM5/18/12
to Chris Marshall, tmo...@tmorris.net, scala-...@googlegroups.com
On Fri, May 18, 2012 at 10:49 AM, Chris Marshall
<oxbow...@hotmail.com> wrote:
> I'll assume by "fixed", you mean "deprecated, with a clear migration
> strategy"

I added that method and oppose its removal.

-jason

Chris Marshall

unread,
May 18, 2012, 4:59:47 AM5/18/12
to Jason Zaugg, tmo...@tmorris.net, scala-...@googlegroups.com
I oppose its removal as well; Validation is quite clearly a Monad.

Tony Morris

unread,
May 18, 2012, 5:25:05 AM5/18/12
to Tim Pigden, Chris Marshall, scala-...@googlegroups.com

Validation.flatMap should be a type error.

Chris Marshall

unread,
May 18, 2012, 6:02:19 AM5/18/12
to tmo...@tmorris.net, tim.p...@optrak.com, scala-...@googlegroups.com
I just don't get the position from the perspective of the types. Validation, fixed in its Failure type is an Applicative functor (which want to keep). It is also a Monad (which you don't). I recall someone saying something about types not lying

Chris


Date: Fri, 18 May 2012 19:25:05 +1000

Subject: Re: [scala-debate] right-biasing Either

Tony Morris

unread,
May 18, 2012, 8:32:28 AM5/18/12
to Chris Marshall, scala-...@googlegroups.com, tim.p...@optrak.com

It's not a monad, such that it obeys any relationship to its applicative functor.

Imagine if flatMap(point compose f) != map(f) for example.

Chris Marshall

unread,
May 18, 2012, 10:39:15 AM5/18/12
to tmo...@tmorris.net, scala-...@googlegroups.com, tim.p...@optrak.com
I was trying to follow what you were getting at and came up with the following:

scala> import scalaz._; import Scalaz._
import scalaz._
import Scalaz._

scala> type VS[a]=Validation[String, a]
defined type alias VS

scala> def point[A](a: A): VS[A] = a.success
point: [A](a: A)VS[A]

scala> def m[A, B](vs: VS[A])(f: A => B): VS[B] = vs map f
m: [A, B](vs: VS[A])(f: A => B)VS[B]

scala> def fm[A, B](vs: VS[A])(f: A => VS[B]): VS[B] = vs flatMap f
fm: [A, B](vs: VS[A])(f: A => VS[B])VS[B]

I presume the f in your example was a function A => M[B], so:

scala> val f: String => VS[Int] = s => try { s.toInt.success }  catch { case x => x.getMessage.fail }
f: String => VS[Int] = <function1>

So then I tried the success case:

scala> fm("1".success)(f andThen point)
res6: VS[VS[Int]] = Success(Success(1))

scala> m("1".success)(f)
res7: VS[VS[Int]] = Success(Success(1))

And the failure cases

scala> fm("a".success)(f andThen point)
res8: VS[VS[Int]] = Success(Failure(For input string: "a"))

scala> m("a".success)(f)
res9: VS[VS[Int]] = Success(Failure(For input string: "a"))

scala> fm("x".fail)(f andThen point)
res15: VS[VS[Int]] = Failure(x)

scala> m("x".fail)(f)
res16: VS[VS[Int]] = Failure(x)

They are the same. Maybe I've misunderstood your argument?

Chris

PS. Works with f as a function A => B anyway.

scala> val g: String => Int = _.length
g: String => Int = <function1>

scala> fm("a".success)(g andThen point)
res10: VS[Int] = Success(1)

scala> m("a".success)(g)
res12: VS[Int] = Success(1)

scala> fm("a".fail)(g andThen point)
res13: VS[Int] = Failure(a)

scala> m("a".fail)(g)
res14: VS[Int] = Failure(a)





Date: Fri, 18 May 2012 22:32:28 +1000
Subject: RE: [scala-debate] right-biasing Either
From: tmo...@tmorris.net
To: oxbow...@hotmail.com
CC: scala-...@googlegroups.com; tim.p...@optrak.com

Runar Bjarnason

unread,
May 18, 2012, 11:49:46 AM5/18/12
to scala-...@googlegroups.com, Chris Marshall, tim.p...@optrak.com
validation.flatMap(f) is simply shorthand for validation.toEither.flatMap(f).toValidation

It doesn't obey Monad on its own, but piggybacks on the Either monad, as it were. This is perfectly alright.

Daniel Sobral

unread,
May 18, 2012, 1:02:22 PM5/18/12
to Chris Marshall, tmo...@tmorris.net, scala-...@googlegroups.com, tim.p...@optrak.com
This is the coolest e-mail I read this year on a mailing list, hands down. :-)

On Fri, May 18, 2012 at 11:39 AM, Chris Marshall
--
Daniel C. Sobral

I travel to the future all the time.

missingfaktor

unread,
May 18, 2012, 2:24:14 PM5/18/12
to Chris Marshall, tmo...@tmorris.net, scala-...@googlegroups.com, tim.p...@optrak.com
Validation's applicative instance accumulates failures. Its monad instance doesn't (and can't), and thus does not comply with its applicative instance. That's what he meant.

scala> val List(a, b, c) = List(Success(2), Failure("foo"), Failure("bar")) : List[Validation[String, Int]]
a: scalaz.Validation[String,Int] = Success(2)
b: scalaz.Validation[String,Int] = Failure(foo)
c: scalaz.Validation[String,Int] = Failure(bar)

scala> (a |@| b |@| c)(_ + _ + _)
res2: scalaz.Validation[String,Int] = Failure(foobar)

scala> import Validation.Monad._
import Validation.Monad._

scala> (a |@| b |@| c)(_ + _ + _)
res3: scalaz.Validation[String,Int] = Failure(foo)

To put it differently, you can write two applicative instances for validation:
1. one that doesn't accumulate errors
2. one that does.

With (1), you can go further ahead and define monad instance. No laws are violated.

With (2), you obey the applicative laws, but violate monad laws, and so you cannot define a monad instance with this accumulation behavior.
--
Cheers,

Tony Morris

unread,
May 18, 2012, 7:43:56 PM5/18/12
to Runar Bjarnason, Chris Marshall, tim.p...@optrak.com, scala-...@googlegroups.com


On May 19, 2012 1:49 AM, "Runar Bjarnason" <runar...@gmail.com> wrote:
>
> validation.flatMap(f) is simply shorthand for validation.toEither.flatMap(f).toValidation

Actually it's the same as:
validation.toEither.flatMap(f andThen (_.toEither)).toValidation.

I agree this is a fine thing and only object to the method being called flatMap or the operation being called a monad. It is not.

√iktor Ҡlang

unread,
May 21, 2012, 5:14:11 AM5/21/12
to Jason Zaugg, scala-debate
So what's the status here.

I strongly think that we should right-bias Either and then remove Try and then simply have:

object Try {
  def apply[T](body: => T): Either[Throwable, T] = try Right(body) catch { case NonFatal(t) => Left(t) }
}

You could even add extracts for Success and Failure:

object Success {
  def unapply[T](e: Either[Throwable, T]): Option[T] = e.right.toOption //or simply e.toOption if right-biased
}

object Failure {
  def unapply[T](e: Either[Throwable, T]): Option[Throwable] = e.left.toOption //or simply e.toOption if right-biased
}

Cheers,


On Mon, May 14, 2012 at 9:08 AM, Jason Zaugg <jza...@gmail.com> wrote:
(A follow-up from ticket SI-5793. [1])

Apologies in advance to any left-handers out there.

I propose (not that I'm the first) to right-bias Either. Concretely,
this means we would add map/flatMap etc directly to Either, rather
than going through RightProjection. RightProjection could probably
deprecated.

Is there any previous discussion on this? Any arguments against?

-jason

[1] https://issues.scala-lang.org/browse/SI-5793



--
Viktor Klang

Akka Tech Lead
Typesafe - The software stack for applications that scale

Twitter: @viktorklang

Jason Zaugg

unread,
May 21, 2012, 5:37:54 AM5/21/12
to √iktor Ҡlang, scala-debate
On Mon, May 21, 2012 at 11:14 AM, √iktor Ҡlang <viktor...@gmail.com> wrote:
> So what's the status here.
>
> I strongly think that we should right-bias Either and then remove Try and
> then simply have:
>
> object Try {
>   def apply[T](body: => T): Either[Throwable, T] = try Right(body) catch {
> case NonFatal(t) => Left(t) }
> }
>
> You could even add extracts for Success and Failure:
>
> object Success {
>   def unapply[T](e: Either[Throwable, T]): Option[T] = e.right.toOption //or
> simply e.toOption if right-biased
> }
>
> object Failure {
>   def unapply[T](e: Either[Throwable, T]): Option[Throwable] =
> e.left.toOption //or simply e.toOption if right-biased
> }

Try catches exception on map/flatMap, which we can't (and shouldn't)
replicate with a wrapper around Either. It's really a different beast.
Maybe we need some input from people who use it.

-jason

Chris Marshall

unread,
May 21, 2012, 11:59:59 AM5/21/12
to Jason Zaugg, viktor...@gmail.com, scala-...@googlegroups.com
I have just got myself *incredibly confused* trying to understand what is going on is a for-comprehension using Either.RightProjection as the monad. Basically I can write a simple for-comprehension using Option

scala> for {
       |     str <- Option("1")
       |     i <- intOpt(str)  //intOpt is String => Option[String]
       |     val j = i + 10    //Note use of = in generator
       |   }
       |   yield j
    res18: Option[Int] = Some(11)

..and I want to convert it to using the Either monad. (i.e. replace Option("1") with Right[Throwable, String]("1") and intOpt with an intEither function

But it doesn't work (I think because RP.flatMap expects an R => Either[L, R]).

I've put it as a question on SO [1]. Any modifications to Either/Try etc should probably leave users less confused.

Chris

> From: jza...@gmail.com
> Date: Mon, 21 May 2012 11:37:54 +0200
> Subject: Re: [scala-debate] right-biasing Either

Jason Zaugg

unread,
May 21, 2012, 12:14:21 PM5/21/12
to Chris Marshall, viktor...@gmail.com, scala-...@googlegroups.com
On Mon, May 21, 2012 at 5:59 PM, Chris Marshall <oxbow...@hotmail.com> wrote:
> I have just got myself *incredibly confused* trying to understand what is
> going on is a for-comprehension using Either.RightProjection as the monad.
> Basically I can write a simple for-comprehension using Option
>
> scala> for {
>        |     str <- Option("1")
>        |     i <- intOpt(str)  //intOpt is String => Option[String]
>        |     val j = i + 10    //Note use of = in generator
>        |   }
>        |   yield j
>     res18: Option[Int] = Some(11)
>
>
> ..and I want to convert it to using the Either monad. (i.e. replace
> Option("1") with Right[Throwable, String]("1") and intOpt with an intEither
> function
>
> But it doesn't work (I think because RP.flatMap expects an R => Either[L,
> R]).
>
> I've put it as a question on SO [1]. Any modifications to Either/Try etc
> should probably leave users less confused.

That was the problem reported in SI-5793, which prompted me to start
this thread. I try to explain what's happening in the comments.

-jason

https://issues.scala-lang.org/browse/SI-5793?focusedCommentId=57583&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-57583

Joa Ebert

unread,
May 21, 2012, 1:00:54 PM5/21/12
to scala-...@googlegroups.com, Chris Marshall, viktor...@gmail.com
I am also in favor of a right-biased Either. It is simple, easy to understand and fulfills the need of encoding failure/success in a type. 

I would vote against adding Try in its current fashion to the standard library without a right-biased Either. Our use case is different for instance. We encode failure into an ADT and unexpected exceptions are wrapped. Try makes only sense if one does not use Either. I wonder how you are supposed to work with Try[Either[A, B]] in a sane way? Yeah, it is possible of course but not very convenient. I imagine it would be nice to have the best of both worlds: Tryther[A, B] ;)


Best,

Joa

On Monday, May 21, 2012 6:14:21 PM UTC+2, Jason Zaugg wrote:

Rex Kerr

unread,
May 21, 2012, 2:24:35 PM5/21/12
to Chris Marshall, scala-...@googlegroups.com
FWIW, the Has class that I linked to earlier in this thread handles this case without a glitch.  (At least as it stands in my current codebase; I may have tweaked it slightly since the PasteBin post.)

  --Rex

Chris Marshall

unread,
May 21, 2012, 2:44:23 PM5/21/12
to Jason Zaugg, viktor...@gmail.com, scala-...@googlegroups.com
Apologies - I missed the beginning of the thread. Personally I like the syntax of the twitter Try class, it maps more closely to the use case. Obviously it's less flexible than right-biasing Either because it's fixed in its "left" type; however, I dislike having two almost-identical classes in the standard library. I think for that reason, I'd have to vote for right-biasing Either.

Chris

> From: jza...@gmail.com
> Date: Mon, 21 May 2012 18:14:21 +0200
> Subject: Re: [scala-debate] right-biasing Either

Rob Dickens

unread,
May 28, 2012, 8:44:53 AM5/28/12
to Chris Marshall, Jason Zaugg, scala-debate
Chris, Jason, All,

How about just fixing the problem in the bug report*, which I think
I've just managed to do:

http://robsscala.blogspot.co.uk/2012/05/fixing-scalaeither-leftrightmap-returns.html

* https://issues.scala-lang.org/browse/SI-5793

Rob

√iktor Ҡlang

unread,
May 28, 2012, 9:07:55 AM5/28/12
to Rob Dickens, Chris Marshall, Jason Zaugg, scala-debate
On Mon, May 28, 2012 at 2:44 PM, Rob Dickens <robcd...@gmail.com> wrote:
Chris, Jason, All,

How about just fixing the problem in the bug report*, which I think
I've just managed to do:

http://robsscala.blogspot.co.uk/2012/05/fixing-scalaeither-leftrightmap-returns.html

* https://issues.scala-lang.org/browse/SI-5793

I think this violates DRY in the sense that you have to scatter "right"'s all over the for-comprehensions.

Cheers,

Rob Dickens

unread,
May 28, 2012, 10:47:39 AM5/28/12
to √iktor Ҡlang, Chris Marshall, Jason Zaugg, scala-debate
You're er, right about that, although this was of course the situation
before. A small downside to using something that's unbiased, but
nevertheless a valid argument in favour of using something that's
biased.

Rob Dickens

unread,
Jun 7, 2012, 12:48:31 PM6/7/12
to scala-debate, Kevin Wright, Heather Miller, Jason Zaugg, l...@underneath.ca, Rex Kerr, Tony Morris
That 'Checked' class I was thinking about, I've now written:

http://robsscala.blogspot.co.uk/2012/06/okayreason-extends-checked-biased.html

On Tue, May 15, 2012 at 12:49 PM, Rob Dickens <robcd...@gmail.com> wrote:
> How about doing the following:
>
> * leave Either as it is, since the name doesn't imply any bias
> (although Right certainly does), and it looks like changing it would
> only buy you definitions in for-comprehensions (and not having to add
> .right)
>
> * introduce a completely new class, Checked, having OK and KO as the
> type constructors
>
> * include support for combining Checked values in both a fail-fast and
> fail-slow manner, including applicative-functor support (<*>
> operator), similar to that which I describe here:
>
> http://robsscala.blogspot.co.uk/2012/05/validating-multiple-values-at-once.html
>
> Rob
>
> On Tue, May 15, 2012 at 10:01 AM, Kevin Wright <kev.lee...@gmail.com> wrote:
>> I want to have my cake and eat it too!  A right-biased disjoint union in
>> which I can parameterise the type of BOTH sides.
>>
>> Consider this example:
>>
>> https://gist.github.com/1262988
>>
>> My rejection is NOT a Throwable, it doesn't incur the cost of building the
>> stack trace for an exception, and it additionally carries the value that
>> caused the failure to occur.
>>
>> Yes, I know that I were to use Try I could create my own Throwable/Exception
>> type and have it carry whatever other values I care for.  But that's just
>> removing ceremony from one place only to hand it back in another, likely
>> sacrificing performance in the process.
>>
>>
>> On 15 May 2012 09:39, Heather Miller <heather...@epfl.ch> wrote:
>>>
>>> To copy/paste a tidbit of motivation here:
>>>
>>> We introduced `Try` a while back along with SIP-14 (Futures). `Try` is
>>> analogous to `Either` with the exception that it's success-biased. That is,
>>> Either is symmetric, it has two type parameters that are wrapped
>>> (symmetrically) in either `Left` or `Right`. In general, by convention,
>>> `Either` can be used to represent a "successful" or a "failed" result, by
>>> representing some generic type in its right projection, and a subtype of
>>> Throwable in its left projection. However, this is by convention only, one
>>> can of course swap these projections (whether accidentally or purposefully)
>>> or one can represent two successful values in each projection if they so
>>> desire.
>>>
>>> `Try`, on the other hand, is parameterized only on one type, with this
>>> success/failure use case in mind. That is, the successful case is wrapped in
>>> `Success` (parameterized on T) while the failed case is a `Throwable`
>>> wrapped in `Failure`.
>>>
>>> `Try` comes from Twitter, who use it frequently in their codebase (see
>>> twitter/util on github), and who have found that it results in more readable
>>> and less error-prone code for this success/failure use case of `Either`.
>>>
>>> --
>>> Heather Miller
>>> Doctoral Assistant
>>> EPFL, IC, LAMP
>>> http://people.epfl.ch/heather.miller
>>>
>>> On Tuesday, May 15, 2012 at 10:25 AM, Heather Miller wrote:
>>>
>>> This comes from discussions with Twitter several months ago during the
>>> evolution of the Futures library. Apparently, Twitter heavily uses Try
>>> internally, they have a couple of years of experience with it and attest
>>> that it results in much simpler, more readable, and less accident-prone (wrt
>>> swapping Left and Right) code. As a result, on their end, they require that
>>> Futures use Try over Either. So, during a few discussions here, Martin was
>>> in favor of introducing Try to the stdlib and using them with the Futures
>>> library, as, arguably, Twitter's Futures library has to be the most
>>> battle-tested Scala Futures library out there.
>>>
>>> However, since the Akka folks solidified their API before scala.concurrent
>>> was finalized, that decision was reversed. So, the signatures in
>>> scala.concurrent still involve Either, but there exists an extractor which
>>> allow one to use Trys as well.
>>>
>>> So, usage like:
>>>
>>> val f = future{0}
>>>
>>> f onComplete {
>>>   case Success(v) => println(v)
>>>   case Failure(e) => println("Exception")
>>> }
>>>
>>> is still possible.
>>>
>>> Since it's a small step towards unifying more Futures libraries (as
>>> Twitter is an important user, likewise with a lot of valuable experience),
>>> it's been agreed for a bit that Try will likely stick around.
>>>
>>> Though, a bottom-line here is, of course, that Try can be used outside of
>>> the context of Futures.
>>>
>>> --
>>> Heather Miller
>>> Doctoral Assistant
>>> EPFL, IC, LAMP
>>> http://people.epfl.ch/heather.miller
>>>
>>> On Tuesday, May 15, 2012 at 8:44 AM, Jason Zaugg wrote:
>>>
>>> On Tue, May 15, 2012 at 8:37 AM, Lee Mighdoll <l...@underneath.ca> wrote:
>>>
>>> Most especially, it's about being able to do so in the context of a
>>> for-comprehension.
>>>
>>>
>>>
>>> Fair enough.  But if this is the only thing it can do, I'm not sure it's
>>> worth it.
>>>
>>>
>>>
>>> +1 for for comprehensions.  They enable a code style that's very clear,
>>> and
>>> really a nice scala selling point when compared to more mainstream
>>> languages.  Let's make for comprehensions shine.
>>>
>>> Note that in for comprehensions the existing Either implementation isn't
>>> just extra boilerplate to pick a projection on every line.  Definitions
>>> don't work.
>>>
>>> As is, I don't think we can recommend using Either to our teams today,
>>> certainly not without bunch of caveats and extra explanation.  That argues
>>> we ought fix the existing Either, rather than pick a new class.
>>>
>>> And I don't think there'd be much cost to the change.  There'd be little
>>> mental shift required of the community if the right side of the Either
>>> gets
>>> blessed.  I'll guess that the vast majority of existing Either users
>>> mentally associate Either with the asymmetric use case already (even as we
>>> appreciate the nifty symmetry of the existing design).  Think Either, and
>>> I
>>> bet most think of a tool for dealing with Left(error) and Right(result).
>>>
>>> +1 for biasing Either in 2.10
>>>
>>>
>>> A new player has entered the arena:
>>>
>>>
>>> https://github.com/scala/scala/blob/master/src/library/scala/util/Try.scala
>>>
>>> -jason
>>>
>>>
>>>
>>
>>
>>
>> --
>> Kevin Wright
>> mail: kevin....@scalatechnology.com
>> gtalk / msn : kev.lee...@gmail.com
>> quora: http://www.quora.com/Kevin-Wright
>> google+: http://gplus.to/thecoda
>> twitter: @thecoda
>> vibe / skype: kev.lee.wright
>> steam: kev_lee_wright
>>
>> "My point today is that, if we wish to count lines of code, we should not
>> regard them as "lines produced" but as "lines spent": the current
>> conventional wisdom is so foolish as to book that count on the wrong side of
>> the ledger" ~ Dijkstra
>>

Rex Kerr

unread,
Jun 7, 2012, 2:02:03 PM6/7/12
to Rob Dickens, scala-debate, Kevin Wright, Heather Miller, Jason Zaugg, l...@underneath.ca, Tony Morris
It is a little awkward to simply say, "Don't use if in your for statements".

This is why when I wrote Has, I gave it three states (isomorphic to Either[Option[A],B]).

Personally, I found working without a generic reason to be awkward.

  --Rex

Rob Dickens

unread,
Jun 8, 2012, 5:50:10 AM6/8/12
to Rex Kerr, scala-debate, Kevin Wright, Heather Miller, Jason Zaugg, l...@underneath.ca, Tony Morris
On Thu, Jun 7, 2012 at 7:02 PM, Rex Kerr <ich...@gmail.com> wrote:
> It is a little awkward to simply say, "Don't use if in your for statements".
>
> This is why when I wrote Has, I gave it three states (isomorphic to
> Either[Option[A],B]).

Rex, Please could you point me to an example that demonstrates why it's awkward.

>
> Personally, I found working without a generic reason to be awkward.

Sorry, I don't understand what you mean.

Rex Kerr

unread,
Jun 8, 2012, 6:23:00 AM6/8/12
to Rob Dickens, scala-debate
On Fri, Jun 8, 2012 at 5:50 AM, Rob Dickens <robcd...@gmail.com> wrote:
On Thu, Jun 7, 2012 at 7:02 PM, Rex Kerr <ich...@gmail.com> wrote:
> It is a little awkward to simply say, "Don't use if in your for statements".
>
> This is why when I wrote Has, I gave it three states (isomorphic to
> Either[Option[A],B]).

Rex, Please could you point me to an example that demonstrates why it's awkward.

Sure.  Lots of methods return Option--headOption, for example.  As such, you might have a method read() which returns a Checked[Exception,Seq[String]].  Maybe you only need the head, and only then if that head is nonempty.

With my implementation of Has, you would write

  for (ss <- read(); h <- ss.headOption if (h != "")) println(h)

whereas with Either you would be forced to

  read().right.flatMap{ _.headOption.filter(_ != "").toRight(new Exception("Zero string")) }.foreach{ h => println(h) }

and with Checked--well, your implementation doesn't seem to have interoperability with Option at all, so it would be even more awkward.

 
>
> Personally, I found working without a generic reason to be awkward.

Sorry, I don't understand what you mean.

See the "new Exception("Zero string")" up there that I was forced to include with Either because I had to pass back _some_ exception, even though it wasn't really appropriate?

That's what I mean.

With exceptions, I might have a val didntLikeThatException = ... which I could drop in anywhere I didn't want to specify a real exception.  But this wouldn't work for, say, user records (or anything else difficult or expensive to fake).  So the pattern Checked[HeavyItemThatFailed, LightAnswer] is only viable if you are absolutely sure you will always fail with HeavyItem in hand.  Otherwise you need to Checked[Option[HeavyItem], LightAnswer].  (Likewise with Either.)

  --Rex

Rob Dickens

unread,
Jun 8, 2012, 8:33:01 AM6/8/12
to Rex Kerr, scala-debate
Thanks for the example.

I've just found out that you can still use 'if' in for-comprehensions
which don't 'yield' anything (i.e. which invoke foreach), even when
you don't supply a filter or withFilter! (Maybe it's using those
provided by the Option, in this particular example.)

And if you do want to yield something, Checked has a toOption.

Please see the following test-code, based on your example, which I've
just added to the project:

https://github.com/robcd/scala-checking/blob/master/src/test/scala/TestsInvolvingOption.scala

Rex Kerr

unread,
Jun 8, 2012, 8:52:47 AM6/8/12
to Rob Dickens, scala-debate
This is obviously a matter of preference, but I prefer the consistency of having yields and not both work (so I can switch to yielding if, for example, I change a side-effecting algorithm to a pure one).

Also, while Checked does have a toOption, that doesn't solve the problem--maybe I want to know if there was an IOException on read()!  You can always downgrade (with Either, also), but _up_grading from Option to something richer is what is missing to make working with a right-biased Either replacement as easy as working with Option.

Anyway, Checked looks decent to me as what Either could turn into; I just doubt I'd use it much more than I used Either since, while it makes things a _little_ easier, it only covers a modest portion of the use cases that drive me to Option from Either now.  Enriching (or simply adding in the library) on an eitherOr[B](b: B): Reason[B,A] to Option would help a bit (to avoid the awkwardness of getOrElse), but I'm just not that excited about having a not-for-comprehension-complete-or-feature-complete solution to a problem that has the same qualities (albeit to a greater extent).

  --Rex

Rob Dickens

unread,
Jun 9, 2012, 5:41:24 AM6/9/12
to Rex Kerr, scala-debate
Rex, I've just added some more tests here:

https://github.com/robcd/scala-checking/blob/master/src/test/scala/TestsInvolvingOption.scala

Please have a look at the last four, which demonstrate converting from a

Checked[A, R], where A is Seq[String], to a

Checked[B, R], where B is Option[String].

Doesn't that do what you wanted?

Rob

Rex Kerr

unread,
Jun 9, 2012, 6:29:57 AM6/9/12
to Rob Dickens, scala-debate
It's certainly perfectly workable!  It's just not as compact as I like (it forces me to write an extra method instead of stating what I want in the for comprehension).  It's hard to have everything at once; I chose to add a third state to get everything I wanted (save for that third state, which I would just as soon not have to think about).  Making it not-too-awkward to deal with two states is another way to go.

  --Rex

Marc Siegel

unread,
Aug 12, 2013, 12:52:35 PM8/12/13
to scala-...@googlegroups.com, Chris Marshall
Hi all,

A similar discussion is now going on in scala-lang here:

Re-iterating: Can someone closer to the core Scala language team please clarify for our team:

  1. Are Either's supposed to break for-expressions, even when using #right (see the discussion at link and SI-5793)
     a.  If not, can this be fixed?
     b.  If so, is it "accepted best practice" to use an implicit to right-bias them?
          i.  If so, can this be documented somewhere?
          ii.  If not, please clarify the best practice in using standard library (ie, "use scalaz" not a good answer)

Thanks all, hope we can get a clear guidance on this obvious usage area (Eithers in for-expressions) over at the scala-lang discussion linked above.

-Marc

--
Marc Siegel
Team Lead
TIM Group

martin odersky

unread,
Aug 12, 2013, 12:59:48 PM8/12/13
to Marc Siegel, scala-debate, Chris Marshall
I am not intimately involved with the discussion, but my impression was that we wanted to get away from Either, and suggest to use Try as a better "biased" option instead. Would that work for your use-case, Marc?

If Either is de-emphasized then my personal preference would be to not change it. But like I said, I am not too familiar with the discussion so if others want to jump in with a different opinion I might bow out quickly :-)

 - Martin
 
It is loading more messages.
0 new messages