@@ -458,10 +458,14 @@ val fail : exn -> _ t
458458 captures a backtrace, while [Lwt.fail] does not. If you call [raise exn] in
459459 a callback that is expected by Lwt to return a promise, Lwt will
460460 automatically wrap [exn] in a rejected promise, but the backtrace will have
461- been recorded by the OCaml runtime. Use [Lwt.fail] only when you
462- specifically want to create a rejected promise, to pass to another function,
463- or store in a data structure. *)
461+ been recorded by the OCaml runtime.
464462
463+ For example, [bind]'s second argument is a callback which returns a promise.
464+ And so it is recommended to use [raise] in the body of that callback. This
465+ applies to the aliases of [bind] as well: [( >>= )] and [( let* )].
466+
467+ Use [Lwt.fail] only when you specifically want to create a rejected promise,
468+ to pass to another function, or store in a data structure. *)
465469
466470
467471(* * {3 Callbacks} *)
@@ -574,6 +578,16 @@ let () =
574578
575579(* * {2:2_Rejection Rejection} *)
576580
581+ external reraise : exn -> 'a = " %reraise"
582+ (* * [reraise e] raises the exception [e]. Unlike [raise e], [reraise e]
583+ preserves the existing exception backtrace and even adds a "Re-raised at"
584+ entry with the call location.
585+
586+ This function is intended to be used in the exception handlers of
587+ [Lwt.catch] and [Lwt.try_bind].
588+
589+ It is also used in the code produced by Lwt_ppx. *)
590+
577591val catch : (unit -> 'a t ) -> (exn -> 'a t ) -> 'a t
578592(* * [Lwt.catch f h] applies [f ()], which returns a promise, and then makes it
579593 so that [h] (“handler”) will run when that promise is {{!t} {e rejected}}.
@@ -582,10 +596,10 @@ val catch : (unit -> 'a t) -> (exn -> 'a t) -> 'a t
582596let () =
583597 Lwt_main.run begin
584598 Lwt.catch
585- (fun () -> Lwt.fail Exit)
599+ (fun () -> raise Exit)
586600 (function
587601 | Exit -> Lwt_io.printl "Got Stdlib.Exit"
588- | exn -> Lwt.fail exn)
602+ | exn -> Lwt.reraise exn)
589603 end
590604
591605(* ocamlfind opt -linkpkg -thread -package lwt.unix code.ml && ./a.out *)
@@ -598,15 +612,15 @@ let () =
598612{[
599613let () =
600614 Lwt_main.run begin
601- try%lwt Lwt.fail Exit
615+ try%lwt raise Exit
602616 with Exit -> Lwt_io.printl "Got Stdlb.Exit"
603617 end
604618
605619(* ocamlfind opt -linkpkg -thread -package lwt_ppx,lwt.unix code.ml && ./a.out *)
606620]}
607621
608622 A particular advantage of the PPX syntax is that it is not necessary to
609- artificially insert a catch-all [exn -> Lwt.fail exn] case. Like in the core
623+ artificially insert a catch-all [exn -> reraise exn] case. Like in the core
610624 language's [try] expression, the catch-all case is implied in [try%lwt].
611625
612626 [Lwt.catch] is a counterpart to {!Lwt.bind} – {!Lwt.bind} is for
@@ -640,33 +654,7 @@ let () =
640654 - If [h exn] instead returns the promise [p_2], [p_3] is effectively made
641655 into a reference to [p_2]. This means [p_3] and [p_2] have the same state,
642656 undergo the same state changes, and performing any operation one is
643- equivalent to performing it on the other.
644-
645- {b (2)} {b Warning}: it may be tempting to write this code, which differs
646- from the second example above only in that [try] is used instead of
647- [try%lwt]:
648-
649- {[
650- let () =
651- Lwt_main.run begin
652- try Lwt.fail Exit
653- with Exit -> Lwt_io.printl "Got Stdlib.Exit"
654- end
655-
656- (* ocamlfind opt -linkpkg -thread -package lwt.unix code.ml && ./a.out *)
657- ]}
658-
659- This does {e not} handle the exception and does not print the message.
660- Instead, it terminates the program with an unhandled [Stdlib.Exit].
661-
662- This is because the call to {!Lwt.fail} creates a rejected promise. The
663- promise is still an ordinary OCaml value, though, and not a {e raised}
664- exception. So, [try] considers that code to have succeeded, and doesn't run
665- the handler. When that rejected promise reaches {!Lwt_main.run},
666- it is {!Lwt_main.run} that raises the exception.
667-
668- Basically, the rule is: if the code inside [try] evaluates to a promise
669- (has type [_ Lwt.t]), replace [try] by [try%lwt]. *)
657+ equivalent to performing it on the other. *)
670658
671659val finalize : (unit -> 'a t ) -> (unit -> unit t ) -> 'a t
672660(* * [Lwt.finalize f c] applies [f ()], which returns a promise, and then makes
@@ -755,6 +743,23 @@ val try_bind : (unit -> 'a t) -> ('a -> 'b t) -> (exn -> 'b t) -> 'b t
755743 fulfilled with, and, respectively, the exception [f ()] was rejected
756744 with.
757745
746+ As with {!Lwt.catch}, it is recommended to use {!reraise} in the catch-all
747+ case of the exception handler:
748+
749+ {[
750+ let () =
751+ Lwt_main.run begin
752+ Lwt.try_bind
753+ (fun () -> raise Exit)
754+ (fun () -> Lwt_io.printl "Got Success")
755+ (function
756+ | Exit -> Lwt_io.printl "Got Stdlib.Exit"
757+ | exn -> Lwt.reraise exn)
758+ end
759+
760+ (* ocamlfind opt -linkpkg -thread -package lwt.unix code.ml && ./a.out *)
761+ ]}
762+
758763 The rest is a detailed description of the promises involved.
759764
760765 As with {!Lwt.finalize} and the several preceding functions, three promises
@@ -892,7 +897,7 @@ val async_exception_hook : (exn -> unit) ref
892897 top level of the program:
893898
894899{[
895- let () = Lwt.async (fun () -> Lwt.fail Exit)
900+ let () = Lwt.async (fun () -> raise Exit)
896901
897902(* ocamlfind opt -linkpkg -package lwt code.ml && ./a.out *)
898903]}
0 commit comments