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 * t
0. 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;;