* Re: [Caml-list] Uncaught exceptions in function type.
2014-05-26 16:34 ` Daniel Bünzli
@ 2014-05-27 6:52 ` Philippe Veber
2014-05-27 8:42 ` Ben Millwood
2014-05-27 21:16 ` Daniel Bünzli
2014-05-27 8:49 ` Goswin von Brederlow
` (2 subsequent siblings)
3 siblings, 2 replies; 28+ messages in thread
From: Philippe Veber @ 2014-05-27 6:52 UTC (permalink / raw)
To: Daniel Bünzli; +Cc: Ben Millwood, Romain Bardou, caml users
[-- Attachment #1: Type: text/plain, Size: 3829 bytes --]
2014-05-26 18:34 GMT+02:00 Daniel Bünzli <daniel.buenzli@erratique.ch>:
> Le lundi, 26 mai 2014 à 18:02, Philippe Veber a écrit :
> > 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 API
> 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 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
> 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
>
>
>
[-- Attachment #2: Type: text/html, Size: 4647 bytes --]
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Caml-list] Uncaught exceptions in function type.
2014-05-27 6:52 ` Philippe Veber
@ 2014-05-27 8:42 ` Ben Millwood
2014-05-27 10:05 ` Goswin von Brederlow
2014-05-27 21:42 ` Daniel Bünzli
2014-05-27 21:16 ` Daniel Bünzli
1 sibling, 2 replies; 28+ messages in thread
From: Ben Millwood @ 2014-05-27 8:42 UTC (permalink / raw)
To: Philippe Veber; +Cc: Daniel Bünzli, Romain Bardou, caml users
[-- Attachment #1: Type: text/plain, Size: 3770 bytes --]
On 26 May 2014 17:02, Philippe Veber <philippe.veber@gmail.com> wrote:
>
> Using options or Result from time to time is certainly a nice habit.
> However to be honest, using option/result monads extensively does not seem
> right to me, like pulling the language in a direction it was not really
> designed for. Monad combinators do a great job at propagating errors, but
> still there is a serious addition of plumbing in function body's and Result
> returning functions have a significantly less readable type. But I guess
> this is pretty much a question of taste/habit to see if the added verbosity
> is worth it.
>
It's true that using a monadic style does introduce *some* noise, but I
don't think it's so bad, especially if you design your API to fit with the
style. In a way I almost prefer having the binds there so that I can easily
see where the possible interruption points in the flow are, and in
particular it's /syntactically/ obvious where errors /can't/ occur.
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?
>
Daniel's summary is very good, although we do use Failure in Core, often
for assertion-failure like scenarios or just any case where the error isn't
meant to be handled specifically. In many cases Invalid_argument would
arguably be more appropriate, but in other cases that isn't obvious (say if
you mutate a Queue.t while you are folding over it, that will be detected
and an error will be thrown, but it isn't /really/ an invalid argument
error), and in any case since we often don't intend to catch them except to
print a stack trace and die, it doesn't matter too much.
We also do just break our own rules sometimes. Possible reasons why are:
- some aspect of usability takes priority over dogmatics (although this is
much rarer than you'd think)
- legacy exceptions (see below)
- sometimes we make bad decisions :(
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?
>
One particularly galling aspect of exceptions not showing up in types is
that they can't easily be refactored. If you decide to change which
exceptions a given function throws, you can't rely on the typechecker to
flag up where code was written to the old specification and needs changing.
You can't even just eyeball the code to see where the function was used and
see if the exception was caught, because who knows where in the call stack
it might have been handled? Explicit error types, on the other hand, will
refuse to compile unless you have changed your code to deal with it, so you
can make your errors richer or more precise with a high level of confidence
that you haven't introduced any "holes" for exceptional conditions to sneak
out where previously they couldn't.
This is essentially why we still have a few Not_found exceptions in Core,
because it's really pretty hard to know where they might be relied upon, so
it's easier to leave them in than purge them and risk silent breakage.
[-- Attachment #2: Type: text/html, Size: 4865 bytes --]
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Caml-list] Uncaught exceptions in function type.
2014-05-27 8:42 ` Ben Millwood
@ 2014-05-27 10:05 ` Goswin von Brederlow
2014-05-27 10:36 ` Ben Millwood
2014-05-27 21:42 ` Daniel Bünzli
1 sibling, 1 reply; 28+ messages in thread
From: Goswin von Brederlow @ 2014-05-27 10:05 UTC (permalink / raw)
To: caml-list
On Tue, May 27, 2014 at 09:42:35AM +0100, Ben Millwood wrote:
> One particularly galling aspect of exceptions not showing up in types is
> that they can't easily be refactored. If you decide to change which
> exceptions a given function throws, you can't rely on the typechecker to
> flag up where code was written to the old specification and needs changing.
> You can't even just eyeball the code to see where the function was used and
> see if the exception was caught, because who knows where in the call stack
> it might have been handled? Explicit error types, on the other hand, will
> refuse to compile unless you have changed your code to deal with it, so you
> can make your errors richer or more precise with a high level of confidence
> that you haven't introduced any "holes" for exceptional conditions to sneak
> out where previously they couldn't.
>
> This is essentially why we still have a few Not_found exceptions in Core,
> because it's really pretty hard to know where they might be relied upon, so
> it's easier to leave them in than purge them and risk silent breakage.
HUH?
Say you have a function
val f : ('a, 'b) t -> 'a -> 'b (raise [Not_found])
then eliminating Not_found that function would become
val f : ('a, 'b) t -> 'a -> 'b option
That should fail to compile if the return type is used or a signature
exists. Where do you think a change would go unnoticed?
MfG
Goswin
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Caml-list] Uncaught exceptions in function type.
2014-05-27 10:05 ` Goswin von Brederlow
@ 2014-05-27 10:36 ` Ben Millwood
2014-05-27 11:24 ` Yaron Minsky
0 siblings, 1 reply; 28+ messages in thread
From: Ben Millwood @ 2014-05-27 10:36 UTC (permalink / raw)
To: Goswin von Brederlow; +Cc: caml users
[-- Attachment #1: Type: text/plain, Size: 1137 bytes --]
On 27 May 2014 11:05, Goswin von Brederlow <goswin-v-b@web.de> wrote:
> On Tue, May 27, 2014 at 09:42:35AM +0100, Ben Millwood wrote:
> > This is essentially why we still have a few Not_found exceptions in Core,
> > because it's really pretty hard to know where they might be relied upon,
> so
> > it's easier to leave them in than purge them and risk silent breakage.
>
> HUH?
>
> Say you have a function
>
> val f : ('a, 'b) t -> 'a -> 'b (raise [Not_found])
>
> then eliminating Not_found that function would become
>
> val f : ('a, 'b) t -> 'a -> 'b option
>
> That should fail to compile if the return type is used or a signature
> exists. Where do you think a change would go unnoticed?
>
> MfG
> Goswin
>
I really mean where we'd like to change Not_found to a more informative or
appropriate exception. Sorry, I forgot about one case where we are
completely fine with using exceptions: in (usually short-lived) programs
where the correct behaviour on error is always to explode apologetically
right there and then. The choice of exception is still relevant because it
affects the quality of the backtrace and message.
[-- Attachment #2: Type: text/html, Size: 1665 bytes --]
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Caml-list] Uncaught exceptions in function type.
2014-05-27 10:36 ` Ben Millwood
@ 2014-05-27 11:24 ` Yaron Minsky
0 siblings, 0 replies; 28+ messages in thread
From: Yaron Minsky @ 2014-05-27 11:24 UTC (permalink / raw)
To: Ben Millwood; +Cc: Goswin von Brederlow, caml users
You shouldn't take Ben's comments to indicate that we don't ever throw
exceptions. We have lots of functions whose names are explicit about
the fact that they throw exceptions, like Map.find_exn or
List.last_exn. They have legitimate uses, for example, in contexts
where you've checked that the precondition for that function to not
throw an exception, and so it would simply be a bug if it were thrown.
In those cases, it is indeed hard to change the specific exception
that is thrown without potentially breaking external code that depends
on it.
That's why in new modules, are usual behavior is to not expose the
concrete exceptions we declare in the mli of our modules, on the
theory that we don't want users of the module to depend on the
identity of an exception.
y
On Tue, May 27, 2014 at 6:36 AM, Ben Millwood <bmillwood@janestreet.com> wrote:
> On 27 May 2014 11:05, Goswin von Brederlow <goswin-v-b@web.de> wrote:
>>
>> On Tue, May 27, 2014 at 09:42:35AM +0100, Ben Millwood wrote:
>> > This is essentially why we still have a few Not_found exceptions in
>> > Core,
>> > because it's really pretty hard to know where they might be relied upon,
>> > so
>> > it's easier to leave them in than purge them and risk silent breakage.
>>
>> HUH?
>>
>> Say you have a function
>>
>> val f : ('a, 'b) t -> 'a -> 'b (raise [Not_found])
>>
>> then eliminating Not_found that function would become
>>
>> val f : ('a, 'b) t -> 'a -> 'b option
>>
>> That should fail to compile if the return type is used or a signature
>> exists. Where do you think a change would go unnoticed?
>>
>> MfG
>> Goswin
>
>
> I really mean where we'd like to change Not_found to a more informative or
> appropriate exception. Sorry, I forgot about one case where we are
> completely fine with using exceptions: in (usually short-lived) programs
> where the correct behaviour on error is always to explode apologetically
> right there and then. The choice of exception is still relevant because it
> affects the quality of the backtrace and message.
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Caml-list] Uncaught exceptions in function type.
2014-05-27 8:42 ` Ben Millwood
2014-05-27 10:05 ` Goswin von Brederlow
@ 2014-05-27 21:42 ` Daniel Bünzli
1 sibling, 0 replies; 28+ messages in thread
From: Daniel Bünzli @ 2014-05-27 21:42 UTC (permalink / raw)
To: Ben Millwood; +Cc: Philippe Veber, Romain Bardou, caml users
Le mardi, 27 mai 2014 à 10:42, Ben Millwood a écrit :
> but in other cases that isn't obvious (say if you mutate a Queue.t while you are folding over it, that will be detected and an error will be thrown, but it isn't /really/ an invalid argument error),
Why not ? If you document (but yes, you have to write documentation…) that the folding function must not mutate the queue it is folding over, a function that does that is an invalid argument.
Best,
Daniel
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Caml-list] Uncaught exceptions in function type.
2014-05-27 6:52 ` Philippe Veber
2014-05-27 8:42 ` Ben Millwood
@ 2014-05-27 21:16 ` Daniel Bünzli
2014-06-02 8:38 ` Goswin von Brederlow
1 sibling, 1 reply; 28+ messages in thread
From: Daniel Bünzli @ 2014-05-27 21:16 UTC (permalink / raw)
To: Philippe Veber; +Cc: Ben Millwood, Romain Bardou, caml users
Le mardi, 27 mai 2014 à 08:52, Philippe Veber a écrit :
> - 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?
Yes, I was unexeperienced. Also I didn’t understand that the world was asynchronous at that time. See jsonm for a more sensitive interface.
> - 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?
Well all what you mention seems exceptional to me (at least I wouldn’t like to work with an API that allows errors to virtually happen everywhere on a regular basis)… But feel free to call that differently.
> - 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.
Yes, note that finding things in datastructures is pretty clear API wise. Usually there are two cases 1) the programmer doesn’t if the item is in the datastructure 2) the programmer knows it’s in there and doesn’t want to be annoyed. This leads to
1) val find : t -> key -> value option
2) val get : t -> key -> value (and raises Invalid_argument if the thing is not in there).
> Having no experience on large projects, it is not clear to me why exceptions are considered so dangerous.
If you don’t/forget to catch the exception at the right place it disrupts your whole call stack, which means that it breaks any invariants a correct excecution of your call stack was supposed to maintain. Which means that your program state is completely broken and you have to exit 1, hoping that you didn’t partially (invariant wise) persist anything to disk/network meanwhile.
Best,
Daniel
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Caml-list] Uncaught exceptions in function type.
2014-05-27 21:16 ` Daniel Bünzli
@ 2014-06-02 8:38 ` Goswin von Brederlow
0 siblings, 0 replies; 28+ messages in thread
From: Goswin von Brederlow @ 2014-06-02 8:38 UTC (permalink / raw)
To: caml-list
On Tue, May 27, 2014 at 11:16:18PM +0200, Daniel Bünzli wrote:
> Le mardi, 27 mai 2014 à 08:52, Philippe Veber a écrit :
> > Having no experience on large projects, it is not clear to me why
> > exceptions are considered so dangerous.
>
> If you don???t/forget to catch the exception at the right place it
> disrupts your whole call stack, which means that it breaks any
> invariants a correct excecution of your call stack was supposed to
> maintain. Which means that your program state is completely broken and
> you have to exit 1, hoping that you didn???t partially (invariant
> wise) persist anything to disk/network meanwhile.
>
> Best,
>
> Daniel
Which is where tracking exceptions in the type of a functions would
come in handy. If you write code that must not be aborted then you
annotate the type to throw no exceptions. The type inference would
then check that that is the case and give you a compile error
otherwise. That way there couldn't be any surprises of an exception
breaking your call stack.
Also note, even though YOU don't use exceptions doesn't mean some
module you use doesn't. With exception part of a functions type this
would be exposed in the interface and you can deal with it accordingly
(worst case rewrite the module :).
So I think you should be all for having exceptions in the type
especially because you don't like them.
MfG
Goswin
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Caml-list] Uncaught exceptions in function type.
2014-05-26 16:34 ` Daniel Bünzli
2014-05-27 6:52 ` Philippe Veber
@ 2014-05-27 8:49 ` Goswin von Brederlow
2014-05-27 8:56 ` David House
2014-05-27 21:39 ` Daniel Bünzli
2014-05-27 9:25 ` Nicolas Boulay
2014-05-30 18:03 ` Florian Weimer
3 siblings, 2 replies; 28+ messages in thread
From: Goswin von Brederlow @ 2014-05-27 8:49 UTC (permalink / raw)
To: caml-list
On Mon, May 26, 2014 at 06:34:33PM +0200, Daniel Bünzli wrote:
> Le lundi, 26 mai 2014 à 18:02, Philippe Veber a écrit :
> > 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 API misuse, like calling Array.create with a negative
> integer.
Sometimes arguments are computed and suddenly exceed aceptable
parameters. E.g. the user specifies a data file that needs to be read
into a string. If the file is too large you get Invalid_argument.
Programms can catch and handle such cases, at least to the point of
giving a good error message.
Idealy a program should catch all exceptions and explain in a human
readable way why they happened.
> * 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.
Out of memory is probably the only exception you can't do anything
about in ocaml. Catching and handling it would nearly always need more
ram causing just another Ouf_of_memory exception. In ocaml you are
pretty much screwed.
> * 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.
That is a matter of taste and with recursions in the mix exceptions
can be a great way to abort the recursion while keeping the code flow
simple. They also allow you to use things like List.fold_left and
abort early.
Variants or option types are not always the best solution.
> 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). Leave exception
> definition/usage at the discretion of the user (if he wishes to shoot
> himself in the foot).
>
> Best,
>
> Daniel
MfG
Goswin
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Caml-list] Uncaught exceptions in function type.
2014-05-27 8:49 ` Goswin von Brederlow
@ 2014-05-27 8:56 ` David House
2014-05-27 21:39 ` Daniel Bünzli
1 sibling, 0 replies; 28+ messages in thread
From: David House @ 2014-05-27 8:56 UTC (permalink / raw)
To: Goswin von Brederlow; +Cc: OCaml Mailing List
[-- Attachment #1: Type: text/plain, Size: 1745 bytes --]
On 27 May 2014 09:49, Goswin von Brederlow <goswin-v-b@web.de> wrote:
> > * 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.
>
> That is a matter of taste and with recursions in the mix exceptions
> can be a great way to abort the recursion while keeping the code flow
> simple. They also allow you to use things like List.fold_left and
> abort early.
>
See https://blogs.janestreet.com/core-gems-many-happy-returns/ for how we
solve this problem in core. The interface is very natural. It uses
exceptions under the hood, although that is not exposed.
However, I think this is entirely separate from the rest of the discussion.
Here we are merely using exceptions for their control flow properties --
there is no error condition.
> Variants or option types are not always the best solution.
>
That's certainly true, although I would argue that exceptions are certainly
overused. We use them quite a bit in core and in the rest of JS's codebase
-- but only for truly "exceptional" circumstances.
> > 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). Leave exception
> > definition/usage at the discretion of the user (if he wishes to shoot
> > himself in the foot).
> >
> > Best,
> >
> > Daniel
>
> MfG
> Goswin
>
> --
> Caml-list mailing list. Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>
[-- Attachment #2: Type: text/html, Size: 3134 bytes --]
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Caml-list] Uncaught exceptions in function type.
2014-05-27 8:49 ` Goswin von Brederlow
2014-05-27 8:56 ` David House
@ 2014-05-27 21:39 ` Daniel Bünzli
2014-06-02 8:31 ` Goswin von Brederlow
1 sibling, 1 reply; 28+ messages in thread
From: Daniel Bünzli @ 2014-05-27 21:39 UTC (permalink / raw)
To: Goswin von Brederlow; +Cc: caml-list
Le mardi, 27 mai 2014 à 10:49, Goswin von Brederlow a écrit :
> Sometimes arguments are computed and suddenly exceed aceptable
> parameters. E.g. the user specifies a data file that needs to be read
> into a string. If the file is too large you get Invalid_argument.
> Programms can catch and handle such cases, at least to the point of
> giving a good error message.
Bad api. Neither exceptional error, neither programming error, *should* not raise Invalid_argument, of course you’ll have to handle it but don't forget to send hate emails to the API designer.
> That is a matter of taste and with recursions in the mix exceptions
> can be a great way to abort the recursion while keeping the code flow
> simple. They also allow you to use things like List.fold_left and
> abort early.
It’s not a matter of taste. What you are describing here is usage of exceptions by a programmer that wants to shoot himself in the foot. Libraries themselves should never disrupt the control flow of clients.
Best,
Daniel
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Caml-list] Uncaught exceptions in function type.
2014-05-27 21:39 ` Daniel Bünzli
@ 2014-06-02 8:31 ` Goswin von Brederlow
0 siblings, 0 replies; 28+ messages in thread
From: Goswin von Brederlow @ 2014-06-02 8:31 UTC (permalink / raw)
To: caml-list
On Tue, May 27, 2014 at 11:39:20PM +0200, Daniel Bünzli wrote:
> Le mardi, 27 mai 2014 à 10:49, Goswin von Brederlow a écrit :
> > Sometimes arguments are computed and suddenly exceed aceptable
> > parameters. E.g. the user specifies a data file that needs to be read
> > into a string. If the file is too large you get Invalid_argument.
> > Programms can catch and handle such cases, at least to the point of
> > giving a good error message.
>
>
> Bad api. Neither exceptional error, neither programming error, *should* not raise Invalid_argument, of course you???ll have to handle it but don't forget to send hate emails to the API designer.
>
> > That is a matter of taste and with recursions in the mix exceptions
> > can be a great way to abort the recursion while keeping the code flow
> > simple. They also allow you to use things like List.fold_left and
> > abort early.
>
> It???s not a matter of taste. What you are describing here is usage of exceptions by a programmer that wants to shoot himself in the foot. Libraries themselves should never disrupt the control flow of clients.
>
> Best,
>
> Daniel
Who said anything about disrupting the codeflow of clients?
The use case is like
exception Result of int
let find_less_than x list =
try
List.iter (fun y -> if x > y then raise (Result y)) list;
None
with Result y -> Some y
# find_less_than 10 [100; 23; 3; 42; 17];;
- : int option = Some 3
You hrow the exception internally and catch it internally. Nothing of
the clients gets disruppted.
Obviously this is a constructed simplistic example. But in more
complex code an exception can be far more readable than 50 ifs and
checks of None/Some all over the place.
MfG
Goswin
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Caml-list] Uncaught exceptions in function type.
2014-05-26 16:34 ` Daniel Bünzli
2014-05-27 6:52 ` Philippe Veber
2014-05-27 8:49 ` Goswin von Brederlow
@ 2014-05-27 9:25 ` Nicolas Boulay
2014-05-27 21:51 ` Daniel Bünzli
2014-05-30 18:03 ` Florian Weimer
3 siblings, 1 reply; 28+ messages in thread
From: Nicolas Boulay @ 2014-05-27 9:25 UTC (permalink / raw)
To: Daniel Bünzli
Cc: Philippe Veber, Ben Millwood, Romain Bardou, caml users
[-- Attachment #1: Type: text/plain, Size: 2456 bytes --]
2014-05-26 18:34 GMT+02:00 Daniel Bünzli <daniel.buenzli@erratique.ch>:
> Le lundi, 26 mai 2014 à 18:02, Philippe Veber a écrit :
> > 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:
>
>
Yes it could be annoying, but very high quality software become much harder
to write. Refactoring is harder. Missing exception handler are harder to
find.
> * 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 API
> 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 should
> occur very rarely, you are unlikely to ever define one such exception.
>
> That means intensive testing to be sur to avoid such failure for normal
user input. For most long running programme (server, gui), that's could a
problem.
For example, an undo/redo use lot of memory after some copy/paste on big
data, then the save command have not enough memory to work, and the file
are troncated. That's not acceptable, and can be see only with big data,
after few high level command run.
Regards,
Nicolas
> * 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). Leave exception
> definition/usage at the discretion of the user (if he wishes to shoot
> himself in the foot).
>
> Best,
>
> Daniel
>
>
>
> --
> Caml-list mailing list. Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>
[-- Attachment #2: Type: text/html, Size: 3741 bytes --]
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Caml-list] Uncaught exceptions in function type.
2014-05-27 9:25 ` Nicolas Boulay
@ 2014-05-27 21:51 ` Daniel Bünzli
0 siblings, 0 replies; 28+ messages in thread
From: Daniel Bünzli @ 2014-05-27 21:51 UTC (permalink / raw)
To: Nicolas Boulay; +Cc: Philippe Veber, Ben Millwood, Romain Bardou, caml users
Le mardi, 27 mai 2014 à 11:25, Nicolas Boulay a écrit :
> > Because that would be utterly annoying. You need to make the following distinctions:
>
> Yes it could be annoying, but very high quality software become much harder to write. Refactoring is harder. Missing exception handler are harder to find.
That’s non sense. What would the programmer do if Array.create wouldn’t raise in case of invalid argument 99.9999999% of the code would read like this:
let a = match Array.create n with
| None -> assert false
| Some a -> a
in
You solved absolutely nothing by having an option type here. But you did manage to be annoying.
>
> > * 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.
>
> That means intensive testing to be sur to avoid such failure for normal user input. For most long running programme (server, gui), that's could a problem.
>
> For example, an undo/redo use lot of memory after some copy/paste on big data, then the save command have not enough memory to work, and the file are troncated. That's not acceptable, and can be see only with big data, after few high level command run.
That is certainly not something you want to solve by handling exceptions but by making sure/designing your program is able to function under a given fixed memory budget (if only to be able to test the error condition).
Best,
Daniel
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Caml-list] Uncaught exceptions in function type.
2014-05-26 16:34 ` Daniel Bünzli
` (2 preceding siblings ...)
2014-05-27 9:25 ` Nicolas Boulay
@ 2014-05-30 18:03 ` Florian Weimer
2014-05-31 11:26 ` Daniel Bünzli
3 siblings, 1 reply; 28+ messages in thread
From: Florian Weimer @ 2014-05-30 18:03 UTC (permalink / raw)
To: Daniel Bünzli
Cc: Philippe Veber, Ben Millwood, Romain Bardou, caml users
* Daniel Bünzli:
> * 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 some cases this introduces allocations even for the success case,
and exception-based design avoids that.
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Caml-list] Uncaught exceptions in function type.
2014-05-30 18:03 ` Florian Weimer
@ 2014-05-31 11:26 ` Daniel Bünzli
2014-06-02 8:43 ` Goswin von Brederlow
0 siblings, 1 reply; 28+ messages in thread
From: Daniel Bünzli @ 2014-05-31 11:26 UTC (permalink / raw)
To: Florian Weimer; +Cc: Philippe Veber, Ben Millwood, Romain Bardou, caml users
Le vendredi, 30 mai 2014 à 20:03, Florian Weimer a écrit :
> * Daniel Bünzli:
>
> > * 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 some cases this introduces allocations even for the success case,
> and exception-based design avoids that.
Exception handlers have their cost too.
Daniel
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Caml-list] Uncaught exceptions in function type.
2014-05-31 11:26 ` Daniel Bünzli
@ 2014-06-02 8:43 ` Goswin von Brederlow
0 siblings, 0 replies; 28+ messages in thread
From: Goswin von Brederlow @ 2014-06-02 8:43 UTC (permalink / raw)
To: caml-list
> Le vendredi, 30 mai 2014 à 20:03, Florian Weimer a écrit :
>
> > * Daniel Bünzli:
> >
> > > * 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 some cases this introduces allocations even for the success case,
> > and exception-based design avoids that.
Doesn't success with option types always introduce an allocation? Some
x is a block and wants to be created. Worse if you constantly unpack
and repack the option.
^ permalink raw reply [flat|nested] 28+ messages in thread