From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Original-To: caml-list@sympa.inria.fr Delivered-To: caml-list@sympa.inria.fr Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by sympa.inria.fr (Postfix) with ESMTPS id BCDD47F8F4 for ; Tue, 27 May 2014 08:52:30 +0200 (CEST) Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of philippe.veber@gmail.com) identity=pra; client-ip=74.125.82.43; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="philippe.veber@gmail.com"; x-sender="philippe.veber@gmail.com"; x-conformance=sidf_compatible Received-SPF: Pass (mail2-smtp-roc.national.inria.fr: domain of philippe.veber@gmail.com designates 74.125.82.43 as permitted sender) identity=mailfrom; client-ip=74.125.82.43; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="philippe.veber@gmail.com"; x-sender="philippe.veber@gmail.com"; x-conformance=sidf_compatible; x-record-type="v=spf1" Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of postmaster@mail-wg0-f43.google.com) identity=helo; client-ip=74.125.82.43; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="philippe.veber@gmail.com"; x-sender="postmaster@mail-wg0-f43.google.com"; x-conformance=sidf_compatible X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AhYCAN01hFNKfVIrlGdsb2JhbABZhDGtR5RQAYEDCBYOAQEBAQcLCwkSKoIlAQEBAwESFRkBGx0BAwELBgULOyIBEQEFARwGEyKICwEDCQijFGqNGYMNmQIKGScNZIU2EQEFDIknhR8HhEABA5lzkTYYKYRqOw X-IPAS-Result: AhYCAN01hFNKfVIrlGdsb2JhbABZhDGtR5RQAYEDCBYOAQEBAQcLCwkSKoIlAQEBAwESFRkBGx0BAwELBgULOyIBEQEFARwGEyKICwEDCQijFGqNGYMNmQIKGScNZIU2EQEFDIknhR8HhEABA5lzkTYYKYRqOw X-IronPort-AV: E=Sophos;i="4.98,917,1392159600"; d="scan'208";a="76553539" Received: from mail-wg0-f43.google.com ([74.125.82.43]) by mail2-smtp-roc.national.inria.fr with ESMTP/TLS/RC4-SHA; 27 May 2014 08:52:28 +0200 Received: by mail-wg0-f43.google.com with SMTP id l18so8736456wgh.26 for ; Mon, 26 May 2014 23:52:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc:content-type; bh=wd3eTjObg2021ll3BTutePDqOFpBWjUqUoo2sTHf5Ss=; b=AHl569KWYGYW/WAd7DMLvuQORKRbkyqUOymIGdOi2Gbk3j+1VvtcnEBggCzOfl8ozU xzOJyKR7JBSng9GgK9Lras6OjYXhqCs3e9dRdJI4Oo+tsWJlNlxxDdSSwhdx89yYl4US +DcAY6XqOOL3Oqg9q83WYxx4iemy8AAfpdmAkFO9LYTcwTsfGR6qIU1by5ENeRTY3QX+ ux2L6XxQYRmekpzSlXsxs6sAxOGYVnBlNNuFGSHArTEz/NCm87FPtpcKFdVi/RWzryxU JMD2yAJVZjkvyRbw8X6O/rI0kxRVdW/lU3xcCekOOMxdc47iHf7ZS/bedZTCOSgusJtI Ve4Q== X-Received: by 10.180.105.72 with SMTP id gk8mr34452666wib.32.1401173547791; Mon, 26 May 2014 23:52:27 -0700 (PDT) MIME-Version: 1.0 Received: by 10.194.239.100 with HTTP; Mon, 26 May 2014 23:52:07 -0700 (PDT) In-Reply-To: <53B801AD6F5B4BFBA0DA2A69D8775497@erratique.ch> References: <53835610.9050609@inria.fr> <53B801AD6F5B4BFBA0DA2A69D8775497@erratique.ch> From: Philippe Veber Date: Tue, 27 May 2014 08:52:07 +0200 Message-ID: To: =?ISO-8859-1?Q?Daniel_B=FCnzli?= Cc: Ben Millwood , Romain Bardou , caml users Content-Type: multipart/alternative; boundary=f46d0442685a9695a404fa5c2382 X-Validation-by: philippe.veber@gmail.com Subject: Re: [Caml-list] Uncaught exceptions in function type. --f46d0442685a9695a404fa5c2382 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable 2014-05-26 18:34 GMT+02:00 Daniel B=FCnzli : > Le lundi, 26 mai 2014 =E0 18:02, Philippe Veber a =E9crit : > > Thanks! BTW core still uses exceptions. Is there an explicit rule as to > how to decide between Result type or exceptions. For instance, why not > write the Array.create function like this: > > > > val create : int -> 'a -> 'a array Or_error.t > > > > where create fails for a negative integer? > Because that would be utterly annoying. You need to make the following > distinctions: > > * Programming errors, for contracts with the programmer that cannot be > enforced through types. For that raises Invalid_argument if the contract = is > violated. Invalid_argument is not supposed to be handled, it denotes an A= PI > misuse, like calling Array.create with a negative integer. > > * Exceptional errors, for errors that the programmer is unlikely to handle > at all (e.g. out of memory). For that raise a custom exception. This shou= ld > occur very rarely, you are unlikely to ever define one such exception. > > * Non-exceptional errors, errors that the programmer will have to handle > (e.g. failing to connect a socket), for that do not use a custom exception > but use variants or options types. > > In general if you write libraries it's better to err on the side of > exceptionless design: never use exceptions beyond Invalid_argument (and > especially never use Not_found or Failure). Thanks Daniel, this is a useful summary. A couple of questions/remarks: - I observed in many libraries (including Xmlm) that people tend to define custom exceptions to signal parsing errors. According to the rules you provide, parsers should return variants, right? - as Ben noted earlier, I think point 2 would better be formulated as errors that can virtually appear anywhere and/or a programmer cannot do much about (as you say) - The adjective "exceptional" is a bit misleading IMO, in particular I guess it should not be understood as "not frequent". Rare failures can be very harmful and should be given extra-care since they are not easy to provoke and debug. Did you mean more like "very abnormal" and so difficult to recover? - Another criterion I like is that if checking the precondition of a function f basically amounts (in terms of complexity/algorithm) to calling f, then f shouldn't raise an exception for this precondition. If the precondition is difficult to check, a user is likely not to check it: - List.find assumes the searched element is in the list, but checking that is precisely what the function is about. - Connecting to a socket assumes it is up and available, but checking that without doing the connection is meaningless because you are not sure the socket will be available just after the check - in a parser you won't know if the input is syntactically correct before actually performing the parsing. > Leave exception definition/usage at the discretion of the user (if he > wishes to shoot himself in the foot). > Having no experience on large projects, it is not clear to me why exceptions are considered so dangerous. One point I see is that when you decide to handle errors with a try ... with expression, there is no exhaustivity check to ensure you handled all possible cases, and that you have to rely on (possibly incomplete) documentation and reasonning to convince yourself you forgot nothing. Another related one is that there is no automatic analysis to show exceptions thrown by a function in the documentation. These are of course already strong reasons why not to use too many exceptions (and were the motivation for my initial question). Do you see other reasons? Anyway, thanks everyone, this has been very informative to me! > Best, > > Daniel > > > --f46d0442685a9695a404fa5c2382 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable



2014-05-26 18:34 GMT+02:00 Daniel B=FCnzli <daniel.buenz= li@erratique.ch>:
Le lundi, 26 mai 2014 =E0= 18:02, Philippe Veber a =E9crit :
> Thanks! BTW core still uses exceptions. Is there an ex= plicit rule as to how to decide between Result type or exceptions. For inst= ance, why not write the Array.create function like this:
>
> val create : int -> 'a -> 'a array Or_error.t
>
> where create fails for a negative integer?
Because that would be utterly annoying. You need to make the followin= g distinctions:

* Programming errors, for contracts with the programmer that cannot be enfo= rced through types. For that raises Invalid_argument if the contract is vio= lated. Invalid_argument is not supposed to be handled, it denotes an API mi= suse, like calling Array.create with a negative integer.

* Exceptional errors, for errors that the programmer is unlikely to handle = at all (e.g. out of memory). For that raise a custom exception. This should= occur very rarely, you are unlikely to ever define one such exception.

* Non-exceptional errors, errors that the programmer will have to handle (e= .g. failing to connect a socket), for that do not use a custom exception bu= t use variants or options types.

In general if you write libraries it’s better to err on the side of e= xceptionless design: never use exceptions beyond Invalid_argument (and espe= cially never use Not_found or Failure).

Thanks Daniel= , this is a useful summary. A couple of questions/remarks:
- I observed in many libraries (including Xmlm) that people tend to=20 define custom exceptions to signal parsing errors. According to the=20 rules you provide, parsers should return variants, right?
- as Ben=20 noted earlier, I think point 2 would better be formulated as errors that can virtually appear anywhere and/or a programmer cannot do much about=20 (as you say)
- The adjective "exceptional" is a bit misleading= IMO, in particular I guess it should not be understood as "not freque= nt". Rare failures can be very harmful and should be given extra-care = since they are not easy to provoke and debug. Did you mean more like "= very abnormal" and so difficult to recover?
- Another criterion I like is that if checking the precondition of a function f basically amounts (in terms of complexity/algorithm) to calling f, then f shouldn't raise an exception for this precondition. = If the precondition is difficult to check, a user=20 is likely not to check it:
    - List.find assumes the searche= d element is in the list, but checking that is precisely what the function = is about.
    - Connecting to a socket assumes it is up and available, but checking=20 that without doing the connection is meaningless because you are not=20 sure the socket will be available just after the check
   = ; - in a parser you won't know if the input is syntactically correct be= fore actually performing the parsing.

 
Leave exception definition/usage at the discretion of the user (if he wishe= s to shoot himself in the foot).

Having no experie= nce on large projects, it is not clear to me why exceptions are considered = so dangerous. One point I see is that when you decide to handle errors with= a try ... with expression, there is no exhaustivity check to ensure you ha= ndled all possible cases, and that you have to rely on (possibly incomplete= ) documentation and reasonning to convince yourself you forgot nothing. Ano= ther related one is that there is no automatic analysis to show exceptions = thrown by a function in the documentation. These are of course already stro= ng reasons why not to use too many exceptions (and were the motivation for = my initial question). Do you see other reasons?

 Anyway, thanks everyone, this has been very informative to me!

Best,

Daniel



--f46d0442685a9695a404fa5c2382--