# Style question regarding try statement

**URL:** <https://discuss.ocaml.org/t/style-question-regarding-try-statement/13687>\
**Category:** Learning\
**Tags:** style\
**Created:** [December 20, 2023, 2:41pm UTC](https://discuss.ocaml.org/t/style-question-regarding-try-statement/13687 "2023-12-20T14:41:45Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![jbe](https://avatars.discourse-cdn.com/v4/letter/j/f6c823/32.png) [@jbe](https://discuss.ocaml.org/u/jbe)\
**Post date:** [December 20, 2023, 2:41pm UTC](https://discuss.ocaml.org/t/style-question-regarding-try-statement/13687/1 "2023-12-20T14:41:45Z")

</div>

Which of the following ways to write the (procedural) function `foo` would be considered most idiomatic?

### Variant 1:

```auto
let foo limit =
  let sum = ref 1 in
  let exception Limit_reached in
  (try
     for i = 1 to 10 do
       let newsum = !sum * i in
       if newsum > limit then raise Limit_reached;
       sum := newsum
     done
   with Limit_reached -> ());
  !sum - 1

```

(Side note: I find the 3-space indentation after the `try` statement a bit irritating, which was made by `dune fmt` / `ocamlformat`.)

### Variant 2:

```auto
let foo limit =
  let sum = ref 1 in
  let exception Limit_reached in
  let () =
    try
      for i = 1 to 10 do
        let newsum = !sum * i in
        if newsum > limit then raise Limit_reached;
        sum := newsum
      done
    with Limit_reached -> ()
  in
  !sum - 1

```

I like variant 2 a bit more, but I’m unsure.

---

<div class="post-metadata">

**Author:** ![nojb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/nojb/32/519_2.png) [@nojb](https://discuss.ocaml.org/u/nojb)\
**Post date:** [December 20, 2023, 4:27pm UTC](https://discuss.ocaml.org/t/style-question-regarding-try-statement/13687/2 "2023-12-20T16:27:59Z")

</div>

It is a question of style, so there is no definitive answer. At work we reserve `let () = ` for top-level bindings. For local side-effects, we use instead `begin ... end` (equivalent to parentheses, but with better indentation and harder to miss).

Incidentally, for local exceptions such as your `Limit_reached`, you can use `raise_notrace` which is a bit more efficient than the ordinary `raise` as it does not keep track of the backtrace.

Cheers,  
Nicolas

---

<div class="post-metadata">

**Author:** ![vlaviron](https://avatars.discourse-cdn.com/v4/letter/v/ec9cab/32.png) [@vlaviron](https://discuss.ocaml.org/u/vlaviron)\
**Post date:** [December 20, 2023, 5:20pm UTC](https://discuss.ocaml.org/t/style-question-regarding-try-statement/13687/3 "2023-12-20T17:20:11Z")

</div>

> [@nojb](#):
>
> Incidentally, for local exceptions such as your `Limit_reached`, you can use `raise_notrace` which is a bit more efficient than the ordinary `raise` as it does not keep track of the backtrace.

It’s useful to know about `raise_notrace`, but I would advise against using it unless you’re very concerned about performance and/or very confident that your code works as intended.  
You can get the performance of `raise_notrace` with regular `raise`s just by not passing the `-g` flag to the compiler, and if you do pass `-g` (and set backtraces on) then any `notrace` exception that is unhandled will be reported with a wrong backtrace (of the last regular `raise` that was caught).  
This leads to very painful debugging experiences.

Example (you can run it in a toplevel):

```ocaml
let setup_backtrace () =
  Printexc.record_backtrace true;
  try raise Not_found with Not_found -> ()

let (let+) def body =
  fun () -> body def

let return c = fun () -> c

let get x = x ()

let oops () =
  let exception Local_exn in
  let r =
    try
      let+ x = 0 in
      if true then raise_notrace Local_exn
      else x
    with Local_exn -> return 0
  in
  get r

let main () =
  setup_backtrace ();
  oops ()

```

---

<div class="post-metadata">

**Author:** ![jbe](https://avatars.discourse-cdn.com/v4/letter/j/f6c823/32.png) [@jbe](https://discuss.ocaml.org/u/jbe)\
**Post date:** [December 20, 2023, 7:58pm UTC](https://discuss.ocaml.org/t/style-question-regarding-try-statement/13687/4 "2023-12-20T19:58:26Z")

</div>

> [@nojb](#):
>
> For local side-effects, we use instead `begin ... end` (equivalent to parentheses, but with better indentation and harder to miss).

Oh interesting. I missed `begin` and `end` in the [core language introduction](https://v2.ocaml.org/manual/coreexamples.html) of the manual, but it’s inside the language section of the manual under [“Parenthesized expressions”](https://v2.ocaml.org/manual/expr.html#sss:expr-parenthesized).

Unfortunately, “`dune fmt`” changes all occurrences of `begin … end` to `( … )`. I think it’s [this issue](https://github.com/ocaml-ppx/ocamlformat/issues/9). _(edit: also see update below)_

Hm, I like to use autoformatting, so not sure what to do. Maybe there is some option I can enable to not touch `begin`/`end` blocks?

* * *

**Update:**

Finding [this PR](https://github.com/ocaml-ppx/ocamlformat/pull/828), I figured out I can achieve that with

```plaintext
exp-grouping = preserve

```

inside the `.ocamlformat` file. Then I can write:

```auto
let foo limit =
  let sum = ref 1 in
  let exception Limit_reached in
  begin
    try
      for i = 1 to 10 do
        let newsum = !sum * i in
        if newsum > limit then raise Limit_reached;
        sum := newsum
      done
    with Limit_reached -> ()
  end;
  !sum - 1

```

That, I like!

---

<div class="post-metadata">

**Author:** ![yawaramin](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/yawaramin/32/3384_2.png) [@yawaramin](https://discuss.ocaml.org/u/yawaramin)\
**Post date:** [December 20, 2023, 8:58pm UTC](https://discuss.ocaml.org/t/style-question-regarding-try-statement/13687/5 "2023-12-20T20:58:01Z")

</div>

Fun fact-- `begin` and `end` mean _exactly_ the same thing as `(` and `)` in OCaml. Even to the extent that `begin end` is a valid expression which is exactly equivalent to `()` (i.e. the unit value).

---

<div class="post-metadata">

**Author:** ![jbe](https://avatars.discourse-cdn.com/v4/letter/j/f6c823/32.png) [@jbe](https://discuss.ocaml.org/u/jbe)\
**Post date:** [December 20, 2023, 9:14pm UTC](https://discuss.ocaml.org/t/style-question-regarding-try-statement/13687/6 "2023-12-20T21:14:35Z")

</div>

Maybe parentheses aren’t so bad. But I dislike how they are formatted by default.

---

<div class="post-metadata">

**Author:** ![jjb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/jjb/32/2713_2.png) [@jjb](https://discuss.ocaml.org/u/jjb)\
**Post date:** [December 22, 2023, 9:58am UTC](https://discuss.ocaml.org/t/style-question-regarding-try-statement/13687/7 "2023-12-22T09:58:13Z")

</div>

There is also a non-performance motivation to use `raise_notrace` some times. It does not modify the hidden current backtrace state. This matters for code that runs in an exception handler before reraising an exception such as:

```ocaml
try
  do_something ()
with
| Error as exc ->
    analyze exc ;
    raise exc

```

Here, if `analyze` as part of its operation raises (with `raise`) and handles an exception, then the backtrace associated with `raise exc` will not lead back to the original point where it was raised in `do_something`. If the implementation of `analyze` uses `raise_notrace` instead of `raise`, then the backtrace is left undisturbed. So if the OP `foo` function is meant to be used in contexts like `analyze` here, then I think it is preferable to use `raise_notrace` irrespective of performance.
