let f () =
let u @ local = [6; 2; 8] in (* mode *)
let len = Base.List.length u in
len;;let f () =
let local_ u = [6; 2; 8] in
let len = Base.List.length u in
len;;let f () =
let u : int list @@ local = stack_ [6; 2; 8] in (* modality *)
let len = Base.List.length u in
len;;let f () =
let u = local_ [6; 2; 8] in
let len = Base.List.length u in
len;;Other keywords to spot: stack_, global_, @ global, exclave_ and [@local_opt]
Mode | Lifetime | Allocation |
|---|---|---|
| MAY outlive its region | MUST be on the heap |
| MUST NOT outlive its region | MAY be on the stack |
let f () =
let foo =
let local_ bar = ("region", "scope") in
bar in
fst foo;;local mean?local means in the caller's regionThis really defines 4 arrows
val global_global : s -> t * t (* Legacy *)
val local_global : local_ s -> t * t
val global_local : s -> local_ t * t
val local_local : local_ s -> local_ t * t0. Low-latency code More importantly, stack allocations will never trigger a GC, and so they're safe to use in low-latency code that must currently be zero-alloc 1. Functions passed to higher-order iterators (such as `map`, `fold`, `bind` and others) are allocated on the stack 2. Safer callbacks
# let monday () = let str = "mon" ^ "day" in str;;# let bye () = let ciao = "sorry" in failwith ciao;;# let make_counter () =
let counter = ref (-1) in
fun () -> incr counter; !counter;;# let state = ref "";;
# let set () = state := "disco";;# let rec map f = function [] -> [] | x :: u -> f x :: map f u;;# let f1 (local_ u : int list) = [1; 2; 3];;# let f2 (local_ u : int list) = u;;# let f3 (local_ u : int list) = 42 :: u;;