From: Pierre Chopin <pierre@punchup.com>
To: Goswin von Brederlow <goswin-v-b@web.de>
Cc: caml-list@inria.fr
Subject: Re: [Caml-list] exn vs option
Date: Thu, 5 Apr 2012 16:19:08 -0400 [thread overview]
Message-ID: <CAGyUfm0=K7ASggPYXnUhKDHuoH=vdD4avmsruKm9sYufqeX8YQ@mail.gmail.com> (raw)
In-Reply-To: <874nsy1rcd.fsf@frosties.localnet>
[-- Attachment #1: Type: text/plain, Size: 5015 bytes --]
Thank you for your answers.
I am actually in the case of a webserver where I need to avoid interrupting
it, even in 'exceptional' cases, but rather report the problem in a log,
and return a default value whenever it is possible. Options seem to be the
best choice, not only from a safety point of view but also performance-wise.
Cheers
On Thu, Apr 5, 2012 at 5:05 AM, Goswin von Brederlow <goswin-v-b@web.de>wrote:
> Pierre Chopin <pierre@punchup.com> writes:
>
> > Hi,
> >
> > I benchmarked two programs, in one case the main function throw an
> exception
> > that is caught, in the other the function returns an option that is
> pattern
> > matched on.
> >
> > I noticed that, whether the exception is thrown or not, the option
> version is
> > always faster.
> >
> > Is there any case where it makes sense, performance wise, to use
> exception
> > instead of 'a option ?
>
> I find that in most cases speed is not a major concern and then it comes
> down to taste and readability of the code.
>
> > test1.ml
> > ----------------------------------------------------------------------
> >
> > exception Foo
> > let f x =
> > if x =1 then raise Foo else ()
> >
> > ;;
> >
> > for i = 0 to 10_000_000 do
> > try
> > f 1
> > with Foo -> ()
> > done
>
> 0.34s user 0.01s system 99% cpu 0.351 total
>
> That is rather short for a test. lets add 2 zeroes to the loop. And lets
> call f 0 and f 1 to test both cases:
>
> f 0: 17.72s user 0.02s system 99% cpu 17.792 total
> f 1: 35.30s user 0.02s system 99% cpu 35.371 total
>
> > ------------------------------------------------------------------------
> > test2.ml:
> > ------------------------------------------------------------------------
> > let f x =
> > if x=1 then None else Some ()
> >
> > ;;
> > for i = 0 to 10_000_000 do
> > match f 1 with
> > None -> ()
> > | Some s -> s
> > done
> > ------------------------------------------------------------------------
>
> f 0: 11.60s user 0.02s system 99% cpu 11.655 total
> f 1: 10.91s user 0.01s system 99% cpu 10.933 total
>
> And lets test the speed when the exception is actualy exceptional:
>
> exception Foo
> let f x = if x =1 then raise Foo else ()
>
> let () =
> try
> for i = 0 to 1000000000 do
> f 0
> done
> with Foo -> ()
>
> 9.94s user 0.00s system 99% cpu 9.946 total
>
> Someone said in deep recursions exceptions are faster because they don't
> have to unwind the stack:
>
> exception Result of int
>
> let rec fac acc = function
> | 1 -> raise (Result acc)
> | n -> fac (n * acc) (n - 1)
>
> let () =
> for i = 0 to 100_000_000 do
> try
> fac 1 50
> with Result _ -> ()
> done
>
> 71.88s user 0.00s system 99% cpu 1:11.90 total
>
>
> let rec fac acc = function
> | 1 -> acc
> | n -> fac (n * acc) (n - 1)
>
> let () =
> for i = 0 to 100_000_000 do
> ignore (fac 1 50)
> done
>
> 67.04s user 0.02s system 99% cpu 1:07.08 total
>
>
> Not feeling it. Lets try something not tail recursive:
>
> exception Error
>
> let rec foo = function
> | 1 -> raise Error
> | n -> n * (foo (n - 1))
>
> let () =
> for i = 0 to 100_000_000 do
> try
> ignore (foo 50)
> with Error -> ()
> done
>
> 25.03s user 0.01s system 99% cpu 25.068 total
>
> let rec foo = function
> | 1 -> None
> | n -> match foo (n - 1) with None -> None | Some x -> Some (n * x)
>
> let () =
> for i = 0 to 100_000_000 do
> ignore (foo 50)
> done
>
> 49.48s user 0.01s system 99% cpu 49.508 total
>
>
> In conclusion I would have to say that exceptions are better if they are
> exceptional.
>
> When you do not catch them right away or not at all then they are
> better. The "try" command is more expensive than an option type and if
> you are going to catch the exception right away anyway then options are
> faster.
>
> But if you don't catch them right away the cost of the try can be
> amortized over many calls and becomes cheaper. Or if you don't catch the
> exception at all then you can get a nice backtrace of where the
> exception occured.
>
> If your code is not tail recursive then option types mean you have to
> match them on every level again and again and allocate a ton of 'Some x'
> if no error occurs. You can make your code tail recursive or use
> exception to improve performance there.
>
>
>
> If you are writing a module then consider providing both flavours for
> functions, one with exceptions and one with options. Even if you only do
> something like this:
>
> let find x y = ....
>
> let raise_on_none exn f arg =
> match f arg with
> | None -> raise exn
> | Some x -> x
>
> let find_exn x y = raise_on_none Not_found (find x) y
>
> Obviously option only works for exceptions like Not_found. If you want
> to return an error you might have to use something like
>
> type ('a, 'b) result = Result of 'a | Error of 'b
>
> Putting the 2 flavours into different submodules can keep things tidy too.
>
> MfG
> Goswin
>
--
Pierre Chopin,
Chief Technology Officer and co-founder
punchup LLC
pierre@punchup.com
[-- Attachment #2: Type: text/html, Size: 6492 bytes --]
prev parent reply other threads:[~2012-04-05 20:19 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-04-04 20:25 Pierre Chopin
2012-04-04 20:38 ` John Carr
2012-04-04 22:10 ` Julien Verlaguet
2012-04-05 1:29 ` Francois Berenger
2012-04-05 6:45 ` Raphael Proust
2012-04-05 7:53 ` Benedikt Grundmann
2012-04-05 9:05 ` Goswin von Brederlow
2012-04-05 9:50 ` Daniel Bünzli
2012-04-11 10:26 ` Goswin von Brederlow
2012-04-11 10:32 ` David House
2012-04-11 10:36 ` David House
2012-04-05 20:19 ` Pierre Chopin [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAGyUfm0=K7ASggPYXnUhKDHuoH=vdD4avmsruKm9sYufqeX8YQ@mail.gmail.com' \
--to=pierre@punchup.com \
--cc=caml-list@inria.fr \
--cc=goswin-v-b@web.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox