* [Caml-list] Exceptions considered harmful
[not found] ` <20040628173400.GB26193@fichte.ai.univie.ac.at>
@ 2004-06-29 1:02 ` skaller
2004-07-04 7:30 ` Lauri Alanko
2004-07-11 13:12 ` [Caml-list] " Richard Cole
0 siblings, 2 replies; 7+ messages in thread
From: skaller @ 2004-06-29 1:02 UTC (permalink / raw)
To: extlib; +Cc: caml-list
On Tue, 2004-06-29 at 03:34, Markus Mottl wrote:
> On Tue, 29 Jun 2004, Martin Jambon wrote:
> > This makes me feel like we will not know if the "finally block" has been
> > completed or not. Why not totally prohibiting any exception raised from
> > the "finally block"?
> >
> > let protect f x finally =
> > let res =
> > try f x
> > with exc ->
> > (try finally x with _ -> invalid_arg "protect")
> > raise exc in
> > (try finally x with _ -> invalid_arg "protect");
> > res
>
> But how do you know then that the exception came from "finally" and not
> from "f"? You could even lose the information, whether "f" was executed
> successfully at all!
In general, I think exceptions are a bad idea.
I spend a lot of time removing them from my code :(
In a typical case it goes like this:
try
let f = open_in fname in
do_something f;
close_in f
with _ -> ()
Only this is very BAD code because it fails to isolate
two completely distinct possibilities for an error:
in opening the file, or in processing it: in the latter
case the file isn't closed: we didn't actually
expected a processing error here, and also fail to
correctly re-raise the exception.
This lack of localisation is quite hard to fix:
let f = try open_in fname with _ -> () in
do_something f;
close_in f
WOOPS! that's a type error, which is good, because
we can't 'do_something' if the file wasn't opened.
What else can we try?
try
let f = open_in fname in
begin
try do_something f
with _ -> close_in f
end;
close_in f;
with _ -> failwith "Do something failed"
WOOPS, we tried to close f twice. We can only do this:
exception Some_error
try
let f = open_in fname in
begin
try do_something f
with _ -> close_in f; raise Some_error
end;
close_in f;
with Some_error -> raise Some_error
| _ -> ()
but now we have lost the location and kind of the
error in something .. and we had to introduce a new
global exception as well.
The obvious way to fix this mess is to eliminate the
undesirable exceptions early:
let result =
try Some (open_in fname) with _ -> None
in match result with
| None -> ()
| Some f ->
begin try do_something with x -> close_in f; raise x end
close_in f
Of course, the result of the calculation here is unit,
more generally we'd be saying
let result = do_something in close_in f; result
and obviously we'd be wrapping that as well.
Generally, the exceptions discard localisation
and destroy any kind of static assurance errors are handled.
To me, the Haskell monadic approach seems a sounder.
The problem with exceptions is that they're basically
without solid theoretical principles. Throwing out
context is one thing .. recovering at an unknown
point, trapping unknown exceptions without any
aid from the type system simply defeats the purpose
of having a type system.
As far as I can see, just about the only way to
use exceptions properly is to eliminate them
at the earliest possible point .. which suggests
libraries simply shouldn't throw them.
It seems difficult to escape from deep recursions
without exceptions. They can be convenient.
They're useful for rapid prototyping where you
need a demo that works on some cases *fast*.
And they seem convenient when you 'know' there
can't be an error. The price is high. In avoiding
statically handling false negatives (errors that
can't occur) your code has become fragile: any change
which may in fact lead to raising an error will
not be discovered without testing.. and then it
will be very hard to find.
Would static exceptions be better? (Allow exceptions
but require that they're caught in an ancestor of the
scope they're raised in, and at least in a child of
the scope the exception is declared in)
Any comments on any of this appreciated.
--
John Skaller, mailto:skaller@users.sf.net
voice: 061-2-9660-0850,
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net
-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Caml-list] Exceptions considered harmful
2004-06-29 1:02 ` [Caml-list] Exceptions considered harmful skaller
@ 2004-07-04 7:30 ` Lauri Alanko
2004-07-04 20:16 ` Christophe TROESTLER
2004-07-04 20:24 ` Michael Hicks
2004-07-11 13:12 ` [Caml-list] " Richard Cole
1 sibling, 2 replies; 7+ messages in thread
From: Lauri Alanko @ 2004-07-04 7:30 UTC (permalink / raw)
To: caml-list
On Tue, Jun 29, 2004 at 11:02:49AM +1000, skaller wrote:
> Any comments on any of this appreciated.
The paper "Exceptional Syntax" by Nick Benton and Andrew Kennedy would
probably interest you. It's published in JFP 11(4), 2001, and an
electronic copy can probably be found somewhere in the net. They propose
an exception syntax that is closer to Haskell's monadic style: an
expression either returns a value or raises an exception, so catching an
exception is like pattern matching: there's one case for the returned
value, others for possible exceptions:
try
x <- foo ()
in
bar ()
unless
E1 -> handle1 ()
E2 -> handle2 ()
To my mind this seems very sensible.
Lauri Alanko
la@iki.fi
-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Caml-list] Exceptions considered harmful
2004-07-04 7:30 ` Lauri Alanko
@ 2004-07-04 20:16 ` Christophe TROESTLER
2004-07-04 20:24 ` Michael Hicks
1 sibling, 0 replies; 7+ messages in thread
From: Christophe TROESTLER @ 2004-07-04 20:16 UTC (permalink / raw)
To: la; +Cc: O'Caml Mailing List
On Sun, 4 Jul 2004, Lauri Alanko <la@iki.fi> wrote:
>
> an exception syntax that is closer to Haskell's monadic style: an
> expression either returns a value or raises an exception, so
> catching an exception is like pattern matching: there's one case for
> the returned value, others for possible exceptions:
>
> try
> x <- foo ()
> in
> bar ()
> unless
> E1 -> handle1 ()
> E2 -> handle2 ()
How is this sensibly different from OCaml' syntax?
try
x <- foo();
bar()
with
| E1 -> handle1()
| E2 -> handle2()
ChriS
-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Caml-list] Exceptions considered harmful
2004-07-04 7:30 ` Lauri Alanko
2004-07-04 20:16 ` Christophe TROESTLER
@ 2004-07-04 20:24 ` Michael Hicks
2004-07-05 3:42 ` skaller
1 sibling, 1 reply; 7+ messages in thread
From: Michael Hicks @ 2004-07-04 20:24 UTC (permalink / raw)
To: Lauri Alanko; +Cc: caml-list
> try
> x <- foo ()
> in
> bar ()
> unless
> E1 -> handle1 ()
> E2 -> handle2 ()
The key part to this approach is that bar() is not covered by the
exception handler. This allows the caller to communicate the
successfully created value into bar() through x. In a traditional
setting, you'd have something like
let x := NONE;
try
x := SOME foo();
with E1 -> ....
if !x <> NONE then bar !x
else ??
Mike
-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Caml-list] Exceptions considered harmful
2004-07-04 20:24 ` Michael Hicks
@ 2004-07-05 3:42 ` skaller
0 siblings, 0 replies; 7+ messages in thread
From: skaller @ 2004-07-05 3:42 UTC (permalink / raw)
To: Michael Hicks; +Cc: Lauri Alanko, caml-list
On Mon, 2004-07-05 at 06:24, Michael Hicks wrote:
> > try
> > x <- foo ()
> > in
> > bar ()
> > unless
> > E1 -> handle1 ()
> > E2 -> handle2 ()
>
> The key part to this approach is that bar() is not covered by the
> exception handler.
Yeah, this is just an extension of let/in:
let x = foo () in bar () unless ...
however it is still dynamic = statically insecure =
unable to reason about the code locally = bad,
however increased localisation is obtained:
you have more idea where the exception came from
so this does seem better.
--
John Skaller, mailto:skaller@users.sf.net
voice: 061-2-9660-0850,
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net
-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
^ permalink raw reply [flat|nested] 7+ messages in thread
* [Caml-list] Re: Exceptions considered harmful
2004-06-29 1:02 ` [Caml-list] Exceptions considered harmful skaller
2004-07-04 7:30 ` Lauri Alanko
@ 2004-07-11 13:12 ` Richard Cole
1 sibling, 0 replies; 7+ messages in thread
From: Richard Cole @ 2004-07-11 13:12 UTC (permalink / raw)
To: caml-list; +Cc: ocaml-lib-devel
When I read your examples I wondered how often this situation arises. Is
it just a symptom of the file interface or is it more general? It occurs
whenever resources, such as a file descriptor, need to be relinquished,
which generally is pretty often.
In one programming task that I worked on for some time most of the code
followed the following pattern.
1. allocate resources
2. manipulate resources
3. free resources
In each step you have to be ready for something to go wrong. Since it
was in a distributed environment steps 1 2 and 3 were composed of
concurrent parts, i.e. all resources were allocated concurrently.
In other programming tasks it has not been important to catch errors
because the effect of the programming stopping or leaking a few
resources is not serious.
But if you have to catch the errors it is tedious and error prone to
write massive try catch blocks to catch every error. Our solution was to
use the command pattern.
type success_or_failure = Success | Failure
class type command =
method do: clipboard -> success_or_failure
method undo: clipboard -> unit
method final: clipboard -> unit
end ;;
Then programs became the construction of object like the following:
let copy_file_cmd_name_args src dst =
let src_cmd = open_file_cmd src in
let dst_cmd = open_file_cmd dst in
seq_execute_cmd [
par_execute_cmd [src_cmd, dst_cmd],
copy_file_cmd_fd_func_args src_cmd#file dst_cmd#file
];
Here serial_execute runs through the commands executing them one by one
until either it finishes or an error is generated in which case it backs
out by calling undo. Finally objects are given a chance to release
resources when final is called.
This way we were sure that resources would be properly accounted for. Of
course hardware faults or mis-behaving clients can still cause you
trouble. Particularly tracing which operation first caused a failure and
what conditions lead to that failure.
It seems to me that if you have to catch errors then you have to
construct some similar framework in Ocaml. There's no language support
for writing commands.
regards,
Richard.
-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
^ permalink raw reply [flat|nested] 7+ messages in thread
* RE: [Caml-list] Exceptions considered harmful
@ 2004-06-29 18:05 Brandon J. Van Every
0 siblings, 0 replies; 7+ messages in thread
From: Brandon J. Van Every @ 2004-06-29 18:05 UTC (permalink / raw)
To: caml
skaller wrote:
>
> Any comments on any of this appreciated.
Being worn out from a dismal weekend of sub minimum wage signature
gathering (HOW can I get pa-id for my actual computer interests?) I did
not follow your logic too closely.
It seemed to me that to partially resolve your issues, whatever is
thrown must simply carry a lot more information about context, type of
error, etc. Many languages allow typed information to be thrown, for
instance, C++. I'm still a noob at OCaml; I thought it could do that
sort of thing.
I say 'partially' because exception handling is always a policy
decision. You simply cannot get away from crafting policies about what
to do when something doesn't work.
The problem is, do you have the implementation time to craft those
policies? I usually don't. It takes me 6 times to get any design
correct, and I do not want to spend a pile of design time on error
conditions when I know the code may very well be thrown out anyways.
If you pass the buck to the next level up, then you have a 'whiney API'.
If you're the boss of a company, do you really want tons of workers
whining about every little thing, saying "I've failed! I don't know
what to do! Can you handle this for me? Pleeeze??" No, you'd fire
'em. They're supposed to be doing jobs; you're supposed to be
delegating jobs to them, to hide the complexity of your corporate
operations. You want answers, not more problems.
Sadly, I think exception handling is only a valid approach to software
engineering once an API is reaching 'maturity'. One really should just
go back into it and rigidly define what's gonna happen when all of the
well-understood design parameters are violated. As an alternative, one
could code very cautiously, at a snail's pace. You could ensure that
exceptions are always thrown, even if nobody knows how to use the API
yet and it's fundamentally 'in flux'. In an industrial context on
someone else's nickel, that might be the way to go. But I certainly
can't afford it in my own development.
Cheers, www.indiegamedesign.com
Bran-don Van Every Se-attle, WA
Praise Be to the caml-list Bayesian filter! It blesseth
my postings, it is evil crap! evil crap! evil crap!
-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2004-07-11 14:30 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <20040628143917.GA21847@fichte.ai.univie.ac.at>
[not found] ` <Pine.LNX.4.44.0406290056580.1229-100000@localhost>
[not found] ` <20040628173400.GB26193@fichte.ai.univie.ac.at>
2004-06-29 1:02 ` [Caml-list] Exceptions considered harmful skaller
2004-07-04 7:30 ` Lauri Alanko
2004-07-04 20:16 ` Christophe TROESTLER
2004-07-04 20:24 ` Michael Hicks
2004-07-05 3:42 ` skaller
2004-07-11 13:12 ` [Caml-list] " Richard Cole
2004-06-29 18:05 [Caml-list] " Brandon J. Van Every
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).