From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail4-relais-sop.national.inria.fr (mail4-relais-sop.national.inria.fr [192.134.164.105]) by walapai.inria.fr (8.13.6/8.13.6) with ESMTP id q34KPtY2013523 for ; Wed, 4 Apr 2012 22:25:55 +0200 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AtYBAFWtfE/RVdc2imdsb2JhbABDpxwBiCMBiG4IIgEBAQoJDQcSBiOCIgITcQddEgEFARYfIodnnh+CXQqVO40rgyQElWOBEYokgxs9hCY X-IronPort-AV: E=Sophos;i="4.75,370,1330902000"; d="scan'208";a="139099240" Received: from mail-lpp01m010-f54.google.com ([209.85.215.54]) by mail4-smtp-sop.national.inria.fr with ESMTP/TLS/RC4-SHA; 04 Apr 2012 22:25:49 +0200 Received: by lagv3 with SMTP id v3so1384164lag.27 for ; Wed, 04 Apr 2012 13:25:49 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=mime-version:date:message-id:subject:from:to:content-type :x-gm-message-state; bh=uG+BBJe1AxSRj+17EGOFJCoHeocPRP/3DCeUDVudmPw=; b=n6H5b3TdDDWFkFpi5G/CPnqod3GCbITmyvUSDtE1y+QldUTKpvIpzx2CDhO+3aWXPT 393wxWhKOrlAiijZGeFv9tHNNATDXx1Bm2Hp5HdarL6a232+1QYatJjx93AIXSFqO+/T JUaIMm4OD8w2ncA/wkRevfn1D7aXCkWIeGZEw4xwjWAY3Ktho1wFDQl8+sCh2xGFk1dG hXc2vefwhsEr/nCwNDPgELUzxxuuMpcVwzkc7x+iTCeIOEpGpLKYgrlV079Fdfr0E2gN kZz0xBeUcb2+HhXMnlFxSGjU4c0rHZ4bFMIg8ovcKJfrU2B+mhBy4VGep/dWSQkDOZe/ Hn6w== MIME-Version: 1.0 Received: by 10.152.123.229 with SMTP id md5mr20210180lab.34.1333571149046; Wed, 04 Apr 2012 13:25:49 -0700 (PDT) Received: by 10.112.55.2 with HTTP; Wed, 4 Apr 2012 13:25:48 -0700 (PDT) Date: Wed, 4 Apr 2012 16:25:48 -0400 Message-ID: From: Pierre Chopin To: caml-list@inria.fr Content-Type: multipart/alternative; boundary=f46d04426aa49f224b04bce03a03 X-Gm-Message-State: ALoCoQkRPZeNLtkmNOiMF9Jak6ccpcVfM3P5Tl3Cu1ubO9RqiR7+XQraEVuT4mUfri2cC/oB4rNG Subject: [Caml-list] exn vs option --f46d04426aa49f224b04bce03a03 Content-Type: text/plain; charset=ISO-8859-1 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 ? 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 ------------------------------------------------------------------------ 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 ------------------------------------------------------------------------ -- Pierre Chopin, Chief Technology Officer and co-founder punchup LLC pierre@punchup.com --f46d04426aa49f224b04bce03a03 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
Hi,

I benchmarked two programs, in one case t= he main function throw an exception that is caught, in the other the functi= on 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 ?

test1.ml
----= ------------------------------------------------------------------

exception Foo
let f x =3D
=A0if x= =3D1 then raise Foo else ()

;;

=A0for i =3D 0 to 10_000_00= 0 do
try
=A0 =A0 f 1
with Foo -> ()
<= div>done
--------------------------------------------------= ----------------------
--------= ----------------------------------------------------------------
let f x =3D
=A0 =A0 if x=3D1 then None else Some ()

;;
for i =3D 0 to 10_000_000 do
=A0 =A0 matc= h f 1 with
=A0 =A0 =A0 =A0 None -> ()
=A0 =A0 | =A0 = Some s -> s
=A0 =A0 done
----------------= --------------------------------------------------------



--
Pierre= Chopin,
Chief Technology Officer and co-founder
punchup LLC<= /div>
--f46d04426aa49f224b04bce03a03-- From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail1-relais-roc.national.inria.fr (mail1-relais-roc.national.inria.fr [192.134.164.82]) by walapai.inria.fr (8.13.6/8.13.6) with ESMTP id q34KcZec013888 for ; Wed, 4 Apr 2012 22:38:35 +0200 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AvQCADGwfE8SB0Qim2dsb2JhbABFuCoiAQEBAQEICRQUJ4IJAQEEAXkFCwtGVwaIFwixDIkJkE8EqRY X-IronPort-AV: E=Sophos;i="4.75,370,1330902000"; d="scan'208";a="152746126" Received: from dmz-mailsec-scanner-5.mit.edu ([18.7.68.34]) by mail1-smtp-roc.national.inria.fr with ESMTP; 04 Apr 2012 22:38:29 +0200 X-AuditID: 12074422-b7fd66d0000008f9-02-4f7cb143c24d Received: from mailhub-auth-4.mit.edu ( [18.7.62.39]) by dmz-mailsec-scanner-5.mit.edu (Symantec Messaging Gateway) with SMTP id 13.A9.02297.341BC7F4; Wed, 4 Apr 2012 16:38:27 -0400 (EDT) Received: from outgoing.mit.edu (OUTGOING-AUTH.MIT.EDU [18.7.22.103]) by mailhub-auth-4.mit.edu (8.13.8/8.9.2) with ESMTP id q34KcQnX010992; Wed, 4 Apr 2012 16:38:26 -0400 Received: from localhost (CONTENTS-VNDER-PRESSVRE.MIT.EDU [18.9.64.11]) (authenticated bits=0) (User authenticated as jfc@ATHENA.MIT.EDU) by outgoing.mit.edu (8.13.6/8.12.4) with ESMTP id q34KcPcj001730; Wed, 4 Apr 2012 16:38:26 -0400 (EDT) Message-Id: <201204042038.q34KcPcj001730@outgoing.mit.edu> To: Pierre Chopin cc: caml-list@inria.fr In-reply-to: References: Comments: In-reply-to Pierre Chopin message dated "Wed, 04 Apr 2012 16:25:48 -0400." X-Mailer: MH-E 8.2; nmh 1.3; GNU Emacs 23.1.1 Date: Wed, 04 Apr 2012 16:38:25 -0400 From: John Carr X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrFIsWRmVeSWpSXmKPExsUixG6nruu8scbf4NVFHYtPOzawWDROOMDu wOQx6cUhFo/rvzsYA5iiuGxSUnMyy1KL9O0SuDJ2/ZrLXPCAs+L12voGxqvsXYycHBICJhLT XyxkhbDFJC7cW8/WxcjFISSwj1Hi5qlbTBDOekaJgwcnMYFUCQn8Z5R49b0axOYVsJKY8rIP LC4ioCbReeQ3C4jNDDTp1cMHYBuEgeLzN61iBrE5BQIlug6/YoSYEyDxcd5fRoj6XInDXbNY IK7Qlfi4aCZQLwcHi4CqxPoGO5Awm4CsxKP2LsYJjPwLGBlWMcqm5Fbp5iZm5hSnJusWJyfm 5aUW6Zrq5WaW6KWmlG5iBAeRi9IOxp8HlQ4xCnAwKvHw6k6u8RdiTSwrrsw9xCjJwaQkyjtv FVCILyk/pTIjsTgjvqg0J7X4EKMEB7OSCK/kAqAcb0piZVVqUT5MSpqDRUmcV13rnZ+QQHpi SWp2ampBahFMVoaDQ0mCd8oGoEbBotT01Iq0zJwShDQTByfIcB6g4VfWgwwvLkjMLc5Mh8if YlSUEudtA2kWAElklObB9cKi/BWjONArwrxVIFU8wAQB1/0KaDAT0OCTX6tBBpckIqSkGhjZ lvU9WFSuqj9dTK9qymkbt8AF8wqW/pnG3L3zE7udtG+S5Gyvee09r5fvXcYRUWcxJUfoaLHP 3TU5G09oeEjOLJgVsMvu+9qEDwvkfpdYaHwq8en1CyvcEXsyO0U6kvXyohdRwS5zX36TkxUP dozRka9h9+Zm4+tuPVqX8GSZx7YnG02fVyixFGckGmoxFxUnAgCoA4ZNzQIAAA== Subject: Re: [Caml-list] exn vs option When thinking about performance, consider the "try" keyword to take time to execute. A try block pushes an exception handler onto a stack and pops the stack on exit. The try block may also interfere with tail call optimizations. A loop like for i = 0 to 10000000 do try ... done executes "try" 10000001 times and will run much more slowly than try for i = 0 to 10000000 do ... done where "try" only executes once. I use options where performance matters, in frequently executed code where the amount of computation is not much more than the overhead of a try...with. For example, I have variants of List.assoc that return options instead of raising exceptions. Where performance doesn't matter, i.e. the amount of code in the block is large or the block is rarely executed, I use exceptions or options based on convenience. > 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 ? From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail1-relais-roc.national.inria.fr (mail1-relais-roc.national.inria.fr [192.134.164.82]) by walapai.inria.fr (8.13.6/8.13.6) with ESMTP id q34MAhp1015689 for ; Thu, 5 Apr 2012 00:10:43 +0200 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AqkBABrGfE/RVaG2kGdsb2JhbABFDqZPiFYBiG4IIgEBAQEJCQ0HFAQjggkBAQEDARICLAEbEgsBAwELBgULAxchIgERAQUBChIGExIQh2IFC5xcCowWgnGEVz+IdgEFC5BEBIhYjQuBEY0/PYNTVw X-IronPort-AV: E=Sophos;i="4.75,370,1330902000"; d="scan'208";a="152753292" Received: from mail-gx0-f182.google.com ([209.85.161.182]) by mail1-smtp-roc.national.inria.fr with ESMTP/TLS/RC4-SHA; 05 Apr 2012 00:10:38 +0200 Received: by ggnk4 with SMTP id k4so710040ggn.27 for ; Wed, 04 Apr 2012 15:10:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=kmbg1sNCwaB1sGW7ni2yOzijd4m52pivfUJNovzitQA=; b=NHNAX2ZNTcgjK5SA70flGQob52NQiDkPkSkCJvWq2OZ+iimujVZiYpBcFJh40fZQL7 rF0EvbO6BYZD6dHk68q9iS9RE6MYtGU7jJHzjk1VlL7FNlur2dzUgkHSYHrWtiIEsSdq MYvP/3fBOrOd1gBbqzLT+EvsUgmvBM5WV2t/tFPUx+1110ySYPG0qgiCf5p/DD5/0yvB SgrboZWRKtBikdOmZL2u8MNAlc2hgs8ksn1418AvnTBxePRLVBJZeKf2Woeaxxk61dOT HWr9VyyL8/I7zfej2mS8u0vBrE5eM6W0F6PIRFuMl4ZlTg6Rd0OQ+RUl4FT7ajzAgHoY hwNA== MIME-Version: 1.0 Received: by 10.60.170.145 with SMTP id am17mr50940oec.73.1333577437203; Wed, 04 Apr 2012 15:10:37 -0700 (PDT) Received: by 10.182.202.69 with HTTP; Wed, 4 Apr 2012 15:10:37 -0700 (PDT) In-Reply-To: <201204042038.q34KcPcj001730@outgoing.mit.edu> References: <201204042038.q34KcPcj001730@outgoing.mit.edu> Date: Wed, 4 Apr 2012 15:10:37 -0700 Message-ID: From: Julien Verlaguet To: John Carr Cc: Pierre Chopin , caml-list@inria.fr Content-Type: multipart/alternative; boundary=bcaec54c4fae6ccb9404bce1b1ad Subject: Re: [Caml-list] exn vs option --bcaec54c4fae6ccb9404bce1b1ad Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable 2 more use cases: 1) When writing a deep recursion Throwing an exception will directly jump to your "catch" block without having to unfold every return call site on the stack one by one. Which can be much faster if the recursion is very "deep". 2) When your exception is exceptional :-) If Not_found is never caught, then using exceptions is faster than option because you don't have to allocate to perform the "find" operation (the difference should be minimal though). Plus it makes your code more readable, you don't have to match on the return value of the find. This use case makes sense if you don't intend to catch Not_found, when Not_found is a bug, period. Le 4 avril 2012 13:38, John Carr a =E9crit : > > When thinking about performance, consider the "try" keyword to take time > to execute. A try block pushes an exception handler onto a stack and > pops the stack on exit. The try block may also interfere with tail call > optimizations. > > A loop like > > for i =3D 0 to 10000000 do try ... done > > executes "try" 10000001 times and will run much more slowly than > > try for i =3D 0 to 10000000 do ... done > > where "try" only executes once. > > I use options where performance matters, in frequently executed code > where the amount of computation is not much more than the overhead of > a try...with. For example, I have variants of List.assoc that return > options instead of raising exceptions. > > Where performance doesn't matter, i.e. the amount of code in the block > is large or the block is rarely executed, I use exceptions or options > based on convenience. > > > 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 ? > > -- > Caml-list mailing list. Subscription management and archives: > https://sympa-roc.inria.fr/wws/info/caml-list > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners > Bug reports: http://caml.inria.fr/bin/caml-bugs > > --bcaec54c4fae6ccb9404bce1b1ad Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
2 more use cases:

1) When writing a deep recu= rsion
Throwing an exception will directly jump to your "catc= h" block without having to unfold every return call site on the stack = one by one. Which can be much faster if the recursion is very "deep&qu= ot;.

2) When your exception is exceptional :-)
If = Not_found is never caught, then using exceptions is faster than option beca= use you don't have to allocate to perform the "find" operatio= n (the difference should be minimal though).
Plus it makes your code more readable, you don't have to match on = the return value of the find.
This use case makes sense if you do= n't intend to catch Not_found, when Not_found is a bug, period.

Le 4 avril 2012 13:38, John Carr <jfc@mit.edu> a= =E9crit :

When thinking about performance, consider the "try" keyword to ta= ke time
to execute. =A0A try block pushes an exception handler onto a stack and
pops the stack on exit. =A0The try block may also interfere with tail call<= br> optimizations.

A loop like

=A0for i =3D 0 to 10000000 do try ... done

executes "try" 10000001 times and will run much more slowly than<= br>
=A0try for i =3D 0 to 10000000 do ... done

where "try" only executes once.

I use options where performance matters, in frequently executed code
where the amount of computation is not much more than the overhead of
a try...with. =A0For example, I have variants of List.assoc that return
options instead of raising exceptions.

Where performance doesn't matter, i.e. the amount of code in the block<= br> is large or the block is rarely executed, I use exceptions or options
based on convenience.

> I benchmarked two programs, in one case the main function throw an exc= eption
> that is caught, in the other the function returns an option that is pa= ttern
> matched on.
>
> I noticed that, whether the exception is thrown or not, the option ver= sion is
> always faster.
>
> Is there any case where it makes sense, performance wise, to use excep= tion
> instead of 'a option ?

--
Caml-list mailing list. =A0Subscription management and archives:
https://sympa-roc.inria.fr/wws/info/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs


--bcaec54c4fae6ccb9404bce1b1ad-- From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail4-relais-sop.national.inria.fr (mail4-relais-sop.national.inria.fr [192.134.164.105]) by walapai.inria.fr (8.13.6/8.13.6) with ESMTP id q351TOZT023571 for ; Thu, 5 Apr 2012 03:29:27 +0200 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: Aq4CACn1fE+GoCGhmWdsb2JhbABFgxGjWJFwAQEBAQEICwsHFCeCCQEBBTIBBTYKEQsYCQQSCAcJAwIBAgEzARETBgIBAQ6Hdwu6Ho0rgyQEiFaNDYERhF+NNg X-IronPort-AV: E=Sophos;i="4.75,372,1330902000"; d="scan'208";a="139116603" Received: from postman1.riken.jp (HELO postman.riken.jp) ([134.160.33.161]) by mail4-smtp-sop.national.inria.fr with ESMTP; 05 Apr 2012 03:29:25 +0200 Received: from postman.riken.jp (postman1.riken.jp [127.0.0.1]) by postman.riken.jp (Postfix) with SMTP id 214A032C0272 for ; Thu, 5 Apr 2012 10:29:22 +0900 (JST) Received: from [172.27.98.103] (rikad98.riken.jp [134.160.214.98]) by postman.riken.jp (Postfix) with ESMTPA id 0D13932A008C for ; Thu, 5 Apr 2012 10:29:22 +0900 (JST) Message-ID: <4F7CF571.9030706@riken.jp> Date: Thu, 05 Apr 2012 10:29:21 +0900 From: Francois Berenger User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.28) Gecko/20120313 Thunderbird/3.1.20 MIME-Version: 1.0 To: caml-list@inria.fr References: <201204042038.q34KcPcj001730@outgoing.mit.edu> In-Reply-To: Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 8bit X-PMX-Version: 5.6.0.2009776, Antispam-Engine: 2.7.2.376379, Antispam-Data: 2012.4.3.91229 Subject: Re: [Caml-list] exn vs option I think there was an article about options versus exceptions in the OCaml journal. If I remember well, the exceptions were faster, but I can't find back the exact benchmark and context of this assertion. Regards, F. On 04/05/2012 07:10 AM, Julien Verlaguet wrote: > 2 more use cases: > > 1) When writing a deep recursion > Throwing an exception will directly jump to your "catch" block without > having to unfold every return call site on the stack one by one. Which > can be much faster if the recursion is very "deep". > > 2) When your exception is exceptional :-) > If Not_found is never caught, then using exceptions is faster than > option because you don't have to allocate to perform the "find" > operation (the difference should be minimal though). > Plus it makes your code more readable, you don't have to match on the > return value of the find. > This use case makes sense if you don't intend to catch Not_found, when > Not_found is a bug, period. > > Le 4 avril 2012 13:38, John Carr > a > écrit : > > > When thinking about performance, consider the "try" keyword to take time > to execute. A try block pushes an exception handler onto a stack and > pops the stack on exit. The try block may also interfere with tail call > optimizations. > > A loop like > > for i = 0 to 10000000 do try ... done > > executes "try" 10000001 times and will run much more slowly than > > try for i = 0 to 10000000 do ... done > > where "try" only executes once. > > I use options where performance matters, in frequently executed code > where the amount of computation is not much more than the overhead of > a try...with. For example, I have variants of List.assoc that return > options instead of raising exceptions. > > Where performance doesn't matter, i.e. the amount of code in the block > is large or the block is rarely executed, I use exceptions or options > based on convenience. > > > 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 ? > > -- > Caml-list mailing list. Subscription management and archives: > https://sympa-roc.inria.fr/wws/info/caml-list > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners > Bug reports: http://caml.inria.fr/bin/caml-bugs > > From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail4-relais-sop.national.inria.fr (mail4-relais-sop.national.inria.fr [192.134.164.105]) by walapai.inria.fr (8.13.6/8.13.6) with ESMTP id q356jdWN006159 for ; Thu, 5 Apr 2012 08:45:40 +0200 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AjoBAEQ/fU/RVda2kGdsb2JhbABDhXyyYggiAQEBAQkJDQcUBCOCCQEBAQQSAg8EGQEbHQEDDAYDAgsNAgIRFQICIgERAQUBHAYTIoddAQMLC6EiCotIToJxhHIKGScNV4EOAQULgSSLcIIYgRgElWiBEY1CPYQM X-IronPort-AV: E=Sophos;i="4.75,374,1330902000"; d="scan'208";a="139133175" Received: from mail-ob0-f182.google.com ([209.85.214.182]) by mail4-smtp-sop.national.inria.fr with ESMTP/TLS/RC4-SHA; 05 Apr 2012 08:45:29 +0200 Received: by obbwc18 with SMTP id wc18so2310648obb.27 for ; Wed, 04 Apr 2012 23:45:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type:content-transfer-encoding; bh=ukgnFB16nCo2M2ZF5APrGE5hNU1vNQeBe58wFFb3V5o=; b=mRXpKez/hydRNxR/ty5FM6HJQ27eK6mh2lUDgbzgtGbiUrlukrnhBRuqggM9m95LG3 Is672PyvsadGbaLhWQLWMDu2hUJxJwpSHcx6nStM0JaQ17LBHH+APCKBSIcGCrcW1oty t11OQlXqU10o3SIMJEbfgvjR9LBUeR9g/qgHZVAuPFhXOQTme3PB6jalcCdRuB6id2gT UZ7uDseKmecRGIz9usCX+dgRVRyoq9bl5yOrU17TRxNaX2JOs75wzQTAJDmzX15+mnpN oX9wUEkxkw1u+yjo4CV9VdVa+fvHbnd2G/1iRoQ/q1XzRP8BZIl28jLAAgwYTZjd6cx2 pONQ== MIME-Version: 1.0 Received: by 10.182.89.101 with SMTP id bn5mr1838520obb.39.1333608328596; Wed, 04 Apr 2012 23:45:28 -0700 (PDT) Received: by 10.76.137.45 with HTTP; Wed, 4 Apr 2012 23:45:28 -0700 (PDT) In-Reply-To: References: Date: Thu, 5 Apr 2012 08:45:28 +0200 Message-ID: From: Raphael Proust To: Pierre Chopin Cc: caml-list@inria.fr Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-MIME-Autoconverted: from quoted-printable to 8bit by walapai.inria.fr id q356jdWN006159 Subject: Re: [Caml-list] exn vs option Aside from performance considerations, there are semantics differences to take into account. This blog post explain why exceptions are "better" (or, more precisely, why it is not generally a good idea to replace exceptions by options) http://blog.dbpatterson.com/post/9528836599 (it is in Haskell rather than OCaml, but it still applies). On Wed, Apr 4, 2012 at 10:25 PM, Pierre Chopin wrote: > 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 ? > > 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 > ------------------------------------------------------------------------ > 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 > ------------------------------------------------------------------------ > > > > -- > Pierre Chopin, > Chief Technology Officer and co-founder > punchup LLC > pierre@punchup.com > -- _______ Raphael From mboxrd@z Thu Jan 1 00:00:00 1970 X-Sympa-To: caml-list@inria.fr Received: from mail1-relais-roc.national.inria.fr (mail1-relais-roc.national.inria.fr [192.134.164.82]) by walapai.inria.fr (8.13.6/8.13.6) with ESMTP id q357rMcs008648 for ; Thu, 5 Apr 2012 09:53:23 +0200 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AkACAPROfU/RVdK2mGdsb2JhbABDhXyhH5FFCCIBAQEBAQgJDQcUJ4IJAQEBBBICDwQZAQEsCwEPCQILAwoCAgkIFQICIQESAQUBChIGExIQh10BAwsLoSQKilpugz8BhH4KQAMKgWUGgS+IaYMHghiBGJVsgRGKJYMdPYQL X-IronPort-AV: E=Sophos;i="4.75,374,1330902000"; d="scan'208";a="152794519" Received: from mail-iy0-f182.google.com ([209.85.210.182]) by mail1-smtp-roc.national.inria.fr with ESMTP/TLS/RC4-SHA; 05 Apr 2012 09:53:22 +0200 Received: by mail-iy0-f182.google.com with SMTP id k25so2378541iah.27 for ; Thu, 05 Apr 2012 00:53:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type:content-transfer-encoding; bh=YpTWTnPLPLm6DeCqrYDF0EBWJUXNC94nS2BpBY7TlPw=; b=HIE6q8IoQc7p7zGG91i4bSMCwe3j1v3CfFEtl0TkZcsnGLgm1RcLcACGfbyxQSK6cl vnnrAjXVHerqd0fgiVhXcmYeFCGaEZpaxZTmU2+/qQnVbkQcWq4sbs9Ne+dJRU2BTQ93 Unhgf3LNxxsYS6xh7kMXW3090AN/2MyqIhi9PbzlZ9THdiFIZz8Ej2KMsRBkH7NcDj3d F5uwFA3j+QJi4RiEbyxYEj4odsN6TriVg/uukI07UvNxSxIVB7t6BuhOj9NI73wkthFz raXiNXZnuxJY3lcVZX4mhT2R5K/xrZzLH13VCTq0gdkRBNLLsi6txNMqerT+fGUHzaUn LTFg== MIME-Version: 1.0 Received: by 10.50.45.167 with SMTP id o7mr1207787igm.22.1333612402732; Thu, 05 Apr 2012 00:53:22 -0700 (PDT) Received: by 10.231.205.204 with HTTP; Thu, 5 Apr 2012 00:53:22 -0700 (PDT) In-Reply-To: References: Date: Thu, 5 Apr 2012 08:53:22 +0100 Message-ID: From: Benedikt Grundmann To: Raphael Proust Cc: Pierre Chopin , caml-list@inria.fr Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-MIME-Autoconverted: from quoted-printable to 8bit by walapai.inria.fr id q357rMcs008648 X-Validation-by: benedikt.grundmann@googlemail.com Subject: Re: [Caml-list] exn vs option That post is against maybe (aka option) as an error type as it looses information about the error. If you use an Either type such as Core's Result.t that argument is invalidated. In fact at Jane Street we try avoid the use of exceptions as they don't force the client of the library to handle the exceptional case. Also exceptions don't immediately imply more information one of the most wide spread exceptions in OCaml's stdlib is Not_found which can be a nightmare to hunt down (in particular if for whatever reason you did not also have a backtrace). Cheers, Bene On 5 April 2012 07:45, Raphael Proust wrote: > Aside from performance considerations, there are semantics differences > to take into account. This blog post explain why exceptions are > "better" (or, more precisely, why it is not generally a good idea to > replace exceptions by options) > http://blog.dbpatterson.com/post/9528836599 (it is in Haskell rather > than OCaml, but it still applies). > > On Wed, Apr 4, 2012 at 10:25 PM, Pierre Chopin wrote: >> 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 ? >> >> 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 >> ------------------------------------------------------------------------ >> 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 >> ------------------------------------------------------------------------ >> >> >> >> -- >> Pierre Chopin, >> Chief Technology Officer and co-founder >> punchup LLC >> pierre@punchup.com >> > > > > -- > _______ > Raphael > > > -- > Caml-list mailing list.  Subscription management and archives: > https://sympa-roc.inria.fr/wws/info/caml-list > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners > Bug reports: http://caml.inria.fr/bin/caml-bugs > -- Calvin: I try to make everyone's day a little more surreal. (From Calvin & Hobbes) From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail4-relais-sop.national.inria.fr (mail4-relais-sop.national.inria.fr [192.134.164.105]) by walapai.inria.fr (8.13.6/8.13.6) with ESMTP id q359BAbt012325 for ; Thu, 5 Apr 2012 11:11:10 +0200 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AoAIAEZhfU/ZSMDyWmdsb2JhbABFuGgYARYKCggUBCSCCQEBBAEnCwFGBQsLISUPAQQoBxoTh38BCQmxEh+KC5BaBJZ8hEyNQA X-IronPort-AV: E=Sophos;i="4.75,374,1330902000"; d="scan'208";a="139158013" Received: from fmmailgate04.web.de ([217.72.192.242]) by mail4-smtp-sop.national.inria.fr with ESMTP; 05 Apr 2012 11:10:49 +0200 Received: from moweb002.kundenserver.de (moweb002.kundenserver.de [172.19.20.108]) by fmmailgate04.web.de (Postfix) with ESMTP id 279BC74ABBBE for ; Thu, 5 Apr 2012 11:05:25 +0200 (CEST) Received: from frosties.localnet ([95.208.118.96]) by smtp.web.de (mrweb002) with ESMTPA (Nemesis) id 0ML8F7-1SFReE3S2j-000JBW; Thu, 05 Apr 2012 11:05:23 +0200 Received: from mrvn by frosties.localnet with local (Exim 4.77) (envelope-from ) id 1SFid9-0001aV-3U; Thu, 05 Apr 2012 11:05:23 +0200 From: Goswin von Brederlow To: Pierre Chopin Cc: caml-list@inria.fr References: Date: Thu, 05 Apr 2012 11:05:22 +0200 In-Reply-To: (Pierre Chopin's message of "Wed, 4 Apr 2012 16:25:48 -0400") Message-ID: <874nsy1rcd.fsf@frosties.localnet> User-Agent: Gnus/5.110009 (No Gnus v0.9) XEmacs/21.4.22 (linux, no MULE) MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit X-Provags-ID: V02:K0:QeooukzIWABnTDr7BKga+DiowP1sKfMGtYEeZ9+fH5c a2+KRDvSZUt0b6UB6Pm+URQkaDJ2GfhGkjaXcwvzLrpIT+e1mF II30nsweYQ2HbvDFU1b1UMgmbT3wYWUs2tOqLXUvqD325MITjI ROFy90yt/vb+cdwAgpDlDuMOvkKJtOblnmMnpFkAI8ua5OcSXL RPoAfPmKQE/ALfchrbFrQ== Subject: Re: [Caml-list] exn vs option Pierre Chopin 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 From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail1-relais-roc.national.inria.fr (mail1-relais-roc.national.inria.fr [192.134.164.82]) by walapai.inria.fr (8.13.6/8.13.6) with ESMTP id q359oNl8013727 for ; Thu, 5 Apr 2012 11:50:25 +0200 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AhgCAPFpfU9KN1ZKm2dsb2JhbABFhW+zGwEBAQEBCAkLCRQnggoBBSMEYgsaAhgOAgI9ChAhiAYEqEqSaYEvjAeCDDVjBJtIjUA X-IronPort-AV: E=Sophos;i="4.75,374,1330902000"; d="scan'208";a="152818576" Received: from mail6.webfaction.com (HELO smtp.webfaction.com) ([74.55.86.74]) by mail1-smtp-roc.national.inria.fr with ESMTP; 05 Apr 2012 11:50:25 +0200 Received: from heyho.local (83-232.197-178.cust.bluewin.ch [178.197.232.83]) by smtp.webfaction.com (Postfix) with ESMTP id 5A8F226ECF5A for ; Thu, 5 Apr 2012 04:50:22 -0500 (CDT) Date: Thu, 5 Apr 2012 11:50:17 +0200 From: =?utf-8?Q?Daniel_B=C3=BCnzli?= To: caml-list@inria.fr Message-ID: <91EB03E665BB4D7BB3CC65466956C79B@erratique.ch> In-Reply-To: <874nsy1rcd.fsf@frosties.localnet> References: <874nsy1rcd.fsf@frosties.localnet> X-Mailer: sparrow 1.5 (build 1043.1) MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Disposition: inline Content-Transfer-Encoding: 8bit X-MIME-Autoconverted: from quoted-printable to 8bit by walapai.inria.fr id q359oNl8013727 Subject: Re: [Caml-list] exn vs option Le jeudi, 5 avril 2012 à 11:05, Goswin von Brederlow a écrit : > 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: I don't think it's a rule that should be applied consistently, I don't like libraries that provide tons of convenience functions, too many names. If you stick with the option type (or variant cases) the user can quickly wrap the function if it needs an exception (or vice-versa but I prefer it that way since it's then documented by the function signature and is in my opinion better behaved in general). However in the particular case of finding something in a data structure where the user could be confronted with a situation where he can prove that the datum will be found I think it's justified to provide both flavours. For these cases, in my own code I settled on the following pattern : val find : 'a t -> key -> 'a option (** [find d k] is the value bound to [k] in [d], if any. *) val get : 'a t -> key -> 'a (** [get d k] is like {!find} but raises [Invalid_argument] if [k] is not bound in [d]. *) Best, Daniel P.S. [Invalid_argument] is used for programming errors. This pattern expresses an opinion about using exceptions. From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail1-relais-roc.national.inria.fr (mail1-relais-roc.national.inria.fr [192.134.164.82]) by walapai.inria.fr (8.13.6/8.13.6) with ESMTP id q35KJFLr031789 for ; Thu, 5 Apr 2012 22:19:15 +0200 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AqoBAPX8fU/RVdc2imdsb2JhbABFr3EBiHkIIgEBAQoJDQcSBiOCCQEBAQMBEgITUgULCws7IhIBBQEcBhMih14DBgWcHQqUQyKJPpBaBJVrgRGNQz2EJg X-IronPort-AV: E=Sophos;i="4.75,378,1330902000"; d="scan'208";a="152911875" Received: from mail-lpp01m010-f54.google.com ([209.85.215.54]) by mail1-smtp-roc.national.inria.fr with ESMTP/TLS/RC4-SHA; 05 Apr 2012 22:19:09 +0200 Received: by lagv3 with SMTP id v3so3486274lag.27 for ; Thu, 05 Apr 2012 13:19:08 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type:x-gm-message-state; bh=9bmWOKiCb0IppICfEaqMUIXM3fwyILWFwt6ygntTAW0=; b=c399mwph6rRfEZUY5Qi7zbgbxEG8+RF7LEDI8RMTseMRANOddEB84dMwQ2xWybaGoT d119hkHXusS6r/+HoNMfs3APr5yvyODVoS9vcrZ87483KX0xHH171oOZoGuXKVvqTjlB Q5fndyoaiLrX1N1qtXfm4R2W6kP3OR8D+6jNSueebf23FFV2/wXjAyNHbayFbPfSSGtI S3Hrwd3DqqSqN//jXVH56btVVpuDgA0IaW9YW7yMUL7MDpCuGnprm/wAs1D+0je+yR+r jywk3D4Nent+UWroJGixLjO6j+/QPF6Bb1XhMy7hlVAE6qD7Leww0iNEpDXVo2gqkEHk E6hA== MIME-Version: 1.0 Received: by 10.152.131.9 with SMTP id oi9mr5063145lab.6.1333657148719; Thu, 05 Apr 2012 13:19:08 -0700 (PDT) Received: by 10.112.55.2 with HTTP; Thu, 5 Apr 2012 13:19:08 -0700 (PDT) In-Reply-To: <874nsy1rcd.fsf@frosties.localnet> References: <874nsy1rcd.fsf@frosties.localnet> Date: Thu, 5 Apr 2012 16:19:08 -0400 Message-ID: From: Pierre Chopin To: Goswin von Brederlow Cc: caml-list@inria.fr Content-Type: multipart/alternative; boundary=f46d042c64779a018504bcf440a5 X-Gm-Message-State: ALoCoQmXjftxYFxWVigzVCADJ6Cm0pn6M+tLNHb94N//cjwPtSoRlwwB12l5Y7YOC4QVrfbEspDh Subject: Re: [Caml-list] exn vs option --f46d042c64779a018504bcf440a5 Content-Type: text/plain; charset=ISO-8859-1 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 wrote: > Pierre Chopin 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 --f46d042c64779a018504bcf440a5 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Thank you for your answers.
I am actually in the case of a webserver wh= ere I need to avoid interrupting it, even in 'exceptional' cases, b= ut 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, A= pr 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 exc= eption
> that is caught, in the other the function returns an option that is pa= ttern
> matched on.
>
> I noticed that, whether the exception is thrown or not, the option ver= sion is
> always faster.
>
> Is there any case where it makes sense, performance wise, to use excep= tion
> instead of 'a option ?

I find that in most cases speed is not a major concern and then it co= mes
down to taste and readability of the code.

> test1.ml
> ----------------------------------------------------------------------=
>
> exception Foo
> let f x =3D
> =A0if x =3D1 then raise Foo else ()
>
> ;;
>
> =A0for i =3D 0 to 10_000_000 do
> try
> =A0 =A0 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 =3D
> =A0 =A0 if x=3D1 then None else Some ()
>
> ;;
> for i =3D 0 to 10_000_000 do
> =A0 =A0 match f 1 with
> =A0 =A0 =A0 =A0 None -> ()
> =A0 =A0 | =A0 Some s -> s
> =A0 =A0 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 =3D if x =3D1 then raise Foo else ()

let () =3D
=A0try
=A0 =A0for i =3D 0 to 1000000000 do
=A0 =A0 =A0f 0
=A0 =A0done
=A0with 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 =3D function
=A0| 1 -> raise (Result acc)
=A0| n -> fac (n * acc) (n - 1)

let () =3D
=A0for i =3D 0 to 100_000_000 do
=A0 =A0try
=A0 =A0 =A0fac 1 50
=A0 =A0with Result _ -> ()
=A0done

71.88s user 0.00s system 99% cpu 1:11.90 total


let rec fac acc =3D function
=A0| 1 -> acc
=A0| n -> fac (n * acc) (n - 1)

let () =3D
=A0for i =3D 0 to 100_000_000 do
=A0 =A0ignore (fac 1 50)
=A0done

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 =3D function
=A0| 1 -> raise Error
=A0| n -> n * (foo (n - 1))

let () =3D
=A0for i =3D 0 to 100_000_000 do
=A0 =A0try
=A0 =A0 =A0ignore (foo 50)
=A0 =A0with Error -> ()
=A0done

25.03s user 0.01s system 99% cpu 25.068 total

let rec foo =3D function
=A0| 1 -> None
=A0| n -> match foo (n - 1) with None -> None | Some x -> Some (n= * x)

let () =3D
=A0for i =3D 0 to 100_000_000 do
=A0 =A0ignore (foo 50)
=A0done

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 a= nd 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 th= e
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 =3D ....

let raise_on_none exn f arg =3D
=A0match f arg with
=A0| None -> raise exn
=A0| Some x -> x

let find_exn x y =3D 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

=A0 type ('a, 'b) result =3D Result of 'a | Error of 'b

Putting the 2 flavours into different submodules can keep things tidy too.<= br>
MfG
=A0 =A0 =A0 =A0Goswin



-- Pierre Chopin,
Chief Technology Officer and co-founder
punc= hup LLC

--f46d042c64779a018504bcf440a5-- From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail4-relais-sop.national.inria.fr (mail4-relais-sop.national.inria.fr [192.134.164.105]) by walapai.inria.fr (8.13.6/8.13.6) with ESMTP id q3BAQM6a014353 for ; Wed, 11 Apr 2012 12:26:27 +0200 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AmADAKNbhU/ZSMDyfGdsb2JhbABFuUYiAQELCQsHFAUkggkBAQQBJwsBSwsLISUPAQQoNId/AQkJsEcfiguOG4MkBJtLjUA X-IronPort-AV: E=Sophos;i="4.75,404,1330902000"; d="scan'208";a="139804804" Received: from fmmailgate04.web.de ([217.72.192.242]) by mail4-smtp-sop.national.inria.fr with ESMTP; 11 Apr 2012 12:26:27 +0200 Received: from moweb001.kundenserver.de (moweb001.kundenserver.de [172.19.20.114]) by fmmailgate04.web.de (Postfix) with ESMTP id 929B275C4ED5 for ; Wed, 11 Apr 2012 12:26:26 +0200 (CEST) Received: from frosties.localnet ([95.208.118.96]) by smtp.web.de (mrweb002) with ESMTPA (Nemesis) id 0M5Oql-1S68GT107r-00zXBI; Wed, 11 Apr 2012 12:26:26 +0200 Received: from mrvn by frosties.localnet with local (Exim 4.77) (envelope-from ) id 1SHukr-00030C-OB for caml-list@inria.fr; Wed, 11 Apr 2012 12:26:25 +0200 From: Goswin von Brederlow To: caml-list@inria.fr In-Reply-To: <91EB03E665BB4D7BB3CC65466956C79B@erratique.ch> ("Daniel Buenzli"'s message of "Thu, 5 Apr 2012 11:50:17 +0200") References: <874nsy1rcd.fsf@frosties.localnet> <91EB03E665BB4D7BB3CC65466956C79B@erratique.ch> User-Agent: Gnus/5.110009 (No Gnus v0.9) XEmacs/21.4.22 (linux, no MULE) Date: Wed, 11 Apr 2012 12:26:25 +0200 Message-ID: <87vcl6d0oe.fsf@frosties.localnet> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit X-Provags-ID: V02:K0:RGnw0KxXNT8X4u8OM+bYu0KsF6yrY8+bFDBbVSPybBq zFj/FevWY3aLVUUqkseMFNoFhynha0eQstPnWeKIwcV51/bNNH WjrrwQuj/Leho8vTQRLcyYxV6ZtDl4Fp7XYtPzRBz0UiMF4LOI 8d2X0Bugw4rzXzuw2DaZTBfGCpFpYyyq9j7z1RkV37UlI9t3ak Y7mJzpIKIGaDbdjruFBGQ== Subject: Re: [Caml-list] exn vs option Daniel Bünzli writes: > Le jeudi, 5 avril 2012 à 11:05, Goswin von Brederlow a écrit : >> 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: > > > I don't think it's a rule that should be applied consistently, I don't like libraries that provide tons of convenience functions, too many names. If you stick with the option type (or variant cases) the user can quickly wrap the function if it needs an exception (or vice-versa but I prefer it that way since it's then documented by the function signature and is in my opinion better behaved in general). > > However in the particular case of finding something in a data structure where the user could be confronted with a situation where he can prove that the datum will be found I think it's justified to provide both flavours. For these cases, in my own code I settled on the following pattern : > > val find : 'a t -> key -> 'a option > (** [find d k] is the value bound to [k] in [d], if any. *) > > val get : 'a t -> key -> 'a > (** [get d k] is like {!find} but raises [Invalid_argument] if [k] is not bound in [d]. *) That pattern works well if you have just one or few such functions and can think of nice names to differentiate them. Otherwise submodules are usefull: module Foo = Foo.Options or module Foo = Foo.Exceptions Foo.do_things () or open Foo.Options do_things () The option and exception raising functions would be named the same and the user selects one or the other by selecting a submodule. As said, it is usualy a matter of taste and the users tastes might differ from the module authors taste. By providing an option and execption flavour of a function (by different names or submodules hardly matters) the user can use what he likes as opposed to what the modules author imposes on him. MfG Goswin From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail1-relais-roc.national.inria.fr (mail1-relais-roc.national.inria.fr [192.134.164.82]) by walapai.inria.fr (8.13.6/8.13.6) with ESMTP id q3BAWVHJ014675 for ; Wed, 11 Apr 2012 12:32:31 +0200 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AuUBAMpchU8machwl2dsb2JhbABFuT4qAQEBAQEGGAc7ggkBAQEEEgITGQEBNwEPCwsNLiISAQUBHAYTCBqHXgMLAwGbdwqKZIQuAYV9Iok4BpE/lXCOVj2ECw X-IronPort-AV: E=Sophos;i="4.75,404,1330902000"; d="scan'208";a="153543758" Received: from mx1.janestreet.com (HELO nyc-dmz-mxout1.janestreet.com) ([38.105.200.112]) by mail1-smtp-roc.national.inria.fr with ESMTP/TLS/DHE-RSA-AES256-SHA; 11 Apr 2012 12:32:25 +0200 Received: from nyc-qsv-mail1.delacy.com ([172.25.22.57]) by nyc-dmz-mxout1.janestreet.com with esmtp (Exim 4.76) (envelope-from ) id 1SHuqX-0006K1-S2 for caml-list@inria.fr; Wed, 11 Apr 2012 06:32:17 -0400 Received: from nyc-dmz-mxgoog1.delacy.com ([172.25.224.109] helo=mxgoog1.janestreet.com) by nyc-qsv-mail1.delacy.com with esmtps (TLSv1:AES256-SHA:256) (Exim 4.76) (envelope-from ) id 1SHuqX-0001ny-QT for caml-list@inria.fr; Wed, 11 Apr 2012 06:32:17 -0400 Received: from mail-wi0-f182.google.com ([209.85.212.182]) by mxgoog1.janestreet.com with esmtp (Exim 4.76) (envelope-from ) id 1SHuqX-0000v8-JK for caml-list@inria.fr; Wed, 11 Apr 2012 06:32:17 -0400 Received: by wibhr14 with SMTP id hr14so677640wib.17 for ; Wed, 11 Apr 2012 03:32:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=janestreet.com; s=google; h=mime-version:x-originating-ip:in-reply-to:references:date :message-id:subject:from:to:cc:content-type :content-transfer-encoding; bh=Y55lmJy9XmQQWvQ6vd+tH3qXTePtrW14tlAnM55KL0M=; b=LrYEkj+FoCybVnHzfSL3zXjpwiyRSfoi+e6+vNWmkM9T06svJyVdjKbv4Ly9vyCqsL slTQDd2vbcQNP3Tq/c6cOrJIhBKQo4pX+qGycsoV+yUJ92IZYP8xq2TgHK8jvjgv1dmU goWoGA3wivoBXuxHolMq8k7er1AltRUbRf7GI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=mime-version:x-originating-ip:in-reply-to:references:date :message-id:subject:from:to:cc:content-type :content-transfer-encoding:x-gm-message-state; bh=Y55lmJy9XmQQWvQ6vd+tH3qXTePtrW14tlAnM55KL0M=; b=haobyClXicSff28E8vyNedDrIsC8bSl9p5wpGl5szqWIbJhPJy1J5w9naKNXkB/z/9 GNVC8SNHjLUehnacHk3Uwww1ESzgV5tTj21cPAIT8h1fxgmh2QLX+NHx3QkDaC433M/e bLUuKAuJCPm9Oz4EOpzcnIqmzW08FyMEIGcK9/W6WWWMiUg9mAqXUJ0iLISltvSdo4dW vTvzQuKUL9ZobRTD6F+ZvD8A38SbhuGq9Q94spqHTAfCot6bjpvgZSdU8M1LFUYoiwN7 SYQtEDztQIHqJaslR2/AXurRz3kUbbSgz53SBe++pbXJPjRe3199BVRjFmUINNWpRTQx b6lg== MIME-Version: 1.0 Received: by 10.180.80.9 with SMTP id n9mr15027947wix.4.1334140337021; Wed, 11 Apr 2012 03:32:17 -0700 (PDT) Received: by 10.216.235.148 with HTTP; Wed, 11 Apr 2012 03:32:16 -0700 (PDT) X-Originating-IP: [80.169.196.210] In-Reply-To: <87vcl6d0oe.fsf@frosties.localnet> References: <874nsy1rcd.fsf@frosties.localnet> <91EB03E665BB4D7BB3CC65466956C79B@erratique.ch> <87vcl6d0oe.fsf@frosties.localnet> Date: Wed, 11 Apr 2012 11:32:16 +0100 Message-ID: From: David House To: Goswin von Brederlow Cc: caml-list@inria.fr Content-Type: text/plain; charset=ISO-8859-1 X-Gm-Message-State: ALoCoQljx7LEXHKG0gzs4n6bSG3kgcbBNxRQ3o+vWvF8ZVRjPpZ29pAr32k7BSR4rPaxh9nPQsZz Content-Transfer-Encoding: 8bit X-MIME-Autoconverted: from quoted-printable to 8bit by walapai.inria.fr id q3BAWVHJ014675 Subject: Re: [Caml-list] exn vs option On Wed, Apr 11, 2012 at 11:26 AM, Goswin von Brederlow wrote: >> However in the particular case of finding something in a data structure where the user could be confronted with a situation where he can prove that the datum will be found I think it's justified to provide both flavours. For these cases, in my own code I settled on the following pattern : >> >>     val find : 'a t -> key -> 'a option >>     (** [find d k] is the value bound to [k] in [d], if any. *) >> >>     val get : 'a t -> key -> 'a >>     (** [get d k] is like {!find} but raises [Invalid_argument] if [k] is not bound in [d]. *) > > That pattern works well if you have just one or few such functions and > can think of nice names to differentiate them. A common pattern that is convenient and clear is to append _exn to the functions that raise excetions on failure. This is used all over Core, and has the advantage that it is very obvious to client code that the call may raise an exception. A call to an _exn function without a try/with or a clearly true invariant is an indication that you might have a bug. (Not always; sometimes the appropriate behaviour to crash the program when some function fails.) From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail1-relais-roc.national.inria.fr (mail1-relais-roc.national.inria.fr [192.134.164.82]) by walapai.inria.fr (8.13.6/8.13.6) with ESMTP id q3BAagSD014940 for ; Wed, 11 Apr 2012 12:36:42 +0200 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AuUBAPFdhU8machzl2dsb2JhbABCuUsqAQEBAQEGGAc7ggkBAQEEEgITGQEBNwEPCwsNLiISAQUBHAYTCBqHXgMLAwEHoCkKimSELgGFfiKBUAIEkT+VcI5WPYQL X-IronPort-AV: E=Sophos;i="4.75,404,1330902000"; d="scan'208";a="153544526" Received: from mx2.janestreet.com (HELO nyc-dmz-mxout2.janestreet.com) ([38.105.200.115]) by mail1-smtp-roc.national.inria.fr with ESMTP/TLS/DHE-RSA-AES256-SHA; 11 Apr 2012 12:36:36 +0200 Received: from nyc-qsv-mail1.delacy.com ([172.25.22.57]) by nyc-dmz-mxout2.janestreet.com with esmtp (Exim 4.76) (envelope-from ) id 1SHuuf-0008VA-TD for caml-list@inria.fr; Wed, 11 Apr 2012 06:36:33 -0400 Received: from nyc-dmz-mxgoog1.delacy.com ([172.25.224.109] helo=mxgoog1.janestreet.com) by nyc-qsv-mail1.delacy.com with esmtps (TLSv1:AES256-SHA:256) (Exim 4.76) (envelope-from ) id 1SHuuf-0002E1-Rr for caml-list@inria.fr; Wed, 11 Apr 2012 06:36:33 -0400 Received: from mail-we0-f170.google.com ([74.125.82.170]) by mxgoog1.janestreet.com with esmtp (Exim 4.76) (envelope-from ) id 1SHuuf-0000yP-No for caml-list@inria.fr; Wed, 11 Apr 2012 06:36:33 -0400 Received: by werh12 with SMTP id h12so538438wer.29 for ; Wed, 11 Apr 2012 03:36:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=janestreet.com; s=google; h=mime-version:x-originating-ip:in-reply-to:references:date :message-id:subject:from:to:cc:content-type :content-transfer-encoding; bh=5XP7+0yv8DkP2HxVHlWHzf6rVNdxbzPELmehAfIt3UU=; b=vW/UKr5+OM+oBnORP1/jPx4qIv0KEQ9FggUwDq+S4EA7v1ogJ9Cpc01ezmqyGd0vZW vydRfZSUeXTnhuP4CUHLlAadBpQKTIW0aiMkJIe0HjRfV6LhSnYjYJhM0jnQz39MWxfr oXdOtpwpdAlfrdJt07vQLeimRXQaectuB8/X4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=mime-version:x-originating-ip:in-reply-to:references:date :message-id:subject:from:to:cc:content-type :content-transfer-encoding:x-gm-message-state; bh=5XP7+0yv8DkP2HxVHlWHzf6rVNdxbzPELmehAfIt3UU=; b=S/Mb0kqq/7GEHOHIWWlTyo5MhqO8hWPugEi+sJG8U6POe0By5ySENQhkN42Zg81Aug KoH5vUTRCOIGnDbZw9nDh8hElftC4yFWgrVxRpLpSwkMPBXyj1eH1he+HEJB4/n/aZv1 I7r9yOA/53EdC+8P7Fs125tysBD46y49cO5Bq1obDhlAVTkFj4fhU22nom9MjwzpOoW9 VHxUgb1Y36uxhNy85M2ZlLd24Ev/IjKHuzhtDgs+B9e4p2p2qYlHgt6sWYPSmjs/0uDZ axS2GevHeGS4Kc9rDeo8/JEZQdXOxCV6x9lVOlSHyd/M+kJs/DfRI4phEwpp5G8NPXvB iD+w== MIME-Version: 1.0 Received: by 10.216.132.6 with SMTP id n6mr8818315wei.26.1334140592879; Wed, 11 Apr 2012 03:36:32 -0700 (PDT) Received: by 10.216.235.148 with HTTP; Wed, 11 Apr 2012 03:36:32 -0700 (PDT) X-Originating-IP: [80.169.196.210] In-Reply-To: References: <874nsy1rcd.fsf@frosties.localnet> <91EB03E665BB4D7BB3CC65466956C79B@erratique.ch> <87vcl6d0oe.fsf@frosties.localnet> Date: Wed, 11 Apr 2012 11:36:32 +0100 Message-ID: From: David House To: Goswin von Brederlow Cc: caml-list@inria.fr Content-Type: text/plain; charset=ISO-8859-1 X-Gm-Message-State: ALoCoQmSOyNAAe1P29wheGIhoMHqEqow/Ki8BKTs2NN4FyPdZPla5hKPSVbJVCtLjNFnCt/6P+pN Content-Transfer-Encoding: 8bit X-MIME-Autoconverted: from quoted-printable to 8bit by walapai.inria.fr id q3BAagSD014940 Subject: Re: [Caml-list] exn vs option On Wed, Apr 11, 2012 at 11:32 AM, David House wrote: > On Wed, Apr 11, 2012 at 11:26 AM, Goswin von Brederlow > wrote: >>> However in the particular case of finding something in a data structure where the user could be confronted with a situation where he can prove that the datum will be found I think it's justified to provide both flavours. For these cases, in my own code I settled on the following pattern : >>> >>>     val find : 'a t -> key -> 'a option >>>     (** [find d k] is the value bound to [k] in [d], if any. *) >>> >>>     val get : 'a t -> key -> 'a >>>     (** [get d k] is like {!find} but raises [Invalid_argument] if [k] is not bound in [d]. *) >> >> That pattern works well if you have just one or few such functions and >> can think of nice names to differentiate them. > > A common pattern that is convenient and clear is to append _exn to the > functions that raise excetions on failure. As an example, see Core's Map module: https://bitbucket.org/yminsky/ocaml-core/src/c0e9df7b574d/base/core/lib/core_map_intf.ml We have, e.g., [find] and [find_exn].