(* In this program, we'll explore ivars. Ivars are very low-level async
* primitive that you seldom use. Often, you can solve all your async problems
* with deferreds and bind, but at times ivars become useful or even necessary.
*
* Recall that I like to think of deferreds as cardboard boxes that are full
* with some value when determined and empty otherwise. Up until now, whenever
* we've gotten our hands on a deferred, we've never been the ones to determine
* it and put the value in the box. For example, the deferred (after (sec 1.0))
* is determined after 1 second, but not by us! We never write the code which
* actually determines the value of the deferred. Well now we can with the
* power of ivars.
*
* Dealing with ivars boils to down to a handful of functions.
*
* 1. Ivar.create creates a brand new ivar.
* 2. Ivar.read i creates a deferred from an ivar.
* 3. Ivar.fill i x fills in any deferreds produced by Ivar.read.
*)
open Core.Std
open Async.Std
(* In this function, we create an ivar i. Then, we schedule the ivar to be
* filled with the string "hello" after 1 second. We then take the deferred d
* read from i and map it into print_endline. After 1 second, this function
* will print "hello". *)
let basics () : unit Deferred.t =
let i = Ivar.create () in
don't_wait_for (after (sec 1.0) >>| fun () -> Ivar.fill i "hello");
let d = Ivar.read i in
d >>| print_endline
(* What happens if we try to fill an ivar twice? Uncomment the following code
* and try for yourself. The code creates an ivar and schedules for it to be
* filled with "ocaml" after 1 second and with "haskell" after 2 seconds. It
* then maps the deferred read from the ivar into print_endline. After 1
* second, the ivar is filled and the deferred becomes determined. At this
* point, "ocaml" is printed to the screen. A second later though, we attempt
* to fill the ivar with "haskell", but the ivar is already filled and our
* program crashes.
*
* The moral of the story is to never fill an ivar more than once! *)
let choices_fill () : unit Deferred.t =
(*
let i = Ivar.create () in
don't_wait_for (Deferred.all_unit [
(after (sec 2.) >>| fun () -> Ivar.fill i "haskell");
(after (sec 1.) >>| fun () -> Ivar.fill i "ocaml");
]);
Ivar.read i >>= fun s ->
print_endline s;
*)
return ()
(* Luckily, it's easy to avoid filling an ivar more than once. We simply have
* to use Ivar.fill_if_empty instead of Ivar.fill. *)
let choices_fill_if_empty () : unit Deferred.t =
let i = Ivar.create () in
don't_wait_for (Deferred.all_unit [
(after (sec 2.) >>| fun () -> Ivar.fill_if_empty i "idris");
(after (sec 1.) >>| fun () -> Ivar.fill_if_empty i "coq");
]);
Ivar.read i >>| print_endline
let main () : unit Deferred.t =
basics () >>= fun () ->
choices_fill () >>= fun () ->
choices_fill_if_empty () >>= fun () ->
return ()
let () =
Command.(run (async ~summary:"" Spec.empty main))