FAQ
I just discovered a difference between Either and Try, but I think it's a
design error.

Because Either is a generic disjoint union, I can put anything into Left:

scala> Left("foo")
res0: scala.util.Left[String,Nothing] = Left(foo)

With Try, I can also put anything into Success:

scala> import util.{Success, Failure}
import util.{Success, Failure}

scala> Success("Foo")
res1: scala.util.Success[String] = Success(Foo)

However, if I try to put anything into Failure, Scala complains:

scala> Failure("Foo")
<console>:9: error: type mismatch;
found : String("Foo")
required: Throwable
Failure("Foo")
^

So if I want to put anything into a Failure, I have to wrap it into
something Throwable, like this:

case class Why(reason:Any) extends Throwable
def e = Failure(Why("ouch!"))

I would like to present Success and Failure as the preferred way to report
errors; that is, Either should only be used when you have two possible
return types which are what I'll call "of equal weight," where one does not
represent an error (a previous example in this list, if I remember
correctly, had a choice where you might get an Int or you might get a
String). If you're producing a Success or reporting a Failure, you should
use those types, which provide much clearer intent.

To do this, I argue that Failure should be able to accept Any, not just
Throwable. I think that would help in moving to this new error-handling
approach.

-- Bruce Eckel
www.AtomicScala.com
www.Reinventing-Business.com
www.MindviewInc.com

Search Discussions

  • Rex Kerr at Aug 25, 2012 at 8:21 pm
    I disagree. We already have Either for that. The distinction should be
    clear:
    - If you want to catch exceptions robustly and hang on to them, use Try
    - If you want to do anything more elaborate or generic, use Either

    If I get a Try, I don't want to have to handle any possible untyped object
    that someone might have tossed in there. Throwables give you quite a bit:
    stack trace, usually, error message, etc.. Also, when using Try what I
    should be most worried about is the control flow disruption that an
    exception can cause--it handles that exception by catching all of them used
    anywhere within the Try (at least as long as the method still returns a
    Try).

    If you don't want that, Either can help and has a fighting chance of being
    the right type, too.

    --Rex
    On Sat, Aug 25, 2012 at 4:07 PM, Bruce Eckel wrote:

    I just discovered a difference between Either and Try, but I think it's a
    design error.

    Because Either is a generic disjoint union, I can put anything into Left:

    scala> Left("foo")
    res0: scala.util.Left[String,Nothing] = Left(foo)

    With Try, I can also put anything into Success:

    scala> import util.{Success, Failure}
    import util.{Success, Failure}

    scala> Success("Foo")
    res1: scala.util.Success[String] = Success(Foo)

    However, if I try to put anything into Failure, Scala complains:

    scala> Failure("Foo")
    <console>:9: error: type mismatch;
    found : String("Foo")
    required: Throwable
    Failure("Foo")
    ^

    So if I want to put anything into a Failure, I have to wrap it into
    something Throwable, like this:

    case class Why(reason:Any) extends Throwable
    def e = Failure(Why("ouch!"))

    I would like to present Success and Failure as the preferred way to report
    errors; that is, Either should only be used when you have two possible
    return types which are what I'll call "of equal weight," where one does not
    represent an error (a previous example in this list, if I remember
    correctly, had a choice where you might get an Int or you might get a
    String). If you're producing a Success or reporting a Failure, you should
    use those types, which provide much clearer intent.

    To do this, I argue that Failure should be able to accept Any, not just
    Throwable. I think that would help in moving to this new error-handling
    approach.

    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com
  • Bruce Eckel at Aug 25, 2012 at 8:32 pm
    Either is generic and doesn't telegraph the intent. Left/Right doesn't mean
    anything. Success/Failure is quite meaningful.

    At some point you have to convey to the client programmer what your
    function will return and they have to adapt to that. It's part of your
    interface. If your function returns a Failure containing a Throwable, the
    client programmer has to deal with that. It's no different than if your
    function returns a Failure containing some other kind of information; the
    client programmer has to know what it is and deal with that, too.

    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com


    On Sat, Aug 25, 2012 at 2:21 PM, Rex Kerr wrote:

    I disagree. We already have Either for that. The distinction should be
    clear:
    - If you want to catch exceptions robustly and hang on to them, use Try
    - If you want to do anything more elaborate or generic, use Either

    If I get a Try, I don't want to have to handle any possible untyped object
    that someone might have tossed in there. Throwables give you quite a bit:
    stack trace, usually, error message, etc.. Also, when using Try what I
    should be most worried about is the control flow disruption that an
    exception can cause--it handles that exception by catching all of them used
    anywhere within the Try (at least as long as the method still returns a
    Try).

    If you don't want that, Either can help and has a fighting chance of being
    the right type, too.

    --Rex

    On Sat, Aug 25, 2012 at 4:07 PM, Bruce Eckel wrote:

    I just discovered a difference between Either and Try, but I think it's a
    design error.

    Because Either is a generic disjoint union, I can put anything into Left:

    scala> Left("foo")
    res0: scala.util.Left[String,Nothing] = Left(foo)

    With Try, I can also put anything into Success:

    scala> import util.{Success, Failure}
    import util.{Success, Failure}

    scala> Success("Foo")
    res1: scala.util.Success[String] = Success(Foo)

    However, if I try to put anything into Failure, Scala complains:

    scala> Failure("Foo")
    <console>:9: error: type mismatch;
    found : String("Foo")
    required: Throwable
    Failure("Foo")
    ^

    So if I want to put anything into a Failure, I have to wrap it into
    something Throwable, like this:

    case class Why(reason:Any) extends Throwable
    def e = Failure(Why("ouch!"))

    I would like to present Success and Failure as the preferred way to
    report errors; that is, Either should only be used when you have two
    possible return types which are what I'll call "of equal weight," where one
    does not represent an error (a previous example in this list, if I remember
    correctly, had a choice where you might get an Int or you might get a
    String). If you're producing a Success or reporting a Failure, you should
    use those types, which provide much clearer intent.

    To do this, I argue that Failure should be able to accept Any, not just
    Throwable. I think that would help in moving to this new error-handling
    approach.

    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com
  • √iktor Ҡlang at Aug 25, 2012 at 8:43 pm

    On Sat, Aug 25, 2012 at 10:32 PM, Bruce Eckel wrote:

    Either is generic and doesn't telegraph the intent. Left/Right doesn't
    mean anything. Success/Failure is quite meaningful.

    import scala.util.{ Either => MyIntent, Right => MyRightIntent, Left =>
    MyLeftIntent }

    At some point you have to convey to the client programmer what your
    function will return and they have to adapt to that. It's part of your
    interface. If your function returns a Failure containing a Throwable, the
    client programmer has to deal with that. It's no different than if your
    function returns a Failure containing some other kind of information; the
    client programmer has to know what it is and deal with that, too.
    Can you explain how you'd implement the same behavior as Try has now if
    Failure was of Any instead of Throwable?

    Cheers,



    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com


    On Sat, Aug 25, 2012 at 2:21 PM, Rex Kerr wrote:

    I disagree. We already have Either for that. The distinction should be
    clear:
    - If you want to catch exceptions robustly and hang on to them, use Try
    - If you want to do anything more elaborate or generic, use Either

    If I get a Try, I don't want to have to handle any possible untyped
    object that someone might have tossed in there. Throwables give you quite
    a bit: stack trace, usually, error message, etc.. Also, when using Try
    what I should be most worried about is the control flow disruption that an
    exception can cause--it handles that exception by catching all of them used
    anywhere within the Try (at least as long as the method still returns a
    Try).

    If you don't want that, Either can help and has a fighting chance of
    being the right type, too.

    --Rex

    On Sat, Aug 25, 2012 at 4:07 PM, Bruce Eckel wrote:

    I just discovered a difference between Either and Try, but I think it's
    a design error.

    Because Either is a generic disjoint union, I can put anything into Left:

    scala> Left("foo")
    res0: scala.util.Left[String,Nothing] = Left(foo)

    With Try, I can also put anything into Success:

    scala> import util.{Success, Failure}
    import util.{Success, Failure}

    scala> Success("Foo")
    res1: scala.util.Success[String] = Success(Foo)

    However, if I try to put anything into Failure, Scala complains:

    scala> Failure("Foo")
    <console>:9: error: type mismatch;
    found : String("Foo")
    required: Throwable
    Failure("Foo")
    ^

    So if I want to put anything into a Failure, I have to wrap it into
    something Throwable, like this:

    case class Why(reason:Any) extends Throwable
    def e = Failure(Why("ouch!"))

    I would like to present Success and Failure as the preferred way to
    report errors; that is, Either should only be used when you have two
    possible return types which are what I'll call "of equal weight," where one
    does not represent an error (a previous example in this list, if I remember
    correctly, had a choice where you might get an Int or you might get a
    String). If you're producing a Success or reporting a Failure, you should
    use those types, which provide much clearer intent.

    To do this, I argue that Failure should be able to accept Any, not just
    Throwable. I think that would help in moving to this new error-handling
    approach.

    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com

    --
    Viktor Klang

    Akka Tech Lead
    Typesafe <http://www.typesafe.com/> - The software stack for applications
    that scale

    Twitter: @viktorklang
  • Rex Kerr at Aug 25, 2012 at 8:44 pm

    On Sat, Aug 25, 2012 at 4:32 PM, Bruce Eckel wrote:

    Either is generic and doesn't telegraph the intent. Left/Right doesn't
    mean anything. Success/Failure is quite meaningful.

    That's why we have conventions.

    Right is the right thing.
    Left is if something went wrong.

    It's not that hard to remember!

    At some point you have to convey to the client programmer what your
    function will return and they have to adapt to that. It's part of your
    interface. If your function returns a Failure containing a Throwable, the
    client programmer has to deal with that. It's no different than if your
    function returns a Failure containing some other kind of information; the
    client programmer has to know what it is and deal with that, too.
    The difference is that Either will tell you what the Left type is. Failure
    will not and cannot given that it wraps Throwables (unless the Failure type
    in Either[Throwable,A]!).

    --Rex
  • Richard Wallace at Aug 25, 2012 at 11:31 pm

    On Sat, Aug 25, 2012 at 1:32 PM, Bruce Eckel wrote:
    Either is generic and doesn't telegraph the intent. Left/Right doesn't mean
    anything. Success/Failure is quite meaningful.
    Success/Failure is no more meaningful than Left/Right. They are just
    names. Using Either for a errors it is quite apparent which side is
    the error and which the success based on the type you give them. I do
    agree with others that parameterizing Try in the error type is a bad
    idea. But I'd go further and say that Try itself is actually a bad
    idea and should *never be used for anything*. After looking into it
    in detail, the implementation of flatMap, map etc have radically
    different semantics than other types that implement these methods and
    will make it much harder to reason about code.
    At some point you have to convey to the client programmer what your function
    will return and they have to adapt to that. It's part of your interface. If
    your function returns a Failure containing a Throwable, the client
    programmer has to deal with that. It's no different than if your function
    returns a Failure containing some other kind of information; the client
    programmer has to know what it is and deal with that, too.


    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com


    On Sat, Aug 25, 2012 at 2:21 PM, Rex Kerr wrote:

    I disagree. We already have Either for that. The distinction should be
    clear:
    - If you want to catch exceptions robustly and hang on to them, use Try
    - If you want to do anything more elaborate or generic, use Either

    If I get a Try, I don't want to have to handle any possible untyped object
    that someone might have tossed in there. Throwables give you quite a bit:
    stack trace, usually, error message, etc.. Also, when using Try what I
    should be most worried about is the control flow disruption that an
    exception can cause--it handles that exception by catching all of them used
    anywhere within the Try (at least as long as the method still returns a
    Try).

    If you don't want that, Either can help and has a fighting chance of being
    the right type, too.

    --Rex


    On Sat, Aug 25, 2012 at 4:07 PM, Bruce Eckel <bruceteckel@gmail.com>
    wrote:
    I just discovered a difference between Either and Try, but I think it's a
    design error.

    Because Either is a generic disjoint union, I can put anything into Left:

    scala> Left("foo")
    res0: scala.util.Left[String,Nothing] = Left(foo)

    With Try, I can also put anything into Success:

    scala> import util.{Success, Failure}
    import util.{Success, Failure}

    scala> Success("Foo")
    res1: scala.util.Success[String] = Success(Foo)

    However, if I try to put anything into Failure, Scala complains:

    scala> Failure("Foo")
    <console>:9: error: type mismatch;
    found : String("Foo")
    required: Throwable
    Failure("Foo")
    ^

    So if I want to put anything into a Failure, I have to wrap it into
    something Throwable, like this:

    case class Why(reason:Any) extends Throwable
    def e = Failure(Why("ouch!"))

    I would like to present Success and Failure as the preferred way to
    report errors; that is, Either should only be used when you have two
    possible return types which are what I'll call "of equal weight," where one
    does not represent an error (a previous example in this list, if I remember
    correctly, had a choice where you might get an Int or you might get a
    String). If you're producing a Success or reporting a Failure, you should
    use those types, which provide much clearer intent.

    To do this, I argue that Failure should be able to accept Any, not just
    Throwable. I think that would help in moving to this new error-handling
    approach.

    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com
  • Tony Morris at Aug 25, 2012 at 11:33 pm
    I concur. scala.util.Try should never be used.
    On 26/08/12 09:31, Richard Wallace wrote:
    On Sat, Aug 25, 2012 at 1:32 PM, Bruce Eckel wrote:
    Either is generic and doesn't telegraph the intent. Left/Right doesn't mean
    anything. Success/Failure is quite meaningful.
    Success/Failure is no more meaningful than Left/Right. They are just
    names. Using Either for a errors it is quite apparent which side is
    the error and which the success based on the type you give them. I do
    agree with others that parameterizing Try in the error type is a bad
    idea. But I'd go further and say that Try itself is actually a bad
    idea and should *never be used for anything*. After looking into it
    in detail, the implementation of flatMap, map etc have radically
    different semantics than other types that implement these methods and
    will make it much harder to reason about code.
    At some point you have to convey to the client programmer what your function
    will return and they have to adapt to that. It's part of your interface. If
    your function returns a Failure containing a Throwable, the client
    programmer has to deal with that. It's no different than if your function
    returns a Failure containing some other kind of information; the client
    programmer has to know what it is and deal with that, too.


    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com


    On Sat, Aug 25, 2012 at 2:21 PM, Rex Kerr wrote:
    I disagree. We already have Either for that. The distinction should be
    clear:
    - If you want to catch exceptions robustly and hang on to them, use Try
    - If you want to do anything more elaborate or generic, use Either

    If I get a Try, I don't want to have to handle any possible untyped object
    that someone might have tossed in there. Throwables give you quite a bit:
    stack trace, usually, error message, etc.. Also, when using Try what I
    should be most worried about is the control flow disruption that an
    exception can cause--it handles that exception by catching all of them used
    anywhere within the Try (at least as long as the method still returns a
    Try).

    If you don't want that, Either can help and has a fighting chance of being
    the right type, too.

    --Rex


    On Sat, Aug 25, 2012 at 4:07 PM, Bruce Eckel <bruceteckel@gmail.com>
    wrote:
    I just discovered a difference between Either and Try, but I think it's a
    design error.

    Because Either is a generic disjoint union, I can put anything into Left:

    scala> Left("foo")
    res0: scala.util.Left[String,Nothing] = Left(foo)

    With Try, I can also put anything into Success:

    scala> import util.{Success, Failure}
    import util.{Success, Failure}

    scala> Success("Foo")
    res1: scala.util.Success[String] = Success(Foo)

    However, if I try to put anything into Failure, Scala complains:

    scala> Failure("Foo")
    <console>:9: error: type mismatch;
    found : String("Foo")
    required: Throwable
    Failure("Foo")
    ^

    So if I want to put anything into a Failure, I have to wrap it into
    something Throwable, like this:

    case class Why(reason:Any) extends Throwable
    def e = Failure(Why("ouch!"))

    I would like to present Success and Failure as the preferred way to
    report errors; that is, Either should only be used when you have two
    possible return types which are what I'll call "of equal weight," where one
    does not represent an error (a previous example in this list, if I remember
    correctly, had a choice where you might get an Int or you might get a
    String). If you're producing a Success or reporting a Failure, you should
    use those types, which provide much clearer intent.

    To do this, I argue that Failure should be able to accept Any, not just
    Throwable. I think that would help in moving to this new error-handling
    approach.

    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com

    --
    Tony Morris
    http://tmorris.net/
  • Matthew Pocock at Aug 25, 2012 at 11:49 pm

    On 26 August 2012 00:31, Richard Wallace wrote:
    On Sat, Aug 25, 2012 at 1:32 PM, Bruce Eckel wrote:
    Either is generic and doesn't telegraph the intent. Left/Right doesn't mean
    anything. Success/Failure is quite meaningful.
    Success/Failure is no more meaningful than Left/Right. They are just
    names.

    We have to agree to disagree here. They are indeed names, but there is no
    'just' about it. Names are incredibly important, and are the glue between
    what people are trying to model and the code that models it. The
    data-structures for Left/Right and Success/Failure have no inherent meaning
    and in some implementations may be isomorphic or even virtually identical,
    but through their names and our expectations, they mean something *to us*.
    We create case classes like Person, Address, .... rather than using
    Tuple<N> precisely because we want to attach meaningful names to things. If
    it was 'just' names, then Tuple2[String, Int] and _1, _2 and so on would be
    sufficient. They are not because there is no 'just' about names.

    (obviously, there's also polymorphic dispatch to be considered, but this
    doesn't require meaningful names either - a numeric index would be
    sufficient)

    M

    --
    Dr Matthew Pocock
    Integrative Bioinformatics Group, School of Computing Science, Newcastle
    University
    mailto: turingatemyhamster@gmail.com
    gchat: turingatemyhamster@gmail.com
    msn: matthew_pocock@yahoo.co.uk
    irc.freenode.net: drdozer
    skype: matthew.pocock
    tel: (0191) 2566550
    mob: +447535664143
  • Peter Pnin at Aug 26, 2012 at 12:01 am
    "Success/Failure is no more meaningful than Left/Right. They are just
    names"

    You can't quite be serious. I mean, that is a spectacularly silly thing to
    say. Will give you the benefit of the doubt.

    (The most aptly named class in scalaz is surely:

    https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Name.scala)



    On Saturday, August 25, 2012 7:31:04 PM UTC-4, Richard Wallace wrote:
    On Sat, Aug 25, 2012 at 1:32 PM, Bruce Eckel wrote:
    Either is generic and doesn't telegraph the intent. Left/Right doesn't mean
    anything. Success/Failure is quite meaningful.
    Success/Failure is no more meaningful than Left/Right. They are just
    names. Using Either for a errors it is quite apparent which side is
    the error and which the success based on the type you give them. I do
    agree with others that parameterizing Try in the error type is a bad
    idea. But I'd go further and say that Try itself is actually a bad
    idea and should *never be used for anything*. After looking into it
    in detail, the implementation of flatMap, map etc have radically
    different semantics than other types that implement these methods and
    will make it much harder to reason about code.
    At some point you have to convey to the client programmer what your function
    will return and they have to adapt to that. It's part of your interface. If
    your function returns a Failure containing a Throwable, the client
    programmer has to deal with that. It's no different than if your function
    returns a Failure containing some other kind of information; the client
    programmer has to know what it is and deal with that, too.


    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com


    On Sat, Aug 25, 2012 at 2:21 PM, Rex Kerr wrote:

    I disagree. We already have Either for that. The distinction should
    be
    clear:
    - If you want to catch exceptions robustly and hang on to them, use
    Try
    - If you want to do anything more elaborate or generic, use Either

    If I get a Try, I don't want to have to handle any possible untyped
    object
    that someone might have tossed in there. Throwables give you quite a
    bit:
    stack trace, usually, error message, etc.. Also, when using Try what I
    should be most worried about is the control flow disruption that an
    exception can cause--it handles that exception by catching all of them
    used
    anywhere within the Try (at least as long as the method still returns a
    Try).

    If you don't want that, Either can help and has a fighting chance of
    being
    the right type, too.

    --Rex


    On Sat, Aug 25, 2012 at 4:07 PM, Bruce Eckel <bruce...@gmail.com<javascript:>>
    wrote:
    I just discovered a difference between Either and Try, but I think
    it's a
    design error.

    Because Either is a generic disjoint union, I can put anything into
    Left:
    scala> Left("foo")
    res0: scala.util.Left[String,Nothing] = Left(foo)

    With Try, I can also put anything into Success:

    scala> import util.{Success, Failure}
    import util.{Success, Failure}

    scala> Success("Foo")
    res1: scala.util.Success[String] = Success(Foo)

    However, if I try to put anything into Failure, Scala complains:

    scala> Failure("Foo")
    <console>:9: error: type mismatch;
    found : String("Foo")
    required: Throwable
    Failure("Foo")
    ^

    So if I want to put anything into a Failure, I have to wrap it into
    something Throwable, like this:

    case class Why(reason:Any) extends Throwable
    def e = Failure(Why("ouch!"))

    I would like to present Success and Failure as the preferred way to
    report errors; that is, Either should only be used when you have two
    possible return types which are what I'll call "of equal weight,"
    where one
    does not represent an error (a previous example in this list, if I
    remember
    correctly, had a choice where you might get an Int or you might get a
    String). If you're producing a Success or reporting a Failure, you
    should
    use those types, which provide much clearer intent.

    To do this, I argue that Failure should be able to accept Any, not
    just
    Throwable. I think that would help in moving to this new
    error-handling
    approach.

    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com
  • Tony Morris at Aug 26, 2012 at 12:05 am
    That was a pretty silly thing to say. I will give you the benefit of the
    doubt and assume you haven't opened an algebra book in your life and
    invite you do so so that you can laugh at your spectacularly silly thing
    to have said.

    The Scalaz class you refer to denotes a call strategy. Although I am not
    the implementer, it exists because Scala (the language) totally screws
    up call strategies and you need these kind of gymnastics to make it usable.
    On 26/08/12 10:01, Peter Pnin wrote:
    "Success/Failure is no more meaningful than Left/Right. They are just
    names"

    You can't quite be serious. I mean, that is a spectacularly silly thing to
    say. Will give you the benefit of the doubt.

    (The most aptly named class in scalaz is surely:

    https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Name.scala)



    On Saturday, August 25, 2012 7:31:04 PM UTC-4, Richard Wallace wrote:
    On Sat, Aug 25, 2012 at 1:32 PM, Bruce Eckel <bruce...@gmail.com<javascript:>>
    wrote:
    Either is generic and doesn't telegraph the intent. Left/Right doesn't mean
    anything. Success/Failure is quite meaningful.
    Success/Failure is no more meaningful than Left/Right. They are just
    names. Using Either for a errors it is quite apparent which side is
    the error and which the success based on the type you give them. I do
    agree with others that parameterizing Try in the error type is a bad
    idea. But I'd go further and say that Try itself is actually a bad
    idea and should *never be used for anything*. After looking into it
    in detail, the implementation of flatMap, map etc have radically
    different semantics than other types that implement these methods and
    will make it much harder to reason about code.
    At some point you have to convey to the client programmer what your function
    will return and they have to adapt to that. It's part of your interface. If
    your function returns a Failure containing a Throwable, the client
    programmer has to deal with that. It's no different than if your function
    returns a Failure containing some other kind of information; the client
    programmer has to know what it is and deal with that, too.


    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com



    On Sat, Aug 25, 2012 at 2:21 PM, Rex Kerr <ich...@gmail.com<javascript:>>
    wrote:
    I disagree. We already have Either for that. The distinction should
    be
    clear:
    - If you want to catch exceptions robustly and hang on to them, use
    Try
    - If you want to do anything more elaborate or generic, use Either

    If I get a Try, I don't want to have to handle any possible untyped
    object
    that someone might have tossed in there. Throwables give you quite a
    bit:
    stack trace, usually, error message, etc.. Also, when using Try what I
    should be most worried about is the control flow disruption that an
    exception can cause--it handles that exception by catching all of them
    used
    anywhere within the Try (at least as long as the method still returns a
    Try).

    If you don't want that, Either can help and has a fighting chance of
    being
    the right type, too.

    --Rex


    On Sat, Aug 25, 2012 at 4:07 PM, Bruce Eckel <bruce...@gmail.com<javascript:>>
    wrote:
    I just discovered a difference between Either and Try, but I think
    it's a
    design error.

    Because Either is a generic disjoint union, I can put anything into
    Left:
    scala> Left("foo")
    res0: scala.util.Left[String,Nothing] = Left(foo)

    With Try, I can also put anything into Success:

    scala> import util.{Success, Failure}
    import util.{Success, Failure}

    scala> Success("Foo")
    res1: scala.util.Success[String] = Success(Foo)

    However, if I try to put anything into Failure, Scala complains:

    scala> Failure("Foo")
    <console>:9: error: type mismatch;
    found : String("Foo")
    required: Throwable
    Failure("Foo")
    ^

    So if I want to put anything into a Failure, I have to wrap it into
    something Throwable, like this:

    case class Why(reason:Any) extends Throwable
    def e = Failure(Why("ouch!"))

    I would like to present Success and Failure as the preferred way to
    report errors; that is, Either should only be used when you have two
    possible return types which are what I'll call "of equal weight,"
    where one
    does not represent an error (a previous example in this list, if I
    remember
    correctly, had a choice where you might get an Int or you might get a
    String). If you're producing a Success or reporting a Failure, you
    should
    use those types, which provide much clearer intent.

    To do this, I argue that Failure should be able to accept Any, not
    just
    Throwable. I think that would help in moving to this new
    error-handling
    approach.

    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com

    --
    Tony Morris
    http://tmorris.net/
  • Peter Pnin at Aug 26, 2012 at 1:12 am
    Are you then the author of Either3?

    https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Either3.scala

    You've chosen the names Left3, Middle3, and Right3 for the cases. Odd that
    you chose "Middle3" for the one in the middle.

    May I suggest an alternative set:

    Northwest, Right, and PoachedEgg

    Please let me know if these are sufficiently arbitrary for you and I will
    make a pull request with the changes. Wallace will no doubt wholeheartedly
    approve.


    On Saturday, August 25, 2012 8:05:36 PM UTC-4, Tony Morris wrote:

    That was a pretty silly thing to say. I will give you the benefit of the
    doubt and assume you haven't opened an algebra book in your life and
    invite you do so so that you can laugh at your spectacularly silly thing
    to have said.

    The Scalaz class you refer to denotes a call strategy. Although I am not
    the implementer, it exists because Scala (the language) totally screws
    up call strategies and you need these kind of gymnastics to make it
    usable.
    On 26/08/12 10:01, Peter Pnin wrote:
    "Success/Failure is no more meaningful than Left/Right. They are just
    names"

    You can't quite be serious. I mean, that is a spectacularly silly thing to
    say. Will give you the benefit of the doubt.

    (The most aptly named class in scalaz is surely:

    https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Name.scala)


    On Saturday, August 25, 2012 7:31:04 PM UTC-4, Richard Wallace wrote:
    On Sat, Aug 25, 2012 at 1:32 PM, Bruce Eckel <bruce...@gmail.com<javascript:>>
    wrote:
    Either is generic and doesn't telegraph the intent. Left/Right doesn't mean
    anything. Success/Failure is quite meaningful.
    Success/Failure is no more meaningful than Left/Right. They are just
    names. Using Either for a errors it is quite apparent which side is
    the error and which the success based on the type you give them. I do
    agree with others that parameterizing Try in the error type is a bad
    idea. But I'd go further and say that Try itself is actually a bad
    idea and should *never be used for anything*. After looking into it
    in detail, the implementation of flatMap, map etc have radically
    different semantics than other types that implement these methods and
    will make it much harder to reason about code.
    At some point you have to convey to the client programmer what your function
    will return and they have to adapt to that. It's part of your
    interface.
    If
    your function returns a Failure containing a Throwable, the client
    programmer has to deal with that. It's no different than if your function
    returns a Failure containing some other kind of information; the
    client
    programmer has to know what it is and deal with that, too.


    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com



    On Sat, Aug 25, 2012 at 2:21 PM, Rex Kerr <ich...@gmail.com<javascript:>>
    wrote:
    I disagree. We already have Either for that. The distinction should
    be
    clear:
    - If you want to catch exceptions robustly and hang on to them, use
    Try
    - If you want to do anything more elaborate or generic, use Either

    If I get a Try, I don't want to have to handle any possible untyped
    object
    that someone might have tossed in there. Throwables give you quite a
    bit:
    stack trace, usually, error message, etc.. Also, when using Try what
    I
    should be most worried about is the control flow disruption that an
    exception can cause--it handles that exception by catching all of
    them
    used
    anywhere within the Try (at least as long as the method still returns
    a
    Try).

    If you don't want that, Either can help and has a fighting chance of
    being
    the right type, too.

    --Rex


    On Sat, Aug 25, 2012 at 4:07 PM, Bruce Eckel <bruce...@gmail.com<javascript:>>
    wrote:
    I just discovered a difference between Either and Try, but I think
    it's a
    design error.

    Because Either is a generic disjoint union, I can put anything into
    Left:
    scala> Left("foo")
    res0: scala.util.Left[String,Nothing] = Left(foo)

    With Try, I can also put anything into Success:

    scala> import util.{Success, Failure}
    import util.{Success, Failure}

    scala> Success("Foo")
    res1: scala.util.Success[String] = Success(Foo)

    However, if I try to put anything into Failure, Scala complains:

    scala> Failure("Foo")
    <console>:9: error: type mismatch;
    found : String("Foo")
    required: Throwable
    Failure("Foo")
    ^

    So if I want to put anything into a Failure, I have to wrap it into
    something Throwable, like this:

    case class Why(reason:Any) extends Throwable
    def e = Failure(Why("ouch!"))

    I would like to present Success and Failure as the preferred way to
    report errors; that is, Either should only be used when you have two
    possible return types which are what I'll call "of equal weight,"
    where one
    does not represent an error (a previous example in this list, if I
    remember
    correctly, had a choice where you might get an Int or you might get
    a
    String). If you're producing a Success or reporting a Failure, you
    should
    use those types, which provide much clearer intent.

    To do this, I argue that Failure should be able to accept Any, not
    just
    Throwable. I think that would help in moving to this new
    error-handling
    approach.

    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com

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

  • Richard Wallace at Aug 26, 2012 at 1:36 am
    It would be rejected because it breaks backwards compability. If you'd like
    to use those in your code, feel free to create type aliases and then
    realize that nothing has changed. Would the proverbial rose smell or look
    different if it was called stinkweed?

    Names are just a short hand way of referring to something. The only
    important thing about names is that we agree on them when we are discussing
    the thing to which they refer. The labels themselves can be arbitrary as
    long as we agree on them.

    Some people will suggest that some names are more "intuitive,"
    unfortunately intuition doesn't exist. Knowledge cannot be spontaneously
    obtained, it must be acquired through a learning process.
    On Aug 25, 2012 6:12 PM, "Peter Pnin" wrote:

    Are you then the author of Either3?


    https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Either3.scala

    You've chosen the names Left3, Middle3, and Right3 for the cases. Odd that
    you chose "Middle3" for the one in the middle.

    May I suggest an alternative set:

    Northwest, Right, and PoachedEgg

    Please let me know if these are sufficiently arbitrary for you and I will
    make a pull request with the changes. Wallace will no doubt wholeheartedly
    approve.


    On Saturday, August 25, 2012 8:05:36 PM UTC-4, Tony Morris wrote:

    That was a pretty silly thing to say. I will give you the benefit of the
    doubt and assume you haven't opened an algebra book in your life and
    invite you do so so that you can laugh at your spectacularly silly thing
    to have said.

    The Scalaz class you refer to denotes a call strategy. Although I am not
    the implementer, it exists because Scala (the language) totally screws
    up call strategies and you need these kind of gymnastics to make it
    usable.
    On 26/08/12 10:01, Peter Pnin wrote:
    "Success/Failure is no more meaningful than Left/Right. They are just
    names"

    You can't quite be serious. I mean, that is a spectacularly silly thing to
    say. Will give you the benefit of the doubt.

    (The most aptly named class in scalaz is surely:

    https://github.com/scalaz/**scalaz/blob/master/core/src/**
    main/scala/scalaz/Name.scala<https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Name.scala>)


    On Saturday, August 25, 2012 7:31:04 PM UTC-4, Richard Wallace wrote:
    On Sat, Aug 25, 2012 at 1:32 PM, Bruce Eckel <bruce...@gmail.com<**javascript:>>
    wrote:
    Either is generic and doesn't telegraph the intent. Left/Right
    doesn't
    mean
    anything. Success/Failure is quite meaningful.
    Success/Failure is no more meaningful than Left/Right. They are just
    names. Using Either for a errors it is quite apparent which side is
    the error and which the success based on the type you give them. I do
    agree with others that parameterizing Try in the error type is a bad
    idea. But I'd go further and say that Try itself is actually a bad
    idea and should *never be used for anything*. After looking into it
    in detail, the implementation of flatMap, map etc have radically
    different semantics than other types that implement these methods and
    will make it much harder to reason about code.
    At some point you have to convey to the client programmer what your function
    will return and they have to adapt to that. It's part of your
    interface.
    If
    your function returns a Failure containing a Throwable, the client
    programmer has to deal with that. It's no different than if your function
    returns a Failure containing some other kind of information; the
    client
    programmer has to know what it is and deal with that, too.


    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com



    On Sat, Aug 25, 2012 at 2:21 PM, Rex Kerr <ich...@gmail.com
    <javascript:>**>
    wrote:
    I disagree. We already have Either for that. The distinction
    should
    be
    clear:
    - If you want to catch exceptions robustly and hang on to them,
    use
    Try
    - If you want to do anything more elaborate or generic, use Either

    If I get a Try, I don't want to have to handle any possible untyped
    object
    that someone might have tossed in there. Throwables give you quite
    a
    bit:
    stack trace, usually, error message, etc.. Also, when using Try
    what I
    should be most worried about is the control flow disruption that an
    exception can cause--it handles that exception by catching all of
    them
    used
    anywhere within the Try (at least as long as the method still
    returns a
    Try).

    If you don't want that, Either can help and has a fighting chance of
    being
    the right type, too.

    --Rex


    On Sat, Aug 25, 2012 at 4:07 PM, Bruce Eckel <bruce...@gmail.com<**javascript:>>
    wrote:
    I just discovered a difference between Either and Try, but I think
    it's a
    design error.

    Because Either is a generic disjoint union, I can put anything into
    Left:
    scala> Left("foo")
    res0: scala.util.Left[String,**Nothing] = Left(foo)

    With Try, I can also put anything into Success:

    scala> import util.{Success, Failure}
    import util.{Success, Failure}

    scala> Success("Foo")
    res1: scala.util.Success[String] = Success(Foo)

    However, if I try to put anything into Failure, Scala complains:

    scala> Failure("Foo")
    <console>:9: error: type mismatch;
    found : String("Foo")
    required: Throwable
    Failure("Foo")
    ^

    So if I want to put anything into a Failure, I have to wrap it into
    something Throwable, like this:

    case class Why(reason:Any) extends Throwable
    def e = Failure(Why("ouch!"))

    I would like to present Success and Failure as the preferred way to
    report errors; that is, Either should only be used when you have
    two
    possible return types which are what I'll call "of equal weight,"
    where one
    does not represent an error (a previous example in this list, if I
    remember
    correctly, had a choice where you might get an Int or you might get
    a
    String). If you're producing a Success or reporting a Failure, you
    should
    use those types, which provide much clearer intent.

    To do this, I argue that Failure should be able to accept Any, not
    just
    Throwable. I think that would help in moving to this new
    error-handling
    approach.

    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com

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

  • Peter Pnin at Aug 26, 2012 at 1:51 am
    Do not considerations of taste and algebra override a Java-like concession
    to "backwards compatibility"? We still have time before scalaz7 is
    released. I believe little production code relies on Either3 at present.

    I find it scandalous that Either3 chooses to call the one in the middle
    "Middle3". It reeks of practical programming for Java joe. Moreover, it
    reinforces the old saw that names have meaning that we've been carrying
    around for the last God knows how many years. Let us free ourselves of
    tyranny of names!

    I reiterate the nomination of "Northwest", "Braveheart", and
    "the_artist_formerly_known_as_prince" for the cases of Either3.





    On Saturday, August 25, 2012 9:36:03 PM UTC-4, Richard Wallace wrote:

    It would be rejected because it breaks backwards compability. If you'd
    like to use those in your code, feel free to create type aliases and then
    realize that nothing has changed. Would the proverbial rose smell or look
    different if it was called stinkweed?

    Names are just a short hand way of referring to something. The only
    important thing about names is that we agree on them when we are discussing
    the thing to which they refer. The labels themselves can be arbitrary as
    long as we agree on them.

    Some people will suggest that some names are more "intuitive,"
    unfortunately intuition doesn't exist. Knowledge cannot be spontaneously
    obtained, it must be acquired through a learning process.
    On Aug 25, 2012 6:12 PM, "Peter Pnin" <peter...@gmail.com <javascript:>>
    wrote:
    Are you then the author of Either3?


    https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Either3.scala

    You've chosen the names Left3, Middle3, and Right3 for the cases. Odd
    that you chose "Middle3" for the one in the middle.

    May I suggest an alternative set:

    Northwest, Right, and PoachedEgg

    Please let me know if these are sufficiently arbitrary for you and I will
    make a pull request with the changes. Wallace will no doubt wholeheartedly
    approve.


    On Saturday, August 25, 2012 8:05:36 PM UTC-4, Tony Morris wrote:

    That was a pretty silly thing to say. I will give you the benefit of the
    doubt and assume you haven't opened an algebra book in your life and
    invite you do so so that you can laugh at your spectacularly silly thing
    to have said.

    The Scalaz class you refer to denotes a call strategy. Although I am not
    the implementer, it exists because Scala (the language) totally screws
    up call strategies and you need these kind of gymnastics to make it
    usable.
    On 26/08/12 10:01, Peter Pnin wrote:
    "Success/Failure is no more meaningful than Left/Right. They are just
    names"

    You can't quite be serious. I mean, that is a spectacularly silly thing to
    say. Will give you the benefit of the doubt.

    (The most aptly named class in scalaz is surely:

    https://github.com/scalaz/**scalaz/blob/master/core/src/**
    main/scala/scalaz/Name.scala<https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Name.scala>)


    On Saturday, August 25, 2012 7:31:04 PM UTC-4, Richard Wallace wrote:
    On Sat, Aug 25, 2012 at 1:32 PM, Bruce Eckel <bruce...@gmail.com<**javascript:>>
    wrote:
    Either is generic and doesn't telegraph the intent. Left/Right
    doesn't
    mean
    anything. Success/Failure is quite meaningful.
    Success/Failure is no more meaningful than Left/Right. They are just
    names. Using Either for a errors it is quite apparent which side is
    the error and which the success based on the type you give them. I
    do
    agree with others that parameterizing Try in the error type is a bad
    idea. But I'd go further and say that Try itself is actually a bad
    idea and should *never be used for anything*. After looking into it
    in detail, the implementation of flatMap, map etc have radically
    different semantics than other types that implement these methods and
    will make it much harder to reason about code.
    At some point you have to convey to the client programmer what your function
    will return and they have to adapt to that. It's part of your
    interface.
    If
    your function returns a Failure containing a Throwable, the client
    programmer has to deal with that. It's no different than if your function
    returns a Failure containing some other kind of information; the
    client
    programmer has to know what it is and deal with that, too.


    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com



    On Sat, Aug 25, 2012 at 2:21 PM, Rex Kerr <ich...@gmail.com
    <javascript:>**>
    wrote:
    I disagree. We already have Either for that. The distinction
    should
    be
    clear:
    - If you want to catch exceptions robustly and hang on to them,
    use
    Try
    - If you want to do anything more elaborate or generic, use
    Either
    If I get a Try, I don't want to have to handle any possible untyped
    object
    that someone might have tossed in there. Throwables give you quite
    a
    bit:
    stack trace, usually, error message, etc.. Also, when using Try
    what I
    should be most worried about is the control flow disruption that an
    exception can cause--it handles that exception by catching all of
    them
    used
    anywhere within the Try (at least as long as the method still
    returns a
    Try).

    If you don't want that, Either can help and has a fighting chance
    of
    being
    the right type, too.

    --Rex


    On Sat, Aug 25, 2012 at 4:07 PM, Bruce Eckel <bruce...@gmail.com<**javascript:>>
    wrote:
    I just discovered a difference between Either and Try, but I think
    it's a
    design error.

    Because Either is a generic disjoint union, I can put anything
    into
    Left:
    scala> Left("foo")
    res0: scala.util.Left[String,**Nothing] = Left(foo)

    With Try, I can also put anything into Success:

    scala> import util.{Success, Failure}
    import util.{Success, Failure}

    scala> Success("Foo")
    res1: scala.util.Success[String] = Success(Foo)

    However, if I try to put anything into Failure, Scala complains:

    scala> Failure("Foo")
    <console>:9: error: type mismatch;
    found : String("Foo")
    required: Throwable
    Failure("Foo")
    ^

    So if I want to put anything into a Failure, I have to wrap it
    into
    something Throwable, like this:

    case class Why(reason:Any) extends Throwable
    def e = Failure(Why("ouch!"))

    I would like to present Success and Failure as the preferred way
    to
    report errors; that is, Either should only be used when you have
    two
    possible return types which are what I'll call "of equal weight,"
    where one
    does not represent an error (a previous example in this list, if I
    remember
    correctly, had a choice where you might get an Int or you might
    get a
    String). If you're producing a Success or reporting a Failure, you
    should
    use those types, which provide much clearer intent.

    To do this, I argue that Failure should be able to accept Any, not
    just
    Throwable. I think that would help in moving to this new
    error-handling
    approach.

    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com

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

  • Richard Wallace at Aug 26, 2012 at 2:03 am
    Ah, sarcasm, the lowest form of communication. You have convinced me, sir.
    Submit your pull request and I will merge it forthwith.
    On Aug 25, 2012 6:51 PM, "Peter Pnin" wrote:

    Do not considerations of taste and algebra override a Java-like concession
    to "backwards compatibility"? We still have time before scalaz7 is
    released. I believe little production code relies on Either3 at present.

    I find it scandalous that Either3 chooses to call the one in the middle
    "Middle3". It reeks of practical programming for Java joe. Moreover, it
    reinforces the old saw that names have meaning that we've been carrying
    around for the last God knows how many years. Let us free ourselves of
    tyranny of names!

    I reiterate the nomination of "Northwest", "Braveheart", and
    "the_artist_formerly_known_as_prince" for the cases of Either3.





    On Saturday, August 25, 2012 9:36:03 PM UTC-4, Richard Wallace wrote:

    It would be rejected because it breaks backwards compability. If you'd
    like to use those in your code, feel free to create type aliases and then
    realize that nothing has changed. Would the proverbial rose smell or look
    different if it was called stinkweed?

    Names are just a short hand way of referring to something. The only
    important thing about names is that we agree on them when we are discussing
    the thing to which they refer. The labels themselves can be arbitrary as
    long as we agree on them.

    Some people will suggest that some names are more "intuitive,"
    unfortunately intuition doesn't exist. Knowledge cannot be spontaneously
    obtained, it must be acquired through a learning process.
    On Aug 25, 2012 6:12 PM, "Peter Pnin" wrote:

    Are you then the author of Either3?

    https://github.com/scalaz/**scalaz/blob/scalaz-seven/core/**
    src/main/scala/scalaz/Either3.**scala<https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Either3.scala>

    You've chosen the names Left3, Middle3, and Right3 for the cases. Odd
    that you chose "Middle3" for the one in the middle.

    May I suggest an alternative set:

    Northwest, Right, and PoachedEgg

    Please let me know if these are sufficiently arbitrary for you and I
    will make a pull request with the changes. Wallace will no doubt
    wholeheartedly approve.


    On Saturday, August 25, 2012 8:05:36 PM UTC-4, Tony Morris wrote:

    That was a pretty silly thing to say. I will give you the benefit of
    the
    doubt and assume you haven't opened an algebra book in your life and
    invite you do so so that you can laugh at your spectacularly silly
    thing
    to have said.

    The Scalaz class you refer to denotes a call strategy. Although I am
    not
    the implementer, it exists because Scala (the language) totally screws
    up call strategies and you need these kind of gymnastics to make it
    usable.
    On 26/08/12 10:01, Peter Pnin wrote:
    "Success/Failure is no more meaningful than Left/Right. They are just
    names"

    You can't quite be serious. I mean, that is a spectacularly silly thing to
    say. Will give you the benefit of the doubt.

    (The most aptly named class in scalaz is surely:

    https://github.com/scalaz/**scal**az/blob/master/core/src/**main/**
    scala/scalaz/Name.scala<https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Name.scala>)


    On Saturday, August 25, 2012 7:31:04 PM UTC-4, Richard Wallace wrote:
    On Sat, Aug 25, 2012 at 1:32 PM, Bruce Eckel <bruce...@gmail.com<**
    javascript**:>>
    wrote:
    Either is generic and doesn't telegraph the intent. Left/Right
    doesn't
    mean
    anything. Success/Failure is quite meaningful.
    Success/Failure is no more meaningful than Left/Right. They are
    just
    names. Using Either for a errors it is quite apparent which side is
    the error and which the success based on the type you give them. I
    do
    agree with others that parameterizing Try in the error type is a bad
    idea. But I'd go further and say that Try itself is actually a bad
    idea and should *never be used for anything*. After looking into it
    in detail, the implementation of flatMap, map etc have radically
    different semantics than other types that implement these methods
    and
    will make it much harder to reason about code.
    At some point you have to convey to the client programmer what your function
    will return and they have to adapt to that. It's part of your
    interface.
    If
    your function returns a Failure containing a Throwable, the client
    programmer has to deal with that. It's no different than if your function
    returns a Failure containing some other kind of information; the
    client
    programmer has to know what it is and deal with that, too.


    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com



    On Sat, Aug 25, 2012 at 2:21 PM, Rex Kerr <ich...@gmail.com
    <javascript:>****>
    wrote:
    I disagree. We already have Either for that. The distinction
    should
    be
    clear:
    - If you want to catch exceptions robustly and hang on to them,
    use
    Try
    - If you want to do anything more elaborate or generic, use
    Either
    If I get a Try, I don't want to have to handle any possible
    untyped
    object
    that someone might have tossed in there. Throwables give you
    quite a
    bit:
    stack trace, usually, error message, etc.. Also, when using Try
    what I
    should be most worried about is the control flow disruption that
    an
    exception can cause--it handles that exception by catching all of
    them
    used
    anywhere within the Try (at least as long as the method still
    returns a
    Try).

    If you don't want that, Either can help and has a fighting chance
    of
    being
    the right type, too.

    --Rex


    On Sat, Aug 25, 2012 at 4:07 PM, Bruce Eckel <bruce...@gmail.com<*
    *javascript**:>>
    wrote:
    I just discovered a difference between Either and Try, but I
    think
    it's a
    design error.

    Because Either is a generic disjoint union, I can put anything
    into
    Left:
    scala> Left("foo")
    res0: scala.util.Left[String,**Nothing**] = Left(foo)

    With Try, I can also put anything into Success:

    scala> import util.{Success, Failure}
    import util.{Success, Failure}

    scala> Success("Foo")
    res1: scala.util.Success[String] = Success(Foo)

    However, if I try to put anything into Failure, Scala complains:

    scala> Failure("Foo")
    <console>:9: error: type mismatch;
    found : String("Foo")
    required: Throwable
    Failure("Foo")
    ^

    So if I want to put anything into a Failure, I have to wrap it
    into
    something Throwable, like this:

    case class Why(reason:Any) extends Throwable
    def e = Failure(Why("ouch!"))

    I would like to present Success and Failure as the preferred way
    to
    report errors; that is, Either should only be used when you have
    two
    possible return types which are what I'll call "of equal weight,"
    where one
    does not represent an error (a previous example in this list, if
    I
    remember
    correctly, had a choice where you might get an Int or you might
    get a
    String). If you're producing a Success or reporting a Failure,
    you
    should
    use those types, which provide much clearer intent.

    To do this, I argue that Failure should be able to accept Any,
    not
    just
    Throwable. I think that would help in moving to this new
    error-handling
    approach.

    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com

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

  • Rex Kerr at Aug 26, 2012 at 7:13 pm

    On Sat, Aug 25, 2012 at 9:36 PM, Richard Wallace wrote:

    Names are just a short hand way of referring to something. The only
    important thing about names is that we agree on them when we are discussing
    the thing to which they refer. The labels themselves can be arbitrary as
    long as we agree on them.

    Some people will suggest that some names are more "intuitive,"
    unfortunately intuition doesn't exist. Knowledge cannot be spontaneously
    obtained, it must be acquired through a learning process.
    "Success/Failure is no more meaningful than Left/Right. They are just
    names"
    This is nonsense. We have _already agreed on what success and failure
    mean_ by virtue of learning English. Yes, you have to learn that we're
    going to use these already-agreed upon terms in a new way, but it's a lot
    less to learn and less to agree on than using other words without such
    agreement--like Mottled for success and Capybara for failure--and less
    still than to learn and agree upon nonsense terms like Hapiculated and
    Varnary (which are themselves easier to learn than something that doesn't
    even have agreed-upon syllable structure, like AF1f3j1P and Uqfjb1$$$$.)

    English has a ready supply of paired terms to denote that which we wish to
    convey here:
    success/failure
    correct/wrong
    right/wrong
    proper/improper

    And a bunch of others that could be easily co-opted:
    yes/no
    win/lose
    up/down
    returned/thrown // Do I win an obviousness prize?
    healthy/injured
    happy/sad
    ...

    Hm, I like that last one.

    trait Moody[+A]
    case class Happy[+A](joy: A) extends Moody[A]
    case class Sad[+A](trauma: Throwable) extends Moody[A]

    Anyway, when starting from scratch with infants with no language exposure,
    you have dramatically fewer restrictions on what makes a good name. Since
    we are not in that situation, names matter.

    Programming is not *just* algebra; it's algebra used to accomplish
    something. Physics also uses algebra to accomplish something, and
    variables are generally chosen with adequate care. (Radii are r,
    accelerations are a, etc.)

    It is essential to not let names fool you about the underlying logical
    structure. This does not mean that one cannot use them to transmit useful
    information (including as a way to remind you of what the underlying
    structure is or what its intended use is).

    --Rex
  • Roland Kuhn at Aug 26, 2012 at 7:13 pm
    Amen. I’m deeply thankful that you took the time to write down the obvious, and for the physics reference.

    Regards,

    Roland

    26 aug 2012 kl. 21:06 skrev Rex Kerr:
    On Sat, Aug 25, 2012 at 9:36 PM, Richard Wallace wrote:
    Names are just a short hand way of referring to something. The only important thing about names is that we agree on them when we are discussing the thing to which they refer. The labels themselves can be arbitrary as long as we agree on them.
    Some people will suggest that some names are more "intuitive," unfortunately intuition doesn't exist. Knowledge cannot be spontaneously obtained, it must be acquired through a learning process.
    "Success/Failure is no more meaningful than Left/Right. They are just
    names"
    This is nonsense. We have _already agreed on what success and failure mean_ by virtue of learning English. Yes, you have to learn that we're going to use these already-agreed upon terms in a new way, but it's a lot less to learn and less to agree on than using other words without such agreement--like Mottled for success and Capybara for failure--and less still than to learn and agree upon nonsense terms like Hapiculated and Varnary (which are themselves easier to learn than something that doesn't even have agreed-upon syllable structure, like AF1f3j1P and Uqfjb1$$$$.)

    English has a ready supply of paired terms to denote that which we wish to convey here:
    success/failure
    correct/wrong
    right/wrong
    proper/improper

    And a bunch of others that could be easily co-opted:
    yes/no
    win/lose
    up/down
    returned/thrown // Do I win an obviousness prize?
    healthy/injured
    happy/sad
    ...

    Hm, I like that last one.

    trait Moody[+A]
    case class Happy[+A](joy: A) extends Moody[A]
    case class Sad[+A](trauma: Throwable) extends Moody[A]

    Anyway, when starting from scratch with infants with no language exposure, you have dramatically fewer restrictions on what makes a good name. Since we are not in that situation, names matter.

    Programming is not *just* algebra; it's algebra used to accomplish something. Physics also uses algebra to accomplish something, and variables are generally chosen with adequate care. (Radii are r, accelerations are a, etc.)

    It is essential to not let names fool you about the underlying logical structure. This does not mean that one cannot use them to transmit useful information (including as a way to remind you of what the underlying structure is or what its intended use is).

    --Rex
    Roland Kuhn
    Typesafe – The software stack for applications that scale.
    twitter: @rolandkuhn
  • Russ Paielli at Aug 26, 2012 at 7:47 pm
    These functional guys are obviously very smart, but they seem to have a
    habit of making bizarre statements. "The labels can be arbitrary as long as
    we agree on them"? So we might just as well use "sd7tq" for success and
    "sd7tg" for failure? If we were talking about communication with machines
    only, that might be true, but as we all know (or should know), source code
    is supposed to be understandable by humans as well as compilers.

    The other bizarre statement here is "unfortunately intuition doesn't
    exist." Oh, really? What in the world could possibly make a person say
    that? If I recall correctly, this isn't the first time I've heard this
    notion expressed by a functional programmer. I will agree that intuition
    does not exist inside a computer (barring some exotic AI machine), but to
    simple assert that it does not exist in general is just plain bizarre.

    In fact, the way humans learn is primarily intuitive. That's why we need
    examples -- many examples. We tend to go from specific examples to general
    concepts rather than the other way around. If that were not so, textbooks
    on programming would not need any examples. A language reference manual
    would be all any programmer would need. Show me a programming instructor
    that does not give examples, and I'll show you a lousy instructor.

    --Russ P.

    On Sun, Aug 26, 2012 at 12:06 PM, Rex Kerr wrote:

    On Sat, Aug 25, 2012 at 9:36 PM, Richard Wallace <
    rwallace@thewallacepack.net> wrote:
    Names are just a short hand way of referring to something. The only
    important thing about names is that we agree on them when we are discussing
    the thing to which they refer. The labels themselves can be arbitrary as
    long as we agree on them.

    Some people will suggest that some names are more "intuitive,"
    unfortunately intuition doesn't exist. Knowledge cannot be spontaneously
    obtained, it must be acquired through a learning process.
    "Success/Failure is no more meaningful than Left/Right. They are just
    names"
    This is nonsense. We have _already agreed on what success and failure
    mean_ by virtue of learning English. Yes, you have to learn that we're
    going to use these already-agreed upon terms in a new way, but it's a lot
    less to learn and less to agree on than using other words without such
    agreement--like Mottled for success and Capybara for failure--and less
    still than to learn and agree upon nonsense terms like Hapiculated and
    Varnary (which are themselves easier to learn than something that doesn't
    even have agreed-upon syllable structure, like AF1f3j1P and Uqfjb1$$$$.)

    English has a ready supply of paired terms to denote that which we wish to
    convey here:
    success/failure
    correct/wrong
    right/wrong
    proper/improper

    And a bunch of others that could be easily co-opted:
    yes/no
    win/lose
    up/down
    returned/thrown // Do I win an obviousness prize?
    healthy/injured
    happy/sad
    ...

    Hm, I like that last one.

    trait Moody[+A]
    case class Happy[+A](joy: A) extends Moody[A]
    case class Sad[+A](trauma: Throwable) extends Moody[A]

    Anyway, when starting from scratch with infants with no language exposure,
    you have dramatically fewer restrictions on what makes a good name. Since
    we are not in that situation, names matter.

    Programming is not *just* algebra; it's algebra used to accomplish
    something. Physics also uses algebra to accomplish something, and
    variables are generally chosen with adequate care. (Radii are r,
    accelerations are a, etc.)

    It is essential to not let names fool you about the underlying logical
    structure. This does not mean that one cannot use them to transmit useful
    information (including as a way to remind you of what the underlying
    structure is or what its intended use is).

    --Rex

    --
    http://RussP.us
  • ARKBAN at Aug 26, 2012 at 8:59 pm
    Since Scala supports Unicode, perhaps the following alternatives would
    be more readable /and/ more algebraic-like (using only a single
    character), satisfying both camps:

    * Either.Right becomes ?
    * Either.Left becomes ?
    * Either.Middle (which appears to the contentious operator) becomes ?

    At work (where we use Scala as our primary language), there is a
    challenge to figure out the best place to use ?_? as a method or class.
    My vote is for a custom exception, so we can write:
    throw new ?_? "your code is bad, and you should feel bad"

    ARKBAN

    On 08/26/2012 03:47 PM, Russ Paielli wrote:
    These functional guys are obviously very smart, but they seem to have
    a habit of making bizarre statements. "The labels can be arbitrary as
    long as we agree on them"? So we might just as well use "sd7tq" for
    success and "sd7tg" for failure? If we were talking about
    communication with machines only, that might be true, but as we all
    know (or should know), source code is supposed to be understandable by
    humans as well as compilers.

    The other bizarre statement here is "unfortunately intuition doesn't
    exist." Oh, really? What in the world could possibly make a person say
    that? If I recall correctly, this isn't the first time I've heard this
    notion expressed by a functional programmer. I will agree that
    intuition does not exist inside a computer (barring some exotic AI
    machine), but to simple assert that it does not exist in general is
    just plain bizarre.

    In fact, the way humans learn is primarily intuitive. That's why we
    need examples -- many examples. We tend to go from specific examples
    to general concepts rather than the other way around. If that were not
    so, textbooks on programming would not need any examples. A language
    reference manual would be all any programmer would need. Show me a
    programming instructor that does not give examples, and I'll show you
    a lousy instructor.

    --Russ P.


    On Sun, Aug 26, 2012 at 12:06 PM, Rex Kerr wrote:

    On Sat, Aug 25, 2012 at 9:36 PM, Richard Wallace
    wrote:

    Names are just a short hand way of referring to something. The
    only important thing about names is that we agree on them when
    we are discussing the thing to which they refer. The labels
    themselves can be arbitrary as long as we agree on them.

    Some people will suggest that some names are more "intuitive,"
    unfortunately intuition doesn't exist. Knowledge cannot be
    spontaneously obtained, it must be acquired through a learning
    process.
    "Success/Failure is no more meaningful than
    Left/Right. They are just
    names"

    This is nonsense. We have _already agreed on what success and
    failure mean_ by virtue of learning English. Yes, you have to
    learn that we're going to use these already-agreed upon terms in a
    new way, but it's a lot less to learn and less to agree on than
    using other words without such agreement--like Mottled for success
    and Capybara for failure--and less still than to learn and agree
    upon nonsense terms like Hapiculated and Varnary (which are
    themselves easier to learn than something that doesn't even have
    agreed-upon syllable structure, like AF1f3j1P and Uqfjb1$$$$.)

    English has a ready supply of paired terms to denote that which we
    wish to convey here:
    success/failure
    correct/wrong
    right/wrong
    proper/improper

    And a bunch of others that could be easily co-opted:
    yes/no
    win/lose
    up/down
    returned/thrown // Do I win an obviousness prize?
    healthy/injured
    happy/sad
    ...

    Hm, I like that last one.

    trait Moody[+A]
    case class Happy[+A](joy: A) extends Moody[A]
    case class Sad[+A](trauma: Throwable) extends Moody[A]

    Anyway, when starting from scratch with infants with no language
    exposure, you have dramatically fewer restrictions on what makes a
    good name. Since we are not in that situation, names matter.

    Programming is not *just* algebra; it's algebra used to accomplish
    something. Physics also uses algebra to accomplish something, and
    variables are generally chosen with adequate care. (Radii are r,
    accelerations are a, etc.)

    It is essential to not let names fool you about the underlying
    logical structure. This does not mean that one cannot use them to
    transmit useful information (including as a way to remind you of
    what the underlying structure is or what its intended use is).

    --Rex




    --
    http://RussP.us
  • HamsterofDeath at Aug 26, 2012 at 9:13 pm

    Am 26.08.2012 22:59, schrieb ARKBAN:
    Since Scala supports Unicode, perhaps the following alternatives would
    be more readable /and/ more algebraic-like (using only a single
    character), satisfying both camps:

    * Either.Right becomes ?
    * Either.Left becomes ?
    * Either.Middle (which appears to the contentious operator) becomes ?
    but you still don't know if left or right is the better one.
    At work (where we use Scala as our primary language), there is a
    challenge to figure out the best place to use ?_? as a method or
    class. My vote is for a custom exception, so we can write:
    throw new ?_? "your code is bad, and you should feel bad"
    scrap the throw new, the smiley itself should be a method that throws
    the exception. and by the looks of it, it seems pretty equivalent to my
    "ThisShouldNeverHappenException" that i introduced in a java project. i
    used it everywhere where something occured that was .... not supposed
    to. illegal argument, illegal state, all that stuff.
    ARKBAN

    On 08/26/2012 03:47 PM, Russ Paielli wrote:
    These functional guys are obviously very smart, but they seem to have
    a habit of making bizarre statements. "The labels can be arbitrary as
    long as we agree on them"? So we might just as well use "sd7tq" for
    success and "sd7tg" for failure? If we were talking about
    communication with machines only, that might be true, but as we all
    know (or should know), source code is supposed to be understandable
    by humans as well as compilers.

    The other bizarre statement here is "unfortunately intuition doesn't
    exist." Oh, really? What in the world could possibly make a person
    say that? If I recall correctly, this isn't the first time I've heard
    this notion expressed by a functional programmer. I will agree that
    intuition does not exist inside a computer (barring some exotic AI
    machine), but to simple assert that it does not exist in general is
    just plain bizarre.

    In fact, the way humans learn is primarily intuitive. That's why we
    need examples -- many examples. We tend to go from specific examples
    to general concepts rather than the other way around. If that were
    not so, textbooks on programming would not need any examples. A
    language reference manual would be all any programmer would need.
    Show me a programming instructor that does not give examples, and
    I'll show you a lousy instructor.

    --Russ P.


    On Sun, Aug 26, 2012 at 12:06 PM, Rex Kerr <ichoran@gmail.com
    wrote:

    On Sat, Aug 25, 2012 at 9:36 PM, Richard Wallace
    <rwallace@thewallacepack.net
    wrote:

    Names are just a short hand way of referring to something.
    The only important thing about names is that we agree on them
    when we are discussing the thing to which they refer. The
    labels themselves can be arbitrary as long as we agree on them.

    Some people will suggest that some names are more
    "intuitive," unfortunately intuition doesn't exist. Knowledge
    cannot be spontaneously obtained, it must be acquired through
    a learning process.
    "Success/Failure is no more meaningful than
    Left/Right. They are just
    names"

    This is nonsense. We have _already agreed on what success and
    failure mean_ by virtue of learning English. Yes, you have to
    learn that we're going to use these already-agreed upon terms in
    a new way, but it's a lot less to learn and less to agree on than
    using other words without such agreement--like Mottled for
    success and Capybara for failure--and less still than to learn
    and agree upon nonsense terms like Hapiculated and Varnary (which
    are themselves easier to learn than something that doesn't even
    have agreed-upon syllable structure, like AF1f3j1P and Uqfjb1$$$$.)

    English has a ready supply of paired terms to denote that which
    we wish to convey here:
    success/failure
    correct/wrong
    right/wrong
    proper/improper

    And a bunch of others that could be easily co-opted:
    yes/no
    win/lose
    up/down
    returned/thrown // Do I win an obviousness prize?
    healthy/injured
    happy/sad
    ...

    Hm, I like that last one.

    trait Moody[+A]
    case class Happy[+A](joy: A) extends Moody[A]
    case class Sad[+A](trauma: Throwable) extends Moody[A]

    Anyway, when starting from scratch with infants with no language
    exposure, you have dramatically fewer restrictions on what makes
    a good name. Since we are not in that situation, names matter.

    Programming is not *just* algebra; it's algebra used to
    accomplish something. Physics also uses algebra to accomplish
    something, and variables are generally chosen with adequate
    care. (Radii are r, accelerations are a, etc.)

    It is essential to not let names fool you about the underlying
    logical structure. This does not mean that one cannot use them
    to transmit useful information (including as a way to remind you
    of what the underlying structure is or what its intended use is).

    --Rex




    --
    http://RussP.us
  • ARKBAN at Aug 26, 2012 at 10:35 pm

    scrap the throw new, the smiley itself should be a method that
    throws the exception
    /*This*, /this is why I subscribe to the Scala debate mailing list.
    Because sometimes a nugget of excellence appears amid the various
    fascinating discussions that appear here, such as the most recent claim
    that since the invention of algebra words are nothing more than a
    "series of letters", just like the Internet is a "series of tubes".

    HamsterofDeath, thank you, kind sir. I award you one Internet, and will
    be sure to mention your name with the Internet Elders.

    ARKBAN
    On 08/26/2012 05:13 PM, HamsterofDeath wrote:


    Am 26.08.2012 22:59, schrieb ARKBAN:
    Since Scala supports Unicode, perhaps the following alternatives
    would be more readable /and/ more algebraic-like (using only a single
    character), satisfying both camps:

    * Either.Right becomes ?
    * Either.Left becomes ?
    * Either.Middle (which appears to the contentious operator) becomes ?
    but you still don't know if left or right is the better one.
    At work (where we use Scala as our primary language), there is a
    challenge to figure out the best place to use ?_? as a method or
    class. My vote is for a custom exception, so we can write:
    throw new ?_? "your code is bad, and you should feel bad"
    scrap the throw new, the smiley itself should be a method that throws
    the exception. and by the looks of it, it seems pretty equivalent to
    my "ThisShouldNeverHappenException" that i introduced in a java
    project. i used it everywhere where something occured that was ....
    not supposed to. illegal argument, illegal state, all that stuff.
    ARKBAN

    On 08/26/2012 03:47 PM, Russ Paielli wrote:
    These functional guys are obviously very smart, but they seem to
    have a habit of making bizarre statements. "The labels can be
    arbitrary as long as we agree on them"? So we might just as well use
    "sd7tq" for success and "sd7tg" for failure? If we were talking
    about communication with machines only, that might be true, but as
    we all know (or should know), source code is supposed to be
    understandable by humans as well as compilers.

    The other bizarre statement here is "unfortunately intuition doesn't
    exist." Oh, really? What in the world could possibly make a person
    say that? If I recall correctly, this isn't the first time I've
    heard this notion expressed by a functional programmer. I will agree
    that intuition does not exist inside a computer (barring some exotic
    AI machine), but to simple assert that it does not exist in general
    is just plain bizarre.

    In fact, the way humans learn is primarily intuitive. That's why we
    need examples -- many examples. We tend to go from specific examples
    to general concepts rather than the other way around. If that were
    not so, textbooks on programming would not need any examples. A
    language reference manual would be all any programmer would need.
    Show me a programming instructor that does not give examples, and
    I'll show you a lousy instructor.

    --Russ P.


    On Sun, Aug 26, 2012 at 12:06 PM, Rex Kerr <ichoran@gmail.com
    wrote:

    On Sat, Aug 25, 2012 at 9:36 PM, Richard Wallace
    <rwallace@thewallacepack.net
    wrote:

    Names are just a short hand way of referring to something.
    The only important thing about names is that we agree on
    them when we are discussing the thing to which they refer.
    The labels themselves can be arbitrary as long as we agree
    on them.

    Some people will suggest that some names are more
    "intuitive," unfortunately intuition doesn't exist.
    Knowledge cannot be spontaneously obtained, it must be
    acquired through a learning process.
    "Success/Failure is no more meaningful than
    Left/Right. They are just
    names"

    This is nonsense. We have _already agreed on what success and
    failure mean_ by virtue of learning English. Yes, you have to
    learn that we're going to use these already-agreed upon terms in
    a new way, but it's a lot less to learn and less to agree on
    than using other words without such agreement--like Mottled for
    success and Capybara for failure--and less still than to learn
    and agree upon nonsense terms like Hapiculated and Varnary
    (which are themselves easier to learn than something that
    doesn't even have agreed-upon syllable structure, like AF1f3j1P
    and Uqfjb1$$$$.)

    English has a ready supply of paired terms to denote that which
    we wish to convey here:
    success/failure
    correct/wrong
    right/wrong
    proper/improper

    And a bunch of others that could be easily co-opted:
    yes/no
    win/lose
    up/down
    returned/thrown // Do I win an obviousness prize?
    healthy/injured
    happy/sad
    ...

    Hm, I like that last one.

    trait Moody[+A]
    case class Happy[+A](joy: A) extends Moody[A]
    case class Sad[+A](trauma: Throwable) extends Moody[A]

    Anyway, when starting from scratch with infants with no language
    exposure, you have dramatically fewer restrictions on what makes
    a good name. Since we are not in that situation, names matter.

    Programming is not *just* algebra; it's algebra used to
    accomplish something. Physics also uses algebra to accomplish
    something, and variables are generally chosen with adequate
    care. (Radii are r, accelerations are a, etc.)

    It is essential to not let names fool you about the underlying
    logical structure. This does not mean that one cannot use them
    to transmit useful information (including as a way to remind you
    of what the underlying structure is or what its intended use is).

    --Rex




    --
    http://RussP.us
  • HamsterofDeath at Aug 27, 2012 at 4:31 pm
    there's more where that came from. want to hire me? :)

    Am 27.08.2012 00:35, schrieb ARKBAN:
    scrap the throw new, the smiley itself should be a method that
    throws the exception
    /*This*, /this is why I subscribe to the Scala debate mailing list.
    Because sometimes a nugget of excellence appears amid the various
    fascinating discussions that appear here, such as the most recent
    claim that since the invention of algebra words are nothing more than
    a "series of letters", just like the Internet is a "series of tubes".

    HamsterofDeath, thank you, kind sir. I award you one Internet, and
    will be sure to mention your name with the Internet Elders.

    ARKBAN
    On 08/26/2012 05:13 PM, HamsterofDeath wrote:


    Am 26.08.2012 22:59, schrieb ARKBAN:
    Since Scala supports Unicode, perhaps the following alternatives
    would be more readable /and/ more algebraic-like (using only a
    single character), satisfying both camps:

    * Either.Right becomes ?
    * Either.Left becomes ?
    * Either.Middle (which appears to the contentious operator) becomes ?
    but you still don't know if left or right is the better one.
    At work (where we use Scala as our primary language), there is a
    challenge to figure out the best place to use ?_? as a method or
    class. My vote is for a custom exception, so we can write:
    throw new ?_? "your code is bad, and you should feel bad"
    scrap the throw new, the smiley itself should be a method that throws
    the exception. and by the looks of it, it seems pretty equivalent to
    my "ThisShouldNeverHappenException" that i introduced in a java
    project. i used it everywhere where something occured that was ....
    not supposed to. illegal argument, illegal state, all that stuff.
    ARKBAN

    On 08/26/2012 03:47 PM, Russ Paielli wrote:
    These functional guys are obviously very smart, but they seem to
    have a habit of making bizarre statements. "The labels can be
    arbitrary as long as we agree on them"? So we might just as well
    use "sd7tq" for success and "sd7tg" for failure? If we were talking
    about communication with machines only, that might be true, but as
    we all know (or should know), source code is supposed to be
    understandable by humans as well as compilers.

    The other bizarre statement here is "unfortunately intuition
    doesn't exist." Oh, really? What in the world could possibly make a
    person say that? If I recall correctly, this isn't the first time
    I've heard this notion expressed by a functional programmer. I will
    agree that intuition does not exist inside a computer (barring some
    exotic AI machine), but to simple assert that it does not exist in
    general is just plain bizarre.

    In fact, the way humans learn is primarily intuitive. That's why we
    need examples -- many examples. We tend to go from specific
    examples to general concepts rather than the other way around. If
    that were not so, textbooks on programming would not need any
    examples. A language reference manual would be all any programmer
    would need. Show me a programming instructor that does not give
    examples, and I'll show you a lousy instructor.

    --Russ P.


    On Sun, Aug 26, 2012 at 12:06 PM, Rex Kerr <ichoran@gmail.com
    wrote:

    On Sat, Aug 25, 2012 at 9:36 PM, Richard Wallace
    <rwallace@thewallacepack.net
    wrote:

    Names are just a short hand way of referring to something.
    The only important thing about names is that we agree on
    them when we are discussing the thing to which they refer.
    The labels themselves can be arbitrary as long as we agree
    on them.

    Some people will suggest that some names are more
    "intuitive," unfortunately intuition doesn't exist.
    Knowledge cannot be spontaneously obtained, it must be
    acquired through a learning process.
    "Success/Failure is no more meaningful than
    Left/Right. They are just
    names"

    This is nonsense. We have _already agreed on what success and
    failure mean_ by virtue of learning English. Yes, you have to
    learn that we're going to use these already-agreed upon terms
    in a new way, but it's a lot less to learn and less to agree on
    than using other words without such agreement--like Mottled for
    success and Capybara for failure--and less still than to learn
    and agree upon nonsense terms like Hapiculated and Varnary
    (which are themselves easier to learn than something that
    doesn't even have agreed-upon syllable structure, like AF1f3j1P
    and Uqfjb1$$$$.)

    English has a ready supply of paired terms to denote that which
    we wish to convey here:
    success/failure
    correct/wrong
    right/wrong
    proper/improper

    And a bunch of others that could be easily co-opted:
    yes/no
    win/lose
    up/down
    returned/thrown // Do I win an obviousness prize?
    healthy/injured
    happy/sad
    ...

    Hm, I like that last one.

    trait Moody[+A]
    case class Happy[+A](joy: A) extends Moody[A]
    case class Sad[+A](trauma: Throwable) extends Moody[A]

    Anyway, when starting from scratch with infants with no
    language exposure, you have dramatically fewer restrictions on
    what makes a good name. Since we are not in that situation,
    names matter.

    Programming is not *just* algebra; it's algebra used to
    accomplish something. Physics also uses algebra to accomplish
    something, and variables are generally chosen with adequate
    care. (Radii are r, accelerations are a, etc.)

    It is essential to not let names fool you about the underlying
    logical structure. This does not mean that one cannot use them
    to transmit useful information (including as a way to remind
    you of what the underlying structure is or what its intended
    use is).

    --Rex




    --
    http://RussP.us
  • Naftoli Gugenheim at Aug 26, 2012 at 9:33 pm

    On Sat, Aug 25, 2012 at 9:36 PM, Richard Wallace wrote:

    unfortunately intuition doesn't exist. Knowledge cannot be spontaneously
    obtained, it must be acquired through a learning process.

    I think there area few logical problems with the above quote. Note that the
    following is not meant to be an expression of a differing opinion, but
    rather of the contradictions inherent in the above.

    You assert that intuition doesn't exist. You also assert that knowledge
    cannot be spontaneously obtained. Do you know those to be true? If so, do
    you know that intuitively? Or because you learned it? If so, how did you
    come to learn it? Does that mean someone taught it to you (claimed it to
    you)? Or did you come across a proof that refuted the possibility of there
    being intuition, or of there being spontaneous knowledge? Note that the
    last question is recursive; if it was taught to you then your teacher must
    have a source, and if it was proved, then the proof was based on other
    premises which must be known. So according to you, where does knowledge
    start?
    Furthermore, in general it is not possible to "know" that something "does
    not exist." For instance, if someone claims to know that the platypus does
    not exist, that implies that he knows every thing that exists, and the
    platypus is not one of them. However it is impossible to know everything
    that exists. Certainly, if the only source of knowledge is "learning"
    (apparently to the exclusion of intuition), then we can say that it is only
    possible to know about the existence of that which is "learnable." So by
    your own admission it is not possible to know of everything that exists,
    since existence does not imply learnability. Thus your own words imply that
    one cannot know that intuition does not exist.
    Of course if intuition does exist, then it's possible to know that it does
    exist.

    Also, the implicit premise of your statement is that intuition is a
    (imaginary) source of knowledge, since your refutation is your assertion
    that knowledge cannot be spontaneously obtained. No one claimed that
    though. Saying that intuition exists doesn't mean that it is a source of
    knowledge. Even if it were not a [potential] source of [accurate]
    knowledge, it still may affect the thought process, and therefore must
    still be taken into account.
  • Peter Pnin at Aug 26, 2012 at 10:00 pm
    Indeed, it's more fatuous nonsense from the school of pomposity.

    Deductive knowledge req
    On Sun, Aug 26, 2012 at 5:33 PM, Naftoli Gugenheim wrote:

    On Sat, Aug 25, 2012 at 9:36 PM, Richard Wallace <
    rwallace@thewallacepack.net> wrote:
    unfortunately intuition doesn't exist. Knowledge cannot be spontaneously
    obtained, it must be acquired through a learning process.

    I think there area few logical problems with the above quote. Note that
    the following is not meant to be an expression of a differing opinion, but
    rather of the contradictions inherent in the above.

    You assert that intuition doesn't exist. You also assert that knowledge
    cannot be spontaneously obtained. Do you know those to be true? If so, do
    you know that intuitively? Or because you learned it? If so, how did you
    come to learn it? Does that mean someone taught it to you (claimed it to
    you)? Or did you come across a proof that refuted the possibility of there
    being intuition, or of there being spontaneous knowledge? Note that the
    last question is recursive; if it was taught to you then your teacher must
    have a source, and if it was proved, then the proof was based on other
    premises which must be known. So according to you, where does knowledge
    start?
    Furthermore, in general it is not possible to "know" that something "does
    not exist." For instance, if someone claims to know that the platypus does
    not exist, that implies that he knows every thing that exists, and the
    platypus is not one of them. However it is impossible to know everything
    that exists. Certainly, if the only source of knowledge is "learning"
    (apparently to the exclusion of intuition), then we can say that it is only
    possible to know about the existence of that which is "learnable." So by
    your own admission it is not possible to know of everything that exists,
    since existence does not imply learnability. Thus your own words imply that
    one cannot know that intuition does not exist.
    Of course if intuition does exist, then it's possible to know that it does
    exist.

    Also, the implicit premise of your statement is that intuition is a
    (imaginary) source of knowledge, since your refutation is your assertion
    that knowledge cannot be spontaneously obtained. No one claimed that
    though. Saying that intuition exists doesn't mean that it is a source of
    knowledge. Even if it were not a [potential] source of [accurate]
    knowledge, it still may affect the thought process, and therefore must
    still be taken into account.
  • Virtualeyes at Aug 28, 2012 at 12:27 pm
    Such a wonderful thread: the importance (or lack thereof) of names, and
    intuition vs. acquired knowledge.

    We are treading on hallowed ground here folks.

    Strip away the names and we understand nothing (perhaps a very good thing,
    at least for one moment); supply names and we have a form of (incomplete)
    understanding as names cannot capture the reality.

    Still, we have to name things in order to play out the string and occupy
    ourselves within limited understanding with tasks such as programming and
    asserting one's own relative and arbitrary brilliance ;-)

    Cheers
    On Sunday, August 26, 2012 5:33:44 PM UTC-4, nafg wrote:

    On Sat, Aug 25, 2012 at 9:36 PM, Richard Wallace <
    rwal...@thewallacepack.net <javascript:>> wrote:
    unfortunately intuition doesn't exist. Knowledge cannot be spontaneously
    obtained, it must be acquired through a learning process.

    I think there area few logical problems with the above quote. Note that
    the following is not meant to be an expression of a differing opinion, but
    rather of the contradictions inherent in the above.

    You assert that intuition doesn't exist. You also assert that knowledge
    cannot be spontaneously obtained. Do you know those to be true? If so, do
    you know that intuitively? Or because you learned it? If so, how did you
    come to learn it? Does that mean someone taught it to you (claimed it to
    you)? Or did you come across a proof that refuted the possibility of there
    being intuition, or of there being spontaneous knowledge? Note that the
    last question is recursive; if it was taught to you then your teacher must
    have a source, and if it was proved, then the proof was based on other
    premises which must be known. So according to you, where does knowledge
    start?
    Furthermore, in general it is not possible to "know" that something "does
    not exist." For instance, if someone claims to know that the platypus does
    not exist, that implies that he knows every thing that exists, and the
    platypus is not one of them. However it is impossible to know everything
    that exists. Certainly, if the only source of knowledge is "learning"
    (apparently to the exclusion of intuition), then we can say that it is only
    possible to know about the existence of that which is "learnable." So by
    your own admission it is not possible to know of everything that exists,
    since existence does not imply learnability. Thus your own words imply that
    one cannot know that intuition does not exist.
    Of course if intuition does exist, then it's possible to know that it does
    exist.

    Also, the implicit premise of your statement is that intuition is a
    (imaginary) source of knowledge, since your refutation is your assertion
    that knowledge cannot be spontaneously obtained. No one claimed that
    though. Saying that intuition exists doesn't mean that it is a source of
    knowledge. Even if it were not a [potential] source of [accurate]
    knowledge, it still may affect the thought process, and therefore must
    still be taken into account.
  • Tony Morris at Aug 26, 2012 at 1:37 am
    I can only promise a good laugh at yourself if you might ever choose to
    figure it out. The best kind of laugh in my opinion.
    On Aug 26, 2012 11:12 AM, "Peter Pnin" wrote:

    Are you then the author of Either3?


    https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Either3.scala

    You've chosen the names Left3, Middle3, and Right3 for the cases. Odd that
    you chose "Middle3" for the one in the middle.

    May I suggest an alternative set:

    Northwest, Right, and PoachedEgg

    Please let me know if these are sufficiently arbitrary for you and I will
    make a pull request with the changes. Wallace will no doubt wholeheartedly
    approve.


    On Saturday, August 25, 2012 8:05:36 PM UTC-4, Tony Morris wrote:

    That was a pretty silly thing to say. I will give you the benefit of the
    doubt and assume you haven't opened an algebra book in your life and
    invite you do so so that you can laugh at your spectacularly silly thing
    to have said.

    The Scalaz class you refer to denotes a call strategy. Although I am not
    the implementer, it exists because Scala (the language) totally screws
    up call strategies and you need these kind of gymnastics to make it
    usable.
    On 26/08/12 10:01, Peter Pnin wrote:
    "Success/Failure is no more meaningful than Left/Right. They are just
    names"

    You can't quite be serious. I mean, that is a spectacularly silly thing to
    say. Will give you the benefit of the doubt.

    (The most aptly named class in scalaz is surely:

    https://github.com/scalaz/**scalaz/blob/master/core/src/**
    main/scala/scalaz/Name.scala<https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Name.scala>)


    On Saturday, August 25, 2012 7:31:04 PM UTC-4, Richard Wallace wrote:
    On Sat, Aug 25, 2012 at 1:32 PM, Bruce Eckel <bruce...@gmail.com<**javascript:>>
    wrote:
    Either is generic and doesn't telegraph the intent. Left/Right
    doesn't
    mean
    anything. Success/Failure is quite meaningful.
    Success/Failure is no more meaningful than Left/Right. They are just
    names. Using Either for a errors it is quite apparent which side is
    the error and which the success based on the type you give them. I do
    agree with others that parameterizing Try in the error type is a bad
    idea. But I'd go further and say that Try itself is actually a bad
    idea and should *never be used for anything*. After looking into it
    in detail, the implementation of flatMap, map etc have radically
    different semantics than other types that implement these methods and
    will make it much harder to reason about code.
    At some point you have to convey to the client programmer what your function
    will return and they have to adapt to that. It's part of your
    interface.
    If
    your function returns a Failure containing a Throwable, the client
    programmer has to deal with that. It's no different than if your function
    returns a Failure containing some other kind of information; the
    client
    programmer has to know what it is and deal with that, too.


    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com



    On Sat, Aug 25, 2012 at 2:21 PM, Rex Kerr <ich...@gmail.com
    <javascript:>**>
    wrote:
    I disagree. We already have Either for that. The distinction
    should
    be
    clear:
    - If you want to catch exceptions robustly and hang on to them,
    use
    Try
    - If you want to do anything more elaborate or generic, use Either

    If I get a Try, I don't want to have to handle any possible untyped
    object
    that someone might have tossed in there. Throwables give you quite
    a
    bit:
    stack trace, usually, error message, etc.. Also, when using Try
    what I
    should be most worried about is the control flow disruption that an
    exception can cause--it handles that exception by catching all of
    them
    used
    anywhere within the Try (at least as long as the method still
    returns a
    Try).

    If you don't want that, Either can help and has a fighting chance of
    being
    the right type, too.

    --Rex


    On Sat, Aug 25, 2012 at 4:07 PM, Bruce Eckel <bruce...@gmail.com<**javascript:>>
    wrote:
    I just discovered a difference between Either and Try, but I think
    it's a
    design error.

    Because Either is a generic disjoint union, I can put anything into
    Left:
    scala> Left("foo")
    res0: scala.util.Left[String,**Nothing] = Left(foo)

    With Try, I can also put anything into Success:

    scala> import util.{Success, Failure}
    import util.{Success, Failure}

    scala> Success("Foo")
    res1: scala.util.Success[String] = Success(Foo)

    However, if I try to put anything into Failure, Scala complains:

    scala> Failure("Foo")
    <console>:9: error: type mismatch;
    found : String("Foo")
    required: Throwable
    Failure("Foo")
    ^

    So if I want to put anything into a Failure, I have to wrap it into
    something Throwable, like this:

    case class Why(reason:Any) extends Throwable
    def e = Failure(Why("ouch!"))

    I would like to present Success and Failure as the preferred way to
    report errors; that is, Either should only be used when you have
    two
    possible return types which are what I'll call "of equal weight,"
    where one
    does not represent an error (a previous example in this list, if I
    remember
    correctly, had a choice where you might get an Int or you might get
    a
    String). If you're producing a Success or reporting a Failure, you
    should
    use those types, which provide much clearer intent.

    To do this, I argue that Failure should be able to accept Any, not
    just
    Throwable. I think that would help in moving to this new
    error-handling
    approach.

    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com

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

  • Derek Williams at Aug 26, 2012 at 2:22 am

    On Sat, Aug 25, 2012 at 5:31 PM, Richard Wallace wrote:

    But I'd go further and say that Try itself is actually a bad
    idea and should *never be used for anything*. After looking into it
    in detail, the implementation of flatMap, map etc have radically
    different semantics than other types that implement these methods and
    will make it much harder to reason about code.

    I'm curious what makes you say those methods are radically different then
    what is found in other types. It seems to me Scalaz already has this
    behaviour by using a Promise with the Sequential strategy. I assume you'd
    consider using that a bad idea as well?

    --
    Derek Williams
  • Richard Wallace at Aug 26, 2012 at 2:36 am
    I'm not in a position to show it atm (on a phone) but it is trivial to show
    that Try violates the functor and monad laws. Try it and see.
    On Aug 25, 2012 7:22 PM, "Derek Williams" wrote:

    On Sat, Aug 25, 2012 at 5:31 PM, Richard Wallace <
    rwallace@thewallacepack.net> wrote:
    But I'd go further and say that Try itself is actually a bad
    idea and should *never be used for anything*. After looking into it
    in detail, the implementation of flatMap, map etc have radically
    different semantics than other types that implement these methods and
    will make it much harder to reason about code.

    I'm curious what makes you say those methods are radically different then
    what is found in other types. It seems to me Scalaz already has this
    behaviour by using a Promise with the Sequential strategy. I assume you'd
    consider using that a bad idea as well?

    --
    Derek Williams
  • Daniel Sobral at Aug 26, 2012 at 3:04 am

    On Sat, Aug 25, 2012 at 11:36 PM, Richard Wallace wrote:
    I'm not in a position to show it atm (on a phone) but it is trivial to show
    that Try violates the functor and monad laws. Try it and see.
    I don't think it quite adheres to the definition of "trivial". It took
    a long time for me to see that composition was not respected if g
    throws an exception and f catches in f(g(x)). In fact, I didn't see it
    -- it had to be explicitly pointed out to me.

    Changing failure's definition from

    def map[U](f: T => U): Try[U] = Failure[U](exception)

    to

    def map[U](f: T => U): Try[U] = Try[U](f(throw exception))

    would get map back to functor law. I'm not sure how people would react
    to a Failure becoming a Success again, though. I think it's
    reasonable.

    I didn't look into monadic laws, since flatMap is often not monadic
    anyway in Scala.
    On Aug 25, 2012 7:22 PM, "Derek Williams" wrote:

    On Sat, Aug 25, 2012 at 5:31 PM, Richard Wallace
    wrote:
    But I'd go further and say that Try itself is actually a bad
    idea and should *never be used for anything*. After looking into it
    in detail, the implementation of flatMap, map etc have radically
    different semantics than other types that implement these methods and
    will make it much harder to reason about code.

    I'm curious what makes you say those methods are radically different then
    what is found in other types. It seems to me Scalaz already has this
    behaviour by using a Promise with the Sequential strategy. I assume you'd
    consider using that a bad idea as well?

    --
    Derek Williams


    --
    Daniel C. Sobral

    I travel to the future all the time.
  • Tony Morris at Aug 26, 2012 at 3:13 am

    On 26/08/12 13:03, Daniel Sobral wrote:
    On Sat, Aug 25, 2012 at 11:36 PM, Richard Wallace
    wrote:
    I'm not in a position to show it atm (on a phone) but it is trivial to show
    that Try violates the functor and monad laws. Try it and see.
    I don't think it quite adheres to the definition of "trivial". It took
    a long time for me to see that composition was not respected if g
    throws an exception and f catches in f(g(x)). In fact, I didn't see it
    -- it had to be explicitly pointed out to me.

    Changing failure's definition from

    def map[U](f: T => U): Try[U] = Failure[U](exception)

    to

    def map[U](f: T => U): Try[U] = Try[U](f(throw exception))

    would get map back to functor law. I'm not sure how people would react
    to a Failure becoming a Success again, though. I think it's
    reasonable.
    This is what I meant by altering the notion of equality to meet a law in
    our earlier discussion.
    I didn't look into monadic laws, since flatMap is often not monadic
    anyway in Scala.
    Whether or not other flatMap implementations satisfy is really beside
    the point. Those that I have seen do this in order to achieve a
    perceived "flexibility", but in fact, do quite the opposite (the
    flexibility goal is admirable, but its execution is poor -- I assume due
    to lack of familiarity with the appropriate abstraction(s)).

    Beside the point of existing libraries, the consequences of failing
    associativity for flatMap are pretty disastrous regardless (right? or
    does this need explanation?).

    All implementations of flatMap should satisfy:
    x f g. (x flatMap f) flatMap g == x flatMap (f(_) flatMap g)

    If you (anyone) write a flatMap method that fails this property, then
    the method you have just written is worth less than the air it occupies.
    In other words, it's not even worth nothing -- you can't just ignore it,
    because others will use it and take it seriously and you will be asked
    to work with that code.

    There are other monad laws in general, but flatMap alone does not denote
    a monad (rather, a semi-monad). There are other laws to be satisfied if
    you are to give a unit operation for the data type.

    It's bad enough when these laws are not satisfied; worse still when it
    is subtle as you have pointed out.

    --
    Tony Morris
    http://tmorris.net/
  • Josh Suereth at Aug 26, 2012 at 10:05 pm
    You're conveniently ignoring the fact that no arbitrary scala function can
    satisfy the monad/functor laws because they can close over mutable state.

    Your argument is rather weak. Where do you draw the line on arbitrary
    function?

    with any category abstraction, you have to understand the category to use
    it.

    arrows can throw but not catch. They also can not close over mutable
    state. That's a category definition that works for try.

    What definition are you using that you're applying? Certainly not what
    *scala* means when it says A => B. Because this is not referentially
    transparent. Scala allows mutability.

    So you are imposing non-enforced constraints in your complaints
    *already*. I add one more: functions should not catch exceptions. Now
    Try is fine in this category.

    I don't limit myself to one category (the one used by most haskell
    abstractions). Neither should anyone. The concepts apply to any well
    formed category.
    On Aug 25, 2012 11:13 PM, "Tony Morris" wrote:
    On 26/08/12 13:03, Daniel Sobral wrote:
    On Sat, Aug 25, 2012 at 11:36 PM, Richard Wallace
    wrote:
    I'm not in a position to show it atm (on a phone) but it is trivial to
    show
    that Try violates the functor and monad laws. Try it and see.
    I don't think it quite adheres to the definition of "trivial". It took
    a long time for me to see that composition was not respected if g
    throws an exception and f catches in f(g(x)). In fact, I didn't see it
    -- it had to be explicitly pointed out to me.

    Changing failure's definition from

    def map[U](f: T => U): Try[U] = Failure[U](exception)

    to

    def map[U](f: T => U): Try[U] = Try[U](f(throw exception))

    would get map back to functor law. I'm not sure how people would react
    to a Failure becoming a Success again, though. I think it's
    reasonable.
    This is what I meant by altering the notion of equality to meet a law in
    our earlier discussion.
    I didn't look into monadic laws, since flatMap is often not monadic
    anyway in Scala.
    Whether or not other flatMap implementations satisfy is really beside
    the point. Those that I have seen do this in order to achieve a
    perceived "flexibility", but in fact, do quite the opposite (the
    flexibility goal is admirable, but its execution is poor -- I assume due
    to lack of familiarity with the appropriate abstraction(s)).

    Beside the point of existing libraries, the consequences of failing
    associativity for flatMap are pretty disastrous regardless (right? or
    does this need explanation?).

    All implementations of flatMap should satisfy:
    x f g. (x flatMap f) flatMap g == x flatMap (f(_) flatMap g)

    If you (anyone) write a flatMap method that fails this property, then
    the method you have just written is worth less than the air it occupies.
    In other words, it's not even worth nothing -- you can't just ignore it,
    because others will use it and take it seriously and you will be asked
    to work with that code.

    There are other monad laws in general, but flatMap alone does not denote
    a monad (rather, a semi-monad). There are other laws to be satisfied if
    you are to give a unit operation for the data type.

    It's bad enough when these laws are not satisfied; worse still when it
    is subtle as you have pointed out.

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

  • Martin odersky at Aug 26, 2012 at 8:16 pm

    On Sun, Aug 26, 2012 at 5:03 AM, Daniel Sobral wrote:

    On Sat, Aug 25, 2012 at 11:36 PM, Richard Wallace
    wrote:
    I'm not in a position to show it atm (on a phone) but it is trivial to show
    that Try violates the functor and monad laws. Try it and see.
    I don't think it quite adheres to the definition of "trivial". It took
    a long time for me to see that composition was not respected if g
    throws an exception and f catches in f(g(x)). In fact, I didn't see it
    -- it had to be explicitly pointed out to me.

    And, on second thought, I doubt it is true. f is a call by value function.
    So how can it catch an exception thrown by g(x)?

    Changing failure's definition from

    def map[U](f: T => U): Try[U] = Failure[U](exception)

    to

    def map[U](f: T => U): Try[U] = Try[U](f(throw exception))

    would get map back to functor law. I'm not sure how people would react
    to a Failure becoming a Success again, though. I think it's
    reasonable.
    No, for call-by-value f,

    f(throw ex) == throw ex

    so the two definitions of Try#map are the same, as long as the computation
    of the function value `f` (not its application) is pure and terminating.

    All a storm in a tea cup?

    Cheers

    - Martin
  • Sébastien Bocq at Aug 27, 2012 at 12:03 am
    2012/8/26 martin odersky <martin.odersky@epfl.ch>
    On Sun, Aug 26, 2012 at 5:03 AM, Daniel Sobral wrote:

    On Sat, Aug 25, 2012 at 11:36 PM, Richard Wallace
    wrote:
    I'm not in a position to show it atm (on a phone) but it is trivial to show
    that Try violates the functor and monad laws. Try it and see.
    I don't think it quite adheres to the definition of "trivial". It took
    a long time for me to see that composition was not respected if g
    throws an exception and f catches in f(g(x)). In fact, I didn't see it
    -- it had to be explicitly pointed out to me.

    And, on second thought, I doubt it is true. f is a call by value
    function. So how can it catch an exception thrown by g(x)?

    Changing failure's definition from

    def map[U](f: T => U): Try[U] = Failure[U](exception)

    to

    def map[U](f: T => U): Try[U] = Try[U](f(throw exception))

    would get map back to functor law. I'm not sure how people would react
    to a Failure becoming a Success again, though. I think it's
    reasonable.
    No, for call-by-value f,

    f(throw ex) == throw ex

    so the two definitions of Try#map are the same, as long as the computation
    of the function value `f` (not its application) is pure and terminating.

    All a storm in a tea cup?

    Cheers

    - Martin
    Ah, I was lured into believing this too and my attempt actually doesn't
    solve anything. Now I thought SIP 14 it would help understand better the
    motivations behind Try but I don't see any mention of it. How is Try linked
    to Promises and Futures in SIP 14?

    Cheers,
    Sébastien
  • Sébastien Bocq at Aug 27, 2012 at 2:19 am
    2012/8/27 Sébastien Bocq <sebastien.bocq@gmail.com>

    2012/8/26 martin odersky <martin.odersky@epfl.ch>
    On Sun, Aug 26, 2012 at 5:03 AM, Daniel Sobral wrote:

    On Sat, Aug 25, 2012 at 11:36 PM, Richard Wallace
    wrote:
    I'm not in a position to show it atm (on a phone) but it is trivial to show
    that Try violates the functor and monad laws. Try it and see.
    I don't think it quite adheres to the definition of "trivial". It took
    a long time for me to see that composition was not respected if g
    throws an exception and f catches in f(g(x)). In fact, I didn't see it
    -- it had to be explicitly pointed out to me.

    And, on second thought, I doubt it is true. f is a call by value
    function. So how can it catch an exception thrown by g(x)?

    Changing failure's definition from

    def map[U](f: T => U): Try[U] = Failure[U](exception)

    to

    def map[U](f: T => U): Try[U] = Try[U](f(throw exception))

    would get map back to functor law. I'm not sure how people would react
    to a Failure becoming a Success again, though. I think it's
    reasonable.
    No, for call-by-value f,

    f(throw ex) == throw ex

    so the two definitions of Try#map are the same, as long as the
    computation of the function value `f` (not its application) is pure and
    terminating.

    All a storm in a tea cup?

    Cheers

    - Martin
    Ah, I was lured into believing this too and my attempt actually doesn't
    solve anything. Now I thought SIP 14 it would help understand better the
    motivations behind Try but I don't see any mention of it. How is Try linked
    to Promises and Futures in SIP 14?

    Cheers,
    Sébastien
    Btw, the factory method of scala.util.Try takes a call-by-name parameter,
    although it is immediately evaluated in the try-catch block.
    https://github.com/scala/scala/blob/v2.10.0-M6/src/library/scala/util/Try.scala#L1

    object Try {
    ...

    def apply[T](r: => T): Try[T] = {
    try { Success(r) } catch {
    case NonFatal(e) => Failure(e)
    }
    }

    }


    final case class Success[+T](value: T) extends Try[T] {
    ...
    }

    If `apply` is really intended this way, then my implementation may not be
    completely wasted. :)

    Speaking again about motivations, the example presented in the doc is not
    very convincing.
    http://www.scala-lang.org/api/milestone/scala/util/Try.html

    How is it better than the following version, which uses the built-in
    exception handling mechanism?

    def divide:Int = {

    def prompt:Either[Throwable, Int] = try {
    val dividend = Console.readLine("Enter an Int that you'd like to
    divide:\n").toInt
    val divisor = Console.readLine("Enter an Int that you'd like to
    divide by:\n").toInt
    val v = dividend/divisor
    println("Result of " + dividend + "/"+ divisor +" is: " + v)
    Right(v)
    } catch {
    case e:Exception =>
    println("You must've divided by zero or entered something that's
    not an Int. Try again!")
    println("Info from the exception: " + e.getMessage)
    Left(e)
    }

    prompt match {
    case Right(v) => v
    case _ => divide
    }
    }

    Thanks,
    Sébastien
  • Sébastien Bocq at Aug 27, 2012 at 8:12 am
    2012/8/27 Sébastien Bocq <sebastien.bocq@gmail.com>

    2012/8/27 Sébastien Bocq <sebastien.bocq@gmail.com>

    2012/8/26 martin odersky <martin.odersky@epfl.ch>
    On Sun, Aug 26, 2012 at 5:03 AM, Daniel Sobral <dcsobral@gmail.com>
    wrote:

    On Sat, Aug 25, 2012 at 11:36 PM, Richard Wallace
    wrote:
    I'm not in a position to show it atm (on a phone) but it is trivial to show
    that Try violates the functor and monad laws. Try it and see.
    I don't think it quite adheres to the definition of "trivial". It took
    a long time for me to see that composition was not respected if g
    throws an exception and f catches in f(g(x)). In fact, I didn't see it
    -- it had to be explicitly pointed out to me.

    And, on second thought, I doubt it is true. f is a call by value
    function. So how can it catch an exception thrown by g(x)?

    Changing failure's definition from

    def map[U](f: T => U): Try[U] = Failure[U](exception)

    to

    def map[U](f: T => U): Try[U] = Try[U](f(throw exception))

    would get map back to functor law. I'm not sure how people would react
    to a Failure becoming a Success again, though. I think it's
    reasonable.
    No, for call-by-value f,

    f(throw ex) == throw ex

    so the two definitions of Try#map are the same, as long as the
    computation of the function value `f` (not its application) is pure and
    terminating.

    All a storm in a tea cup?

    Cheers

    - Martin
    Ah, I was lured into believing this too and my attempt actually doesn't
    solve anything. Now I thought SIP 14 it would help understand better the
    motivations behind Try but I don't see any mention of it. How is Try linked
    to Promises and Futures in SIP 14?

    Cheers,
    Sébastien
    Btw, the factory method of scala.util.Try takes a call-by-name parameter,
    although it is immediately evaluated in the try-catch block. If `apply`
    is really intended this way, then my implementation may not be completely
    wasted.
    Ok, probably the only goal is evaluate in the try/catch block and not to
    defer computations that may never be evaluated.
    Sébastien
  • Roland Kuhn at Aug 27, 2012 at 6:33 am
    Hi Sébastien,

    27 aug 2012 kl. 02:03 skrev Sébastien Bocq:
    2012/8/26 martin odersky <martin.odersky@epfl.ch>
    On Sun, Aug 26, 2012 at 5:03 AM, Daniel Sobral wrote:

    On Sat, Aug 25, 2012 at 11:36 PM, Richard Wallace
    wrote:
    I'm not in a position to show it atm (on a phone) but it is trivial to show
    that Try violates the functor and monad laws. Try it and see.
    I don't think it quite adheres to the definition of "trivial". It took
    a long time for me to see that composition was not respected if g
    throws an exception and f catches in f(g(x)). In fact, I didn't see it
    -- it had to be explicitly pointed out to me.

    And, on second thought, I doubt it is true. f is a call by value function. So how can it catch an exception thrown by g(x)?

    Changing failure's definition from

    def map[U](f: T => U): Try[U] = Failure[U](exception)

    to

    def map[U](f: T => U): Try[U] = Try[U](f(throw exception))

    would get map back to functor law. I'm not sure how people would react
    to a Failure becoming a Success again, though. I think it's
    reasonable.

    No, for call-by-value f,

    f(throw ex) == throw ex

    so the two definitions of Try#map are the same, as long as the computation of the function value `f` (not its application) is pure and terminating.

    All a storm in a tea cup?

    Cheers

    - Martin


    Ah, I was lured into believing this too and my attempt actually doesn't solve anything. Now I thought SIP 14 it would help understand better the motivations behind Try but I don't see any mention of it. How is Try linked to Promises and Futures in SIP 14?
    Apart from the sync/async semantic difference a Try is isomorphic to a Future, which is why the temporal aspect is the only thing wrapped around a Try to implement Future/Promise. In fact, an argument was made that Try could be implemented as a KeptPromise with a synchronous ExecutionContext, but we felt that the semantic difference warranted its own name.

    Regards,

    Roland Kuhn
    Typesafe – The software stack for applications that scale.
    twitter: @rolandkuhn
  • Sébastien Bocq at Aug 27, 2012 at 9:21 am
    2012/8/27 Roland Kuhn <google@rkuhn.info>
    Hi Sébastien,

    27 aug 2012 kl. 02:03 skrev Sébastien Bocq:

    2012/8/26 martin odersky <martin.odersky@epfl.ch>
    On Sun, Aug 26, 2012 at 5:03 AM, Daniel Sobral wrote:

    On Sat, Aug 25, 2012 at 11:36 PM, Richard Wallace
    wrote:
    I'm not in a position to show it atm (on a phone) but it is trivial to show
    that Try violates the functor and monad laws. Try it and see.
    I don't think it quite adheres to the definition of "trivial". It took
    a long time for me to see that composition was not respected if g
    throws an exception and f catches in f(g(x)). In fact, I didn't see it
    -- it had to be explicitly pointed out to me.

    And, on second thought, I doubt it is true. f is a call by value
    function. So how can it catch an exception thrown by g(x)?

    Changing failure's definition from

    def map[U](f: T => U): Try[U] = Failure[U](exception)

    to

    def map[U](f: T => U): Try[U] = Try[U](f(throw exception))

    would get map back to functor law. I'm not sure how people would react
    to a Failure becoming a Success again, though. I think it's
    reasonable.
    No, for call-by-value f,

    f(throw ex) == throw ex

    so the two definitions of Try#map are the same, as long as the
    computation of the function value `f` (not its application) is pure and
    terminating.

    All a storm in a tea cup?

    Cheers

    - Martin
    Ah, I was lured into believing this too and my attempt actually doesn't
    solve anything. Now I thought SIP 14 it would help understand better the
    motivations behind Try but I don't see any mention of it. How is Try linked
    to Promises and Futures in SIP 14?

    Apart from the sync/async semantic difference a Try is isomorphic to a
    Future, which is why the temporal aspect is the only thing wrapped around a
    Try to implement Future/Promise. In fact, an argument was made that Try
    could be implemented as a KeptPromise with a synchronous ExecutionContext,
    but we felt that the semantic difference warranted its own name.

    Regards,
    Thanks Roland. I'm not familiar with your implementation but I looked up
    the API and, if I understand you correctly, Try is actually an offspring of
    the implementation of SIP14 to defer the continuation of exception handling
    inside an execution context. Other than that, I have yet to see why Try is
    of general interest and ease error handling compared to regular exception
    handling. Even with Future and Promises, Either seems good enough to do the
    job.

    For example the methods:

    def onComplete[U](func: (Try[T]) => U)(implicit executor: ExecutionContext):
    Unit
    def complete(result:Try[T]): Unit
    def value: Option[Try[T]]

    Can get rid of Try and wrap around a Either value 'v' instead, without
    increasing much complexity:

    def onComplete[U](e: Throwable => U, k:T => U)(implicit executor:
    ExecutionContext): Unit = {...;v.fold(e, k); ...}
    def complete(result:Either[Throwable, T]): Unit = {...; v = result; ...}
    def submit(b: => T):Unit = executor.submit(complete( try {Right(b)} catch
    {case e => Left(e)})) // just an example...
    def poll: Option[T] // throws an exception if present.

    Cheers,
    Sébastien
  • Roland Kuhn at Aug 27, 2012 at 9:38 am

    27 aug 2012 kl. 11:21 skrev Sébastien Bocq:



    2012/8/27 Roland Kuhn <google@rkuhn.info>
    Hi Sébastien,

    27 aug 2012 kl. 02:03 skrev Sébastien Bocq:
    2012/8/26 martin odersky <martin.odersky@epfl.ch>
    On Sun, Aug 26, 2012 at 5:03 AM, Daniel Sobral wrote:

    On Sat, Aug 25, 2012 at 11:36 PM, Richard Wallace
    wrote:
    I'm not in a position to show it atm (on a phone) but it is trivial to show
    that Try violates the functor and monad laws. Try it and see.
    I don't think it quite adheres to the definition of "trivial". It took
    a long time for me to see that composition was not respected if g
    throws an exception and f catches in f(g(x)). In fact, I didn't see it
    -- it had to be explicitly pointed out to me.

    And, on second thought, I doubt it is true. f is a call by value function. So how can it catch an exception thrown by g(x)?

    Changing failure's definition from

    def map[U](f: T => U): Try[U] = Failure[U](exception)

    to

    def map[U](f: T => U): Try[U] = Try[U](f(throw exception))

    would get map back to functor law. I'm not sure how people would react
    to a Failure becoming a Success again, though. I think it's
    reasonable.

    No, for call-by-value f,

    f(throw ex) == throw ex

    so the two definitions of Try#map are the same, as long as the computation of the function value `f` (not its application) is pure and terminating.

    All a storm in a tea cup?

    Cheers

    - Martin


    Ah, I was lured into believing this too and my attempt actually doesn't solve anything. Now I thought SIP 14 it would help understand better the motivations behind Try but I don't see any mention of it. How is Try linked to Promises and Futures in SIP 14?
    Apart from the sync/async semantic difference a Try is isomorphic to a Future, which is why the temporal aspect is the only thing wrapped around a Try to implement Future/Promise. In fact, an argument was made that Try could be implemented as a KeptPromise with a synchronous ExecutionContext, but we felt that the semantic difference warranted its own name.

    Regards,

    Thanks Roland. I'm not familiar with your implementation but I looked up the API and, if I understand you correctly, Try is actually an offspring of the implementation of SIP14 to defer the continuation of exception handling inside an execution context. Other than that, I have yet to see why Try is of general interest and ease error handling compared to regular exception handling. Even with Future and Promises, Either seems good enough to do the job.

    For example the methods:

    def onComplete[U](func: (Try[T]) ⇒ U)(implicit executor: ExecutionContext): Unit
    def complete(result:Try[T]): Unit
    def value: Option[Try[T]]

    Can get rid of Try and wrap around a Either value 'v' instead, without increasing much complexity:

    def onComplete[U](e: Throwable ⇒ U, k:T => U)(implicit executor: ExecutionContext): Unit = {...;v.fold(e, k); ...}
    def complete(result:Either[Throwable, T]): Unit = {...; v = result; ...}
    def submit(b: => T):Unit = executor.submit(complete( try {Right(b)} catch {case e => Left(e)})) // just an example...
    def poll: Option[T] // throws an exception if present.
    Akka futures were based upon Either[Throwable, T], so we definitely know that this is possible. The change was made because we realized that the internal logic of Try and Future looks virtually identical, apart from the execution mechanism of the transformations. Reuse is good. Also, Try is much nicer to work with using for-comprehensions and from Java (for those who need that).

    Regards,

    Roland Kuhn
    Typesafe – The software stack for applications that scale.
    twitter: @rolandkuhn
  • Josh Suereth at Aug 27, 2012 at 10:18 am
    The big reason for try to exist is that all of its "monadic" (for
    comprehension) operations catch exceptions and lift into Failure.

    You could do this with Either but would have to manually lift exceptions
    yourself.

    When it comes to "error handling". Try is but one of many ways to handle
    failures.
    On Aug 27, 2012 5:38 AM, "Roland Kuhn" wrote:


    27 aug 2012 kl. 11:21 skrev Sébastien Bocq:



    2012/8/27 Roland Kuhn <google@rkuhn.info>
    Hi Sébastien,

    27 aug 2012 kl. 02:03 skrev Sébastien Bocq:

    2012/8/26 martin odersky <martin.odersky@epfl.ch>
    On Sun, Aug 26, 2012 at 5:03 AM, Daniel Sobral <dcsobral@gmail.com>
    wrote:

    On Sat, Aug 25, 2012 at 11:36 PM, Richard Wallace
    wrote:
    I'm not in a position to show it atm (on a phone) but it is trivial to show
    that Try violates the functor and monad laws. Try it and see.
    I don't think it quite adheres to the definition of "trivial". It took
    a long time for me to see that composition was not respected if g
    throws an exception and f catches in f(g(x)). In fact, I didn't see it
    -- it had to be explicitly pointed out to me.

    And, on second thought, I doubt it is true. f is a call by value
    function. So how can it catch an exception thrown by g(x)?

    Changing failure's definition from

    def map[U](f: T => U): Try[U] = Failure[U](exception)

    to

    def map[U](f: T => U): Try[U] = Try[U](f(throw exception))

    would get map back to functor law. I'm not sure how people would react
    to a Failure becoming a Success again, though. I think it's
    reasonable.
    No, for call-by-value f,

    f(throw ex) == throw ex

    so the two definitions of Try#map are the same, as long as the
    computation of the function value `f` (not its application) is pure and
    terminating.

    All a storm in a tea cup?

    Cheers

    - Martin
    Ah, I was lured into believing this too and my attempt actually doesn't
    solve anything. Now I thought SIP 14 it would help understand better the
    motivations behind Try but I don't see any mention of it. How is Try linked
    to Promises and Futures in SIP 14?

    Apart from the sync/async semantic difference a Try is isomorphic to a
    Future, which is why the temporal aspect is the only thing wrapped around a
    Try to implement Future/Promise. In fact, an argument was made that Try
    could be implemented as a KeptPromise with a synchronous ExecutionContext,
    but we felt that the semantic difference warranted its own name.

    Regards,
    Thanks Roland. I'm not familiar with your implementation but I looked up
    the API and, if I understand you correctly, Try is actually an offspring of
    the implementation of SIP14 to defer the continuation of exception handling
    inside an execution context. Other than that, I have yet to see why Try is
    of general interest and ease error handling compared to regular exception
    handling. Even with Future and Promises, Either seems good enough to do the
    job.

    For example the methods:

    def onComplete[U](func: (Try[T]) => U)(implicit executor:
    ExecutionContext): Unit
    def complete(result:Try[T]): Unit
    def value: Option[Try[T]]

    Can get rid of Try and wrap around a Either value 'v' instead, without
    increasing much complexity:

    def onComplete[U](e: Throwable => U, k:T => U)(implicit executor:
    ExecutionContext): Unit = {...;v.fold(e, k); ...}
    def complete(result:Either[Throwable, T]): Unit = {...; v = result; ...}
    def submit(b: => T):Unit = executor.submit(complete( try {Right(b)} catch
    {case e => Left(e)})) // just an example...
    def poll: Option[T] // throws an exception if present.

    Akka futures were based upon Either[Throwable, T], so we definitely know
    that this is possible. The change was made because we realized that the
    internal logic of Try and Future looks virtually identical, apart from the
    execution mechanism of the transformations. Reuse is good. Also, Try is
    much nicer to work with using for-comprehensions and from Java (for those
    who need that).

    Regards,

    Roland Kuhn
    Typesafe <http://typesafe.com/> - The software stack for applications
    that scale.
    twitter: @rolandkuhn <http://twitter.com/#!/rolandkuhn>
  • Bruce Eckel at Aug 27, 2012 at 2:08 pm
    Since its genesis, Java has been filled with poor design decisions that
    have become canon. The language is gridlocked by rigid adherence to
    backwards compatibility with these poor decisions.

    I hold Scala to a higher standard. So far, anyway.

    The big step forward in error reporting is the use of the disjoint union.
    The Go language uses tuples, but at the root it's the same effect: return
    two kinds of things. A valid thing and an error thing.

    One way or another the client programmer must understand what is returned,
    and then upack and deal with the results.

    Using Either as the disjoint union was fine as an experiment. But to now
    cling to that as the best approach simply because we experimented with that
    particular implementation, and to saddle all future programmers with the
    cognitive load of remembering that "Left" is failure and "Right" is success
    is, to my mind, "Java thinking" and counterproductive to Scala programmers.

    Especially new programmers. I don't want to explain to new programmers that
    they have to use Left and Right instead of Success and Failure, especially
    now that (with the introduction of Try) Success and Failure will be staring
    them in the face. That's the kind of embarassing explanation that I've
    gotten really tired of in Java.

    Using Either was just an experiment. There's nothing that binds us to using
    it. The client programmer must always understand what a function returns,
    so why not let go of Either and use something that conveys useful
    information?

    I would really like to see full support for moving from Either to the use
    of Success and Failure, certainly for new code (explaining legacy code is
    tolerable: "left over from a successful experiment"). That's certainly the
    way I plan to explain it to people and I'd love to have support from the
    libary.

    Perhaps we could even add a method to Either that would produce
    Success/Failure, to make legacy code more tolerable.

    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com
  • Rex Kerr at Aug 27, 2012 at 2:41 pm

    On Mon, Aug 27, 2012 at 10:07 AM, Bruce Eckel wrote:

    I don't want to explain to new programmers that they have to use Left and
    Right instead of Success and Failure, especially now that (with the
    introduction of Try) Success and Failure will be staring them in the face.
    That's the kind of embarassing explanation that I've gotten really tired of
    in Java.
    Using Either was just an experiment. There's nothing that binds us to
    using it. The client programmer must always understand what a function
    returns, so why not let go of Either and use something that conveys useful
    information?
    I've said this twice already. Maybe the third time will be the charm.

    *Either is not just for error handling.*

    In my code I have used Either in the following ways which have nothing to
    do with error handling:
    (1) Input data can be floats or doubles;
    Either[Array[Float],Array[Double]]
    (2) Entry forms with drop-down options plus text are
    Either[ListedItems,String] depending on whether the user chooses one or
    types their own
    (3) There are two different FFT routines I use; I provide a common
    interface with Either holding the non-identical optional settings for the
    two
    (4) I use Either when command-line settings can be read from a file to
    hold the file name or the command, as I showed before
    (5) When recursing directories to collect information, I have
    Either[DirectoryData,FileData]
    (6) While processing errors, I have Either[Exception,Exception] to
    segregate the exceptions I can/cannot handle.
    (7) I provide a common interface to static and lazy processing with
    Either[X, () => X].

    (and probably more that I have overlooked at the moment).

    So, Either is useful well beyond its application to error handling.
    Getting rid of Either would either cause a lot of repetitive work, or force
    people back to AnyRef with no type-level support for what might actually be
    there (and probably unsafe casting).

    Now, given that you already have Either, because it is generically useful,
    do you or do you not want to create a clone that works much like Either but
    sounds like it is specifically for errors? DRY suggests no. Use the
    generic construct *unless* you have a significant value-add with the clone.

    And Try does have a significant value add: it handles exceptions for you,
    catching and packaging them up as Failure. It (aside from bugs) catches
    every exception, always. So you can do something like
    Try(s.toLong.toInt).recover(_ => s.toDouble.toInt).map(myArray)
    and either the whole thing will work (yay!) or you'll get an exception
    (boo!), and you didn't have to think about three different try-catch
    blocks. It can do this *specifically because it only handles exceptions*.
    If it handled arbitrary errors, it would again have to fall back to AnyRef
    (or Either[Throwable,X], or have three states) and would be clunky and/or
    invite a lack of type safety.

    So
    - If you want to be bulletproof to exceptions, use Try
    - If you want to hold either of two types, use Either
    (Hint: error value and correct value is a useful case of needing two
    types; in that case the convention is that Right is the correct value.)

    Now, the one drawback of Either is that it is not biased, which means that
    it is equally inconvenient to work with either Lefts or Rights. Rob
    Dickens has a pretty good implementation of a right-biased Either, where
    the right side is the favored side (map, flatMap, etc. will work on that
    side). We can discuss whether this or something based on it should replace
    the existing unbiased Either.

    I don't think it's too hard for people to understand that it's usually good
    to use a powerful generic construct to help them with their error-handling
    tasks instead of using a construct that's specialized for
    exception-handling. You do have to present it with a modicum of care, but
    you have to do that anyway since more often than not you'll use Option not
    Either when something could result in not a value. (You don't care why,
    usually. You just want your value if you can have it.)

    --Rex
  • Bruce Eckel at Aug 27, 2012 at 3:04 pm
    Sorry I wasn't clear. I don't want to get rid of Either: it's good for
    holding either of two types.

    I want to use Success/Failure to report successes and failures.

    The "experiment" I spoke of was using Left and Right to report errors.
    That's what we should get rid of, in favor of Success/Failure.

    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com


    On Mon, Aug 27, 2012 at 8:41 AM, Rex Kerr wrote:
    On Mon, Aug 27, 2012 at 10:07 AM, Bruce Eckel wrote:

    I don't want to explain to new programmers that they have to use Left and
    Right instead of Success and Failure, especially now that (with the
    introduction of Try) Success and Failure will be staring them in the face.
    That's the kind of embarassing explanation that I've gotten really tired of
    in Java.
    Using Either was just an experiment. There's nothing that binds us to
    using it. The client programmer must always understand what a function
    returns, so why not let go of Either and use something that conveys useful
    information?
    I've said this twice already. Maybe the third time will be the charm.

    *Either is not just for error handling.*

    In my code I have used Either in the following ways which have nothing to
    do with error handling:
    (1) Input data can be floats or doubles;
    Either[Array[Float],Array[Double]]
    (2) Entry forms with drop-down options plus text are
    Either[ListedItems,String] depending on whether the user chooses one or
    types their own
    (3) There are two different FFT routines I use; I provide a common
    interface with Either holding the non-identical optional settings for the
    two
    (4) I use Either when command-line settings can be read from a file to
    hold the file name or the command, as I showed before
    (5) When recursing directories to collect information, I have
    Either[DirectoryData,FileData]
    (6) While processing errors, I have Either[Exception,Exception] to
    segregate the exceptions I can/cannot handle.
    (7) I provide a common interface to static and lazy processing with
    Either[X, () => X].

    (and probably more that I have overlooked at the moment).

    So, Either is useful well beyond its application to error handling.
    Getting rid of Either would either cause a lot of repetitive work, or force
    people back to AnyRef with no type-level support for what might actually be
    there (and probably unsafe casting).

    Now, given that you already have Either, because it is generically useful,
    do you or do you not want to create a clone that works much like Either but
    sounds like it is specifically for errors? DRY suggests no. Use the
    generic construct *unless* you have a significant value-add with the
    clone.

    And Try does have a significant value add: it handles exceptions for you,
    catching and packaging them up as Failure. It (aside from bugs) catches
    every exception, always. So you can do something like
    Try(s.toLong.toInt).recover(_ => s.toDouble.toInt).map(myArray)
    and either the whole thing will work (yay!) or you'll get an exception
    (boo!), and you didn't have to think about three different try-catch
    blocks. It can do this *specifically because it only handles exceptions*.
    If it handled arbitrary errors, it would again have to fall back to AnyRef
    (or Either[Throwable,X], or have three states) and would be clunky and/or
    invite a lack of type safety.

    So
    - If you want to be bulletproof to exceptions, use Try
    - If you want to hold either of two types, use Either
    (Hint: error value and correct value is a useful case of needing two
    types; in that case the convention is that Right is the correct value.)

    Now, the one drawback of Either is that it is not biased, which means that
    it is equally inconvenient to work with either Lefts or Rights. Rob
    Dickens has a pretty good implementation of a right-biased Either, where
    the right side is the favored side (map, flatMap, etc. will work on that
    side). We can discuss whether this or something based on it should replace
    the existing unbiased Either.

    I don't think it's too hard for people to understand that it's usually
    good to use a powerful generic construct to help them with their
    error-handling tasks instead of using a construct that's specialized for
    exception-handling. You do have to present it with a modicum of care, but
    you have to do that anyway since more often than not you'll use Option not
    Either when something could result in not a value. (You don't care why,
    usually. You just want your value if you can have it.)

    --Rex
  • Rex Kerr at Aug 27, 2012 at 3:42 pm
    You didn't address my second point, which was that given that we need
    Either, having yet another class duplicating the type union functionality
    would be repeating yourself.

    Can you reread, or explain more clearly how what you propose doesn't fall
    afoul of that criticism?

    Do you want to add yet another container? Or can you show what is wrong
    with my explanation that Try cannot be the general tool that you want it to
    be?

    --Rex
    On Mon, Aug 27, 2012 at 10:56 AM, Bruce Eckel wrote:

    Sorry I wasn't clear. I don't want to get rid of Either: it's good for
    holding either of two types.

    I want to use Success/Failure to report successes and failures.

    The "experiment" I spoke of was using Left and Right to report errors.
    That's what we should get rid of, in favor of Success/Failure.


    -- Bruce Eckel
    www.AtomicScala.com
    www.Reinventing-Business.com
    www.MindviewInc.com


    On Mon, Aug 27, 2012 at 8:41 AM, Rex Kerr wrote:
    On Mon, Aug 27, 2012 at 10:07 AM, Bruce Eckel wrote:

    I don't want to explain to new programmers that they have to use Left
    and Right instead of Success and Failure, especially now that (with the
    introduction of Try) Success and Failure will be staring them in the face.
    That's the kind of embarassing explanation that I've gotten really tired of
    in Java.
    Using Either was just an experiment. There's nothing that binds us to
    using it. The client programmer must always understand what a function
    returns, so why not let go of Either and use something that conveys useful
    information?
    I've said this twice already. Maybe the third time will be the charm.

    *Either is not just for error handling.*

    In my code I have used Either in the following ways which have nothing to
    do with error handling:
    (1) Input data can be floats or doubles;
    Either[Array[Float],Array[Double]]
    (2) Entry forms with drop-down options plus text are
    Either[ListedItems,String] depending on whether the user chooses one or
    types their own
    (3) There are two different FFT routines I use; I provide a common
    interface with Either holding the non-identical optional settings for the
    two
    (4) I use Either when command-line settings can be read from a file to
    hold the file name or the command, as I showed before
    (5) When recursing directories to collect information, I have
    Either[DirectoryData,FileData]
    (6) While processing errors, I have Either[Exception,Exception] to
    segregate the exceptions I can/cannot handle.
    (7) I provide a common interface to static and lazy processing with
    Either[X, () => X].

    (and probably more that I have overlooked at the moment).

    So, Either is useful well beyond its application to error handling.
    Getting rid of Either would either cause a lot of repetitive work, or force
    people back to AnyRef with no type-level support for what might actually be
    there (and probably unsafe casting).

    Now, given that you already have Either, because it is generically
    useful, do you or do you not want to create a clone that works much like
    Either but sounds like it is specifically for errors? DRY suggests no.
    Use the generic construct *unless* you have a significant value-add with
    the clone.

    And Try does have a significant value add: it handles exceptions for you,
    catching and packaging them up as Failure. It (aside from bugs) catches
    every exception, always. So you can do something like
    Try(s.toLong.toInt).recover(_ => s.toDouble.toInt).map(myArray)
    and either the whole thing will work (yay!) or you'll get an exception
    (boo!), and you didn't have to think about three different try-catch
    blocks. It can do this *specifically because it only handles exceptions*.
    If it handled arbitrary errors, it would again have to fall back to AnyRef
    (or Either[Throwable,X], or have three states) and would be clunky and/or
    invite a lack of type safety.

    So
    - If you want to be bulletproof to exceptions, use Try
    - If you want to hold either of two types, use Either
    (Hint: error value and correct value is a useful case of needing two
    types; in that case the convention is that Right is the correct value.)

    Now, the one drawback of Either is that it is not biased, which means
    that it is equally inconvenient to work with either Lefts or Rights. Rob
    Dickens has a pretty good implementation of a right-biased Either, where
    the right side is the favored side (map, flatMap, etc. will work on that
    side). We can discuss whether this or something based on it should replace
    the existing unbiased Either.

    I don't think it's too hard for people to understand that it's usually
    good to use a powerful generic construct to help them with their
    error-handling tasks instead of using a construct that's specialized for
    exception-handling. You do have to present it with a modicum of care, but
    you have to do that anyway since more often than not you'll use Option not
    Either when something could result in not a value. (You don't care why,
    usually. You just want your value if you can have it.)

    --Rex
  • Sébastien Bocq at Aug 27, 2012 at 4:58 pm
    2012/8/27 Rex Kerr <ichoran@gmail.com>
    And Try does have a significant value add: it handles exceptions for you,
    catching and packaging them up as Failure. It (aside from bugs) catches
    every exception, always. So you can do something like
    Try(s.toLong.toInt).recover(_ => s.toDouble.toInt).map(myArray)
    and either the whole thing will work (yay!) or you'll get an exception
    (boo!), and you didn't have to think about three different try-catch blocks.
    I hate playing the wet blanket, but sometimes it is useful when someone
    puts itself on the other side of the fence in a respectful and constructive
    manner, at least this has always be my intent.

    Considering only the simple case, how is this example better than:

    try {
    myArray(s.toInt)
    } catch {case _:Exception => // ??? }

    In the end, we have also to unbox the result, in which case we're not much
    better off:

    Try(s.toInt).map(myArray) match {
    case Success(a) => a
    case Failure(e) => // ???
    }

    Personally, I don't encounter often nested exception handlers. If you can,
    you don't nest them. Even then, implementing robust recovery mechanisms
    means handling exceptions accurately as soon as possible in the context in
    which they occur. If the exception context is important, the following
    example:

    try { a } catch {
    case e:EA =>
    // ... deal with EA
    try { b } catch {
    case e:EB =>
    // ... deal with EB
    c
    }
    }

    becomes:

    Try(a) rescue {
    case e:EA =>
    // ... deal with EA
    Try(b) recover {
    case e:EB =>
    // ... deal with EB
    c
    }
    } match {
    case Success(c) => c
    case Failure(e) => throw e
    }

    So, we have now introduced two additional keywords 'recover', 'rescue',
    boxing and a less readable form of nesting because we can apparently do it
    yet another way. Is that what a Java programmer must remember while
    learning Scala? Would he be impressed? At the risk of sounding like a
    broken record, how can such monadic exception handling win the heart of
    imperative programmers for writing regular (synchronous) code on a
    platformthat has already good built-in support for threads and
    exceptions?

    Regards,
    Sébastien
  • Daniel Sobral at Aug 27, 2012 at 5:14 pm

    On Mon, Aug 27, 2012 at 1:58 PM, Sébastien Bocq wrote:


    2012/8/27 Rex Kerr <ichoran@gmail.com>

    And Try does have a significant value add: it handles exceptions for you,
    catching and packaging them up as Failure. It (aside from bugs) catches
    every exception, always. So you can do something like
    Try(s.toLong.toInt).recover(_ => s.toDouble.toInt).map(myArray)
    and either the whole thing will work (yay!) or you'll get an exception
    (boo!), and you didn't have to think about three different try-catch blocks.

    I hate playing the wet blanket, but sometimes it is useful when someone puts
    itself on the other side of the fence in a respectful and constructive
    manner, at least this has always be my intent.

    Considering only the simple case, how is this example better than:

    try {
    myArray(s.toInt)
    } catch {case _:Exception => // ??? }
    Simple answer: the code that does the try, the recover and the map
    need not be the same in the first case. That's the essence of Try and
    other solutions that transform exceptions into value.
    In the end, we have also to unbox the result, in which case we're not much
    better off:

    Try(s.toInt).map(myArray) match {
    case Success(a) => a
    case Failure(e) => // ???
    }

    Personally, I don't encounter often nested exception handlers. If you can,
    you don't nest them. Even then, implementing robust recovery mechanisms
    means handling exceptions accurately as soon as possible in the context in
    which they occur. If the exception context is important, the following
    example:

    try { a } catch {
    case e:EA =>
    // ... deal with EA
    try { b } catch {
    case e:EB =>
    // ... deal with EB
    c
    }
    }

    becomes:

    Try(a) rescue {
    case e:EA =>
    // ... deal with EA
    Try(b) recover {
    case e:EB =>
    // ... deal with EB
    c
    }
    } match {
    case Success(c) => c
    case Failure(e) => throw e
    }

    So, we have now introduced two additional keywords 'recover', 'rescue',
    boxing and a less readable form of nesting because we can apparently do it
    yet another way. Is that what a Java programmer must remember while learning
    Scala? Would he be impressed? At the risk of sounding like a broken record,
    how can such monadic exception handling win the heart of imperative
    programmers for writing regular (synchronous) code on a platform that has
    already good built-in support for threads and exceptions?

    Regards,
    Sébastien


    --
    Daniel C. Sobral

    I travel to the future all the time.
  • Sébastien Bocq at Aug 27, 2012 at 5:31 pm
    2012/8/27 Daniel Sobral <dcsobral@gmail.com>
    On Mon, Aug 27, 2012 at 1:58 PM, Sébastien Bocq
    wrote:

    2012/8/27 Rex Kerr <ichoran@gmail.com>

    And Try does have a significant value add: it handles exceptions for
    you,
    catching and packaging them up as Failure. It (aside from bugs) catches
    every exception, always. So you can do something like
    Try(s.toLong.toInt).recover(_ => s.toDouble.toInt).map(myArray)
    and either the whole thing will work (yay!) or you'll get an exception
    (boo!), and you didn't have to think about three different try-catch
    blocks.

    I hate playing the wet blanket, but sometimes it is useful when someone puts
    itself on the other side of the fence in a respectful and constructive
    manner, at least this has always be my intent.

    Considering only the simple case, how is this example better than:

    try {
    myArray(s.toInt)
    } catch {case _:Exception => // ??? }
    Simple answer: the code that does the try, the recover and the map
    need not be the same in the first case. That's the essence of Try and
    other solutions that transform exceptions into value.
    Can you elaborate? What is the difference with the regular `try` statement?

    In the end, we have also to unbox the result, in which case we're not much
    better off:

    Try(s.toInt).map(myArray) match {
    case Success(a) => a
    case Failure(e) => // ???
    }

    Personally, I don't encounter often nested exception handlers. If you can,
    you don't nest them. Even then, implementing robust recovery mechanisms
    means handling exceptions accurately as soon as possible in the context in
    which they occur. If the exception context is important, the following
    example:

    try { a } catch {
    case e:EA =>
    // ... deal with EA
    try { b } catch {
    case e:EB =>
    // ... deal with EB
    c
    }
    }

    becomes:

    Try(a) rescue {
    case e:EA =>
    // ... deal with EA
    Try(b) recover {
    case e:EB =>
    // ... deal with EB
    c
    }
    } match {
    case Success(c) => c
    case Failure(e) => throw e
    }

    So, we have now introduced two additional keywords 'recover', 'rescue',
    boxing and a less readable form of nesting because we can apparently do it
    yet another way. Is that what a Java programmer must remember while learning
    Scala? Would he be impressed? At the risk of sounding like a broken record,
    how can such monadic exception handling win the heart of imperative
    programmers for writing regular (synchronous) code on a platform that has
    already good built-in support for threads and exceptions?

    Regards,
    Sébastien


    --
    Daniel C. Sobral

    I travel to the future all the time.


    --
    Sébastien
  • Daniel Sobral at Aug 27, 2012 at 9:27 pm

    On Mon, Aug 27, 2012 at 2:24 PM, Sébastien Bocq wrote:


    2012/8/27 Daniel Sobral <dcsobral@gmail.com>
    On Mon, Aug 27, 2012 at 1:58 PM, Sébastien Bocq
    wrote:

    2012/8/27 Rex Kerr <ichoran@gmail.com>

    And Try does have a significant value add: it handles exceptions for
    you,
    catching and packaging them up as Failure. It (aside from bugs)
    catches
    every exception, always. So you can do something like
    Try(s.toLong.toInt).recover(_ => s.toDouble.toInt).map(myArray)
    and either the whole thing will work (yay!) or you'll get an exception
    (boo!), and you didn't have to think about three different try-catch
    blocks.

    I hate playing the wet blanket, but sometimes it is useful when someone
    puts
    itself on the other side of the fence in a respectful and constructive
    manner, at least this has always be my intent.

    Considering only the simple case, how is this example better than:

    try {
    myArray(s.toInt)
    } catch {case _:Exception => // ??? }
    Simple answer: the code that does the try, the recover and the map
    need not be the same in the first case. That's the essence of Try and
    other solutions that transform exceptions into value.
    Can you elaborate? What is the difference with the regular `try` statement?
    I can return Try[T] from a method. If I use "try" at the callee level,
    it might catch exceptions I'm not interested in catching. Furthermore,
    Try[T] effectively introduces a limited form of checked exceptions
    into Scala type system which, while generally a problem, sometimes are
    useful.

    For example:

    computeAverage(data: Data): Try[Double]

    The obvious exception would be a division by zero, in case there's no
    data to compute an average of. The method computeAverage, however, is
    the wrong place to handle this exception -- were it going to be used
    for further computations or visualization? If visualization, directly
    as a number, or as a graph? And if we have the exception, do we
    display something else, or omit the information?

    Of course, it could return Option[Double], but everything Try does can
    be handled by Option or Either. Any use case you come up with can be
    handled by then -- but Try provides a more concise interface and a
    clearer statement of intent.

    --
    Daniel C. Sobral

    I travel to the future all the time.
  • Rex Kerr at Aug 27, 2012 at 9:37 pm
    Double is not the best example because with Double you'd likely use
    Double.NaN. But the point is a good one regardless.

    --Rex
    On Mon, Aug 27, 2012 at 5:27 PM, Daniel Sobral wrote:


    For example:

    computeAverage(data: Data): Try[Double]

    The obvious exception would be a division by zero, in case there's no
    data to compute an average of.
  • Tony Morris at Aug 27, 2012 at 10:29 pm

    On 28/08/12 07:27, Daniel Sobral wrote:
    On Mon, Aug 27, 2012 at 2:24 PM, Sébastien Bocq
    wrote:
    2012/8/27 Daniel Sobral <dcsobral@gmail.com>
    On Mon, Aug 27, 2012 at 1:58 PM, Sébastien Bocq
    wrote:
    2012/8/27 Rex Kerr <ichoran@gmail.com>
    And Try does have a significant value add: it handles exceptions for
    you,
    catching and packaging them up as Failure. It (aside from bugs)
    catches
    every exception, always. So you can do something like
    Try(s.toLong.toInt).recover(_ => s.toDouble.toInt).map(myArray)
    and either the whole thing will work (yay!) or you'll get an exception
    (boo!), and you didn't have to think about three different try-catch
    blocks.
    I hate playing the wet blanket, but sometimes it is useful when someone
    puts
    itself on the other side of the fence in a respectful and constructive
    manner, at least this has always be my intent.

    Considering only the simple case, how is this example better than:

    try {
    myArray(s.toInt)
    } catch {case _:Exception => // ??? }
    Simple answer: the code that does the try, the recover and the map
    need not be the same in the first case. That's the essence of Try and
    other solutions that transform exceptions into value.
    Can you elaborate? What is the difference with the regular `try` statement?
    I can return Try[T] from a method. If I use "try" at the callee level,
    it might catch exceptions I'm not interested in catching. Furthermore,
    Try[T] effectively introduces a limited form of checked exceptions
    into Scala type system which, while generally a problem, sometimes are
    useful.

    For example:

    computeAverage(data: Data): Try[Double]

    The obvious exception would be a division by zero, in case there's no
    data to compute an average of. The method computeAverage, however, is
    the wrong place to handle this exception -- were it going to be used
    for further computations or visualization? If visualization, directly
    as a number, or as a graph? And if we have the exception, do we
    display something else, or omit the information?

    Of course, it could return Option[Double], but everything Try does can
    be handled by Option or Either. Any use case you come up with can be
    handled by then -- but Try provides a more concise interface and a
    clearer statement of intent.
    What if I want to know the context of the data where the 0 was?

    You're not going to make me go through that exception, look at the
    message, so that I can never work it out are you? WHAT DID I EVER DO TO
    YOU?!


    --
    Tony Morris
    http://tmorris.net/
  • Rex Kerr at Aug 27, 2012 at 11:16 pm

    On Mon, Aug 27, 2012 at 6:29 PM, Tony Morris wrote:
    What if I want to know the context of the data where the 0 was?
    Don't use Try, or if you insist on using it,

    case class Exceptional[A](value: A) extends Exception {
    override def fillInStackTrace() = this
    }
    Try(s.toInt).rescue(_ => throw Exceptional((42,"Whatever I need")))

    Clunky. I don't recommend it. You have to pattern match to get it back.
    I'd rather
    Try(s.toInt).toEither.left.map(_ => (42,"Whatever I need"))
    except toEither doesn't exist.

    I'd want either a toEither or a withLeft[A](Throwable => A).

    --Rex
  • Tony Morris at Aug 27, 2012 at 11:41 pm

    On 28/08/12 09:16, Rex Kerr wrote:
    On Mon, Aug 27, 2012 at 6:29 PM, Tony Morris wrote:


    What if I want to know the context of the data where the 0 was?


    Don't use Try, or if you insist on using it,
    Well I won't be using Try because it is full of bugs.

    I was more concerned about the sloppy degree of error-reporting. You
    have *surely* seen those applications that do this -- fail to give you
    an appropriate error report. They are *everywhere* and in my experience,
    the programmers who maintain them can do nothing about it because the
    underlying data structures are inappropriate (except of course, a
    rewrite which often results in the same thing).

    Please let's not write more of them. There is *far* more to
    error-handling and reporting than is being made out here -- this is
    aside from the fact that Try is inappropriate for anything at all.

    case class Exceptional[A](value: A) extends Exception {
    override def fillInStackTrace() = this
    }
    Try(s.toInt).rescue(_ => throw Exceptional((42,"Whatever I need")))

    Clunky. I don't recommend it. You have to pattern match to get it
    back. I'd rather
    Try(s.toInt).toEither.left.map(_ => (42,"Whatever I need"))
    except toEither doesn't exist.

    I'd want either a toEither or a withLeft[A](Throwable => A).

    --Rex

    --
    Tony Morris
    http://tmorris.net/
  • Martin odersky at Aug 28, 2012 at 7:47 am

    On Tue, Aug 28, 2012 at 1:19 AM, Tony Morris wrote:

    **
    On 28/08/12 09:16, Rex Kerr wrote:
    On Mon, Aug 27, 2012 at 6:29 PM, Tony Morris wrote:


    What if I want to know the context of the data where the 0 was?
    Don't use Try, or if you insist on using it,


    Well I won't be using Try because it is full of bugs.

    I was more concerned about the sloppy degree of error-reporting. You have
    *surely* seen those applications that do this -- fail to give you an
    appropriate error report. They are *everywhere* and in my experience, the
    programmers who maintain them can do nothing about it because the
    underlying data structures are inappropriate (except of course, a rewrite
    which often results in the same thing).

    Please let's not write more of them. There is *far* more to error-handling
    and reporting than is being made out here -- this is aside from the fact
    that Try is inappropriate for anything at all.




    case class Exceptional[A](value: A) extends Exception {
    override def fillInStackTrace() = this
    }
    Try(s.toInt).rescue(_ => throw Exceptional((42,"Whatever I need")))

    Clunky. I don't recommend it. You have to pattern match to get it back.
    I'd rather
    Try(s.toInt).toEither.left.map(_ => (42,"Whatever I need"))
    except toEither doesn't exist.

    I'd want either a toEither or a withLeft[A](Throwable => A).

    --Rex



    --
    Tony Morrishttp://tmorris.net/

    If Try is full of bugs, and you want to be a good Scala citizen, you
    might mention what they are here, or, better, file tickets.

    It seems you alluded to a problem earlier (Functor law). Not on this list,
    that was reserved exclusively for slandering from your part. But that's
    what Daniel and others have brought up, it seems after discussions on the
    irc channel.

    I stated on this list that the problem does not exist, the Functor equality
    holds for Try.

    You never got back on that. It would be good to have you acknowledge this
    or provide a counter point. That's how scientific debate works. The mailing
    list threads we had recently were severely lacking in that respect.

    Thanks

    - Martin

Related Discussions

People

Translate

site design / logo © 2022 Grokbase