From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.1.3 (2006-06-01) on yquem.inria.fr X-Spam-Level: * X-Spam-Status: No, score=1.3 required=5.0 tests=AWL,HTML_MESSAGE,SPF_NEUTRAL autolearn=disabled version=3.1.3 X-Original-To: caml-list@yquem.inria.fr Delivered-To: caml-list@yquem.inria.fr Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by yquem.inria.fr (Postfix) with ESMTP id 406D5BC6B for ; Mon, 11 Feb 2008 03:16:31 +0100 (CET) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AgAAACY/r0fAXQInh2dsb2JhbACCPDWNSgEBAQgKKZIog1Q X-IronPort-AV: E=Sophos;i="4.25,331,1199660400"; d="scan'208";a="7146755" Received: from concorde.inria.fr ([192.93.2.39]) by mail2-smtp-roc.national.inria.fr with ESMTP; 11 Feb 2008 03:16:32 +0100 Received: from mail1-relais-roc.national.inria.fr (mail1-relais-roc.national.inria.fr [192.134.164.82]) by concorde.inria.fr (8.13.6/8.13.6) with ESMTP id m1B2GVVM015095 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=OK) for ; Mon, 11 Feb 2008 03:16:31 +0100 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AgAAAOs+r0fRVca6mGdsb2JhbACCPDWNSgEBAQEBBgQECQoYkiiDVQ X-IronPort-AV: E=Sophos;i="4.25,331,1199660400"; d="scan'208";a="7882035" Received: from rv-out-0910.google.com ([209.85.198.186]) by mail1-smtp-roc.national.inria.fr with ESMTP; 11 Feb 2008 03:16:27 +0100 Received: by rv-out-0910.google.com with SMTP id g11so2961408rvb.57 for ; Sun, 10 Feb 2008 18:16:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:message-id:date:from:reply-to:to:subject:cc:in-reply-to:mime-version:content-type:references; bh=kq7fPVnkeXsMwplOQQ4yaU4drv4mHE/LvbRLRlCJF60=; b=wPZTjPpBr4Z0an/yVvltI+hMIKekK+71Yqzl8K+568hELZxkLSOzmJLAvkcKgA5pRfzedBpGHS6WiTwjycMAO/wMNs8EGYzTKWPdKHkqap8kfxxqNoJkw+Am2gELpauWvFKA7+lRtLaHb58AegKjY2bWeHev28dII4/jquDZmxg= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:reply-to:to:subject:cc:in-reply-to:mime-version:content-type:references; b=j8k9jmGgI4KO+LMe51bRSrblcv3EYltwm9DWYJvxCykd2W9Th8L9pWNCPfUqiEG4OI/ZZGp4MqLmIzZah0ks+yuy4U4Nn/HgR1FuSc61erA9IYWavP/oyoArCvAxjJcciCSghMocXBo74AoTGiLNMBJCCwWFZ1xtLXt7kLzQJlA= Received: by 10.141.114.21 with SMTP id r21mr1562559rvm.154.1202696185661; Sun, 10 Feb 2008 18:16:25 -0800 (PST) Received: by 10.141.153.18 with HTTP; Sun, 10 Feb 2008 18:16:25 -0800 (PST) Message-ID: <891bd3390802101816r6812a574nc074abd67faf2039@mail.gmail.com> Date: Sun, 10 Feb 2008 21:16:25 -0500 From: "Yaron Minsky" Reply-To: yminsky@gmail.com To: "David Teller" Subject: Re: [Caml-list] [OSR] Exceptionless error management, take 2 Cc: OCaml In-Reply-To: <1202681123.6278.40.camel@Blefuscu> MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="----=_Part_3994_16502546.1202696185638" References: <1202396482.6084.5.camel@Blefuscu> <891bd3390802101047o187a94fch8f66a6c8a457d391@mail.gmail.com> <1202681123.6278.40.camel@Blefuscu> X-Miltered: at concorde with ID 47AFAFFF.000 by Joe's j-chkmail (http://j-chkmail . ensmp . fr)! X-Spam: no; 0.00; yaron:01 minsky:01 yminsky:01 univ-orleans:01 yaron:01 minsky:01 monadic:01 monadic:01 indirection:01 monads:01 univ-orleans:01 lifo:01 lifo:01 nomenclature:01 pipelines:01 ------=_Part_3994_16502546.1202696185638 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Disposition: inline On Feb 10, 2008 5:05 PM, David Teller wrote: > On Sun, 2008-02-10 at 13:47 -0500, Yaron Minsky wrote: > > A couple of quick thoughts about the proposal: > > * I don't understand the motivation behind separating out > > may_fail and status. In the case where no explicit error is > > returned, we're happy to return an ordinary option. Why not > > return a status when we want to return an error condition? And > > I don't understand the argument about wanting to delay > > evaluation until the function result is called. Why is that > > good, and if it's good, why do we still support functions that > > return options? The whole thing seems to add verbosity with > > little gain. > > I agree that this is the most arguable part of this recommendation > candidate. I introduced it because > * it makes possible to decide at a later stage between several > mechanisms for delivering errors from within libraries > * some of these mechanisms make possible to use fully monadic > exceptionless error management, without the usual high cost of fully > monadic exceptionless error management Unless I misunderstand (which is quite likely) you can do fully monadic error handling without this extra level of indirection. i.e.: let bind v f = match v with Error _ as x -> x | Ok y -> f y let return v = Ok v There you go, a fully-functioning monad. Or really a family of monads, since you basically get a distinct monad for each type of value in the error position. I really think we should get far enough in thinking this through to get a workable suggestion the first time, rather than add this extra bit of pervasive syntactic noise to allow for some possible future change later. > > I have put together three different implementations for such mechanisms > [1] and an example of fully monadic exceptionless error management [2]. > > [1] > > http://www.univ-orleans.fr/lifo/Members/David.Teller/software/exceptionless/exceptionless.ml > [2] > > http://www.univ-orleans.fr/lifo/Members/David.Teller/software/exceptionless/test_monad.ml > * > * > > * I think some attention on nomenclature is in order. In the > > libraries Jane Street uses, we have something similar to > > status (called "result"), but the type is "Ok of 'a | Error of > > 'b" rather than "Success of 'a | Error of 'b", simply for > > terseness. Also, having a function called "result" which > > converts a "may_fail" into a "status" seems like one name too > > many. I would call both the function and the type the same > > thing (either status or result). Unless, of course, you want > > to imply something material about the operation, in which case > > calling it "eval" or somesuch would make sense. > > Interesting question. You are correct that "eval" might make more sense > and I believe nobody would object to "Ok|Error" instead of "Success| > Error". If terseness is a concern, "Bad" might even make a shorter > replacement for "Error", although this would probably be harder to read. I wouldn't mind type ('a,'b) Result = Ok of 'a | Err of 'b. Bad seems, well, bad. > > * I don't understand why this proposal is only for functional > > data types. I didn't find the motivation given in the OSR for > > this convincing. I feel like the use of exceptions involves > > roughly the same tradeoffs when you're using imperative and > > functional code. If you have long functional pipelines, doing > > exception handling at each stage is a pain, much as it is if > > you do long sequences of imperative operations. That's why I > > think the goal should not be for the interfaces to be > > "exceptionless" so much as to make it easier to keep track of > > where exceptions might and might not be thrown, so that the > > reader of a piece of code knows where to stop and worry about > > exceptions. > > My intuition is that managing errors with ('a, 'b) status (or whatever > this name may become) is mostly functional in the first place. I have in > mind functions such as Unix.rename, which return nothing but may fail. > Without exceptions, one would need to stop at each step to check if no > error has occurred. > > Of course, we can handle this with monadic operators, just as we would > handle errors in functional code. I believe this monadic approach is as > close as we can get to having errors tracked by the type system without > requiring the user to handle them at each step along the road. > > Now, I admit that I usually write functional code, so input from people > dealing in imperative code in OCaml would be interesting. I really think the issue is the same for imperative or functional code. It's easy enough, even in an imperative version, to have a function like this: let throw = function Ok x -> x | Error e -> failwith e At least assuming that the thing inside the error is a string. It could also be an exception, which would then only need to be raised. I do think it would be helpful to have examples of libraries using these idioms. For what it's worth, in a few weeks we hope to release a version of Jane Street's standard library (which we call "core"), which has a bunch of examples of these kinds of error-handling patterns. One thing that's nice about our library is that it has actually been used in anger, and so we're pretty sure that the approaches we've taken are at least reasonably usable in practice. (As a side, note, I do think there is a lot of charm for using polymorphic variants for error cases. It's quite lightweight, and makes for very pleasant and explicit function signatures.) y > > > y > > Cheers, > David > -- > David Teller > Security of Distributed Systems > http://www.univ-orleans.fr/lifo/Members/David.Teller > Angry researcher: French Universities need reforms, but the LRU act > brings liquidations. > > ------=_Part_3994_16502546.1202696185638 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Disposition: inline On Feb 10, 2008 5:05 PM, David Teller <David.Teller@univ-orleans.fr> wrote:
On Sun, 2008-02-10 at 13:47 -0500, Yaron Minsky wrote:
> A couple of quick thoughts about the proposal:
>       * I don't understand the motivation behind separating out
>         may_fail and status.  In the case where no explicit error is
>         returned, we're happy to return an ordinary option.  Why not
>         return a status when we want to return an error condition? And
>         I don't understand the argument about wanting to delay
>         evaluation until the function result is called.  Why is that
>         good, and if it's good, why do we still support functions that
>         return options?  The whole thing seems to add verbosity with
>         little gain.

I agree that this is the most arguable part of this recommendation
candidate. I introduced it because
* it makes possible to decide at a later stage between several
mechanisms for delivering errors from within libraries
* some of these mechanisms make possible to use fully monadic
exceptionless error management, without the usual high cost of fully
monadic exceptionless error management

Unless I misunderstand (which is quite likely) you can do fully monadic error handling without this extra level of indirection.  i.e.:

let bind v f = match v with Error _ as x -> x | Ok y -> f y
let return v = Ok v

There you go, a fully-functioning monad.  Or really a family of monads, since you basically get a distinct monad for each type of value in the error position.

I really think we should get far enough in thinking this through to get a workable suggestion the first time, rather than add this extra bit of pervasive syntactic noise to allow for some possible future change later.
 

I have put together three different implementations for such mechanisms
[1] and an example of fully monadic exceptionless error management [2].

[1]
http://www.univ-orleans.fr/lifo/Members/David.Teller/software/exceptionless/exceptionless.ml
[2]
http://www.univ-orleans.fr/lifo/Members/David.Teller/software/exceptionless/test_monad.ml
     *
     *
>       * I think some attention on nomenclature is in order.  In the
>         libraries Jane Street uses, we have something similar to
>         status (called "result"), but the type is "Ok of 'a | Error of
>         'b" rather than "Success of 'a | Error of 'b", simply for
>         terseness.  Also, having a function called "result" which
>         converts a "may_fail" into a "status" seems like one name too
>         many.  I would call both the function and the type the same
>         thing (either status or result).  Unless, of course, you want
>         to imply something material about the operation, in which case
>         calling it "eval" or somesuch would make sense.

Interesting question. You are correct that "eval" might make more sense
and I believe nobody would object to "Ok|Error" instead of "Success|
Error". If terseness is a concern, "Bad" might even make a shorter
replacement for "Error", although this would probably be harder to read.

I wouldn't mind type ('a,'b) Result = Ok of 'a | Err of 'b.  Bad seems, well, bad.


>       * I don't understand why this proposal is only for functional
>         data types.  I didn't find the motivation given in the OSR for
>         this convincing.  I feel like the use of exceptions involves
>         roughly the same tradeoffs when you're using imperative and
>         functional code.  If you have long functional pipelines, doing
>         exception handling at each stage is a pain, much as it is if
>         you do long sequences of imperative operations.  That's why I
>         think the goal should not be for the interfaces to be
>         "exceptionless" so much as to make it easier to keep track of
>         where exceptions might and might not be thrown, so that the
>         reader of a piece of code knows where to stop and worry about
>         exceptions.

My intuition is that managing errors with ('a, 'b) status (or whatever
this name may become) is mostly functional in the first place. I have in
mind functions such as Unix.rename, which return nothing but may fail.
Without exceptions, one would need to stop at each step to check if no
error has occurred.

Of course, we can handle this with monadic operators, just as we would
handle errors in functional code. I believe this monadic approach is as
close as we can get to having errors tracked by the type system without
requiring the user to handle them at each step along the road.

Now, I admit that I usually write functional code, so input from people
dealing in imperative code in OCaml would be interesting.

I really think the issue is the same for imperative or functional code.  It's easy enough, even in an imperative version, to have a function like this:

let throw = function Ok x -> x | Error e -> failwith e

At least assuming that the thing inside the error is a string.  It could also be an exception, which would then only need to be raised.

I do think it would be helpful to have examples of libraries using these idioms.  For what it's worth, in a few weeks we hope to release a version of Jane Street's standard library (which we call "core"), which has a bunch of examples of these kinds of error-handling patterns.  One thing that's nice about our library is that it has actually been used in anger, and so we're pretty sure that the approaches we've taken are at least reasonably usable in practice.

(As a side, note, I do think there is a lot of charm for using polymorphic variants for error cases.  It's quite lightweight, and makes for very pleasant and explicit function signatures.)

y

 

> y

Cheers,
 David
--
David Teller
 Security of Distributed Systems
 http://www.univ-orleans.fr/lifo/Members/David.Teller
 Angry researcher: French Universities need reforms, but the LRU act brings liquidations.


------=_Part_3994_16502546.1202696185638--