Skip to content

Commit 8722710

Browse files
direct: rewrite some parts of the documentation
1 parent 94a397f commit 8722710

File tree

1 file changed

+55
-38
lines changed

1 file changed

+55
-38
lines changed

src/direct/lwt_direct.mli

Lines changed: 55 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,52 @@
11
(** Direct style control flow for Lwt.
22
3-
This module relies on OCaml 5's
4-
{{:https://ocaml.org/manual/5.3/effects.html} effect handlers}.
5-
Instead of chaining promises using {!Lwt.bind} and {!Lwt.map}
6-
and other combinators, it becomes possible to start
7-
lightweight "tasks" using [Lwt_direct.spawn (fun () -> ...)].
8-
The body of such a task is written in direct-style code,
9-
using OCaml's standard control flow structures such as loops,
10-
higher-order functions, exception handlers, [match], etc.
11-
12-
Interactions with the rest of lwt can be done using [await],
13-
for example:
3+
Using this module you can write code in direct style (using loops,
4+
exceptions handlers, etc.) in an Lwt codebase. Your direct-style sections
5+
must be enclosed in a call to {!spawn} and they may {!await} on promises.
6+
For example:
147
158
{[
16-
Lwt_direct.spawn (fun () ->
9+
open Lwt_direct
10+
spawn (fun () ->
1711
let continue = ref true in
1812
while !continue do
19-
match Lwt_io.read_line in_channel |> Lwt_direct.await with
13+
match await @@ Lwt_io.read_line in_channel with
2014
| exception End_of_file -> continue := false
2115
| line ->
2216
let uppercase_line = String.uppercase_ascii line in
23-
Lwt_io.write_line out_channel uppercase_line |> Lwt_direct.await
17+
await @@ Lwt_io.write_line out_channel uppercase_line
2418
done)
2519
]}
2620
27-
This code snippet contains a simple "task" that repeatedly reads
28-
a line from a [Lwt_io] channel, uppercases it, and writes the
29-
uppercase version to another channel.
21+
In this code snippet, the [while]-loop repeats a simple task of reading from
22+
an {!Lwt_io.channel}, modifying it, and writing it to a different channel.
23+
The code is in direct-style: the control structures are standard OCaml
24+
without any Lwt primitives.
3025
31-
This task is itself a [unit Lwt.t], which is resolved when the function
32-
returns. It is possible to use
33-
{!Lwt_direct.run_in_the_background} to ignore the result and
34-
let the task run in the background instead.
26+
The code-snippet as a whole is a [unit Lwt.t] promise. It becomes resovled
27+
when the function returns. Conversely, the promises inside the snippet are
28+
wrapped in {!await}, turning them into regular plain (non-Lwt) values
29+
(although values that are not available immediately).
3530
36-
*)
31+
The [Lwt_direct] module is implemented using OCaml 5's
32+
{{:https://ocaml.org/manual/5.3/effects.html} effects and effect handlers}.
33+
This allows the kind of scheduling where a promise is turned into a regular
34+
value and vice-versa. *)
3735

3836
val spawn : (unit -> 'a) -> 'a Lwt.t
39-
(** [spawn f] runs the function [f ()] in a task within
40-
the [Lwt_unix] event loop. [f ()] can create [Lwt]
41-
promises and use {!await} to wait for them. Like any promise
42-
in Lwt, [f ()] can starve the event loop if it runs long computations
43-
without yielding to the event loop.
37+
(** [spawn f] runs the function [f ()], it also returns a promise [p] which is
38+
resolved when the call to [f ()] returns a value. If [f ()] throws an
39+
exception, the promise [p] is rejected.
40+
41+
The function [f] can create Lwt promises (e.g., by calling functions from
42+
[Lwt_io], [Lwt_unix], or third-party libraries) and use {!await} to wait for
43+
them. These promises are evaluated in the Lwt event loop.
44+
45+
Like any promise in Lwt, [f ()] can starve the event loop if it runs long
46+
computations without yielding to the event loop.
47+
48+
Cancelling the promise returned by [spawn] has no effect: the execution of
49+
[f ()] continues and the promise is not cancelled.
4450
4551
When [f ()] terminates (successfully or not), the promise
4652
[spawn f] is resolved with [f ()]'s result, or the exception
@@ -50,32 +56,43 @@ val spawn_in_the_background :
5056
(unit -> unit) ->
5157
unit
5258
(** [spawn_in_the_background f] is similar to [ignore (spawn f)].
53-
The computation [f()] runs in the background in the event loop
59+
The computation [f ()] runs in the background in the event loop
5460
and returns no result.
61+
5562
If [f()] raises an exception, {!Lwt.async_exception_hook} is called. *)
5663

5764
val yield : unit -> unit
5865
(** Yield to the event loop.
5966
60-
Calling [yield] outside of {!spawn} or {!run_in_the_background} will raise an exception,
61-
crash your program, or otherwise cause errors. It is a programming error to do so. *)
67+
This is similar to [await (Lwt.pause ())], using less indirection internally
68+
and fewer characters to write.
69+
70+
Calling [yield] outside of {!spawn} or {!spawn_in_the_background} will raise
71+
an exception, crash your program, or otherwise cause errors. It is a
72+
programming error to do so. *)
6273

6374
val await : 'a Lwt.t -> 'a
64-
(** [await prom] returns the result of [prom], or re-raises the
65-
exception with which [prom] failed if it failed.
66-
If [prom] is not resolved yet, [await prom] will suspend the
67-
current task and resume it when [prom] is resolved.
75+
(** [await p] returns the result of [p] (or raises the exception with which [p]
76+
was rejected.
77+
78+
If [p] is not resolved yet, [await p] will suspend the current task (i.e.,
79+
the computation started by the surrounding {!spawn}) and resume it when [p]
80+
is resolved.
6881
69-
Calling [await] outside of {!spawn} or {!run_in_the_background} will raise an exception,
70-
crash your program, or otherwise cause errors. It is a programming error to do so. *)
82+
Calling [await] outside of {!spawn} or {!spawn_in_the_background} will raise
83+
an exception, crash your program, or otherwise cause errors. It is a
84+
programming error to do so. *)
7185

7286
(** Local storage.
7387
7488
This storage is the same as the one described with {!Lwt.key},
7589
except that it is usable from the inside of {!spawn} or
76-
{!run_in_the_background}.
90+
{!spawn_in_the_background}.
91+
92+
Each task has its own storage, independent from other tasks or promises.
7793
78-
Each task has its own storage, independent from other tasks or promises. *)
94+
NOTE: it is recommended to use [Lwt_direct.Storage] functions rather than
95+
[Lwt.key] functions from {!Lwt}. The latter is deprecated. *)
7996
module Storage : sig
8097
type 'a key = 'a Lwt.key
8198
val new_key : unit -> 'a key

0 commit comments

Comments
 (0)