;;;; nil <-> None at (Option T) boundaries -- M2 queue item 4. ;;;; ;;;; nil is dyn's own absence and None is (Option T)'s; this is the boundary ;;;; where the checker decides they are the same absence. [absent] and ;;;; [opt-of] take it in at the two annotated sites that are not a function ;;;; argument -- a global's declared type and a return type; [via-param] ;;;; takes it in at the third, a parameter. [as-dyn] is the other direction: ;;;; a written (Option i64) crossing into dyn becomes nil or the boxed ;;;; payload. [box-it]/[unbox-opt] round-trip a value through both crossings. ;;;; ;;;; The last line is the trap: a dyn that is nil only once the program runs, ;;;; reaching a bare i64. The literal [nil] two lines above it would have been ;;;; refused at compile time instead -- see test_flan.ml and ;;;; test_acceptance.ml's "nil at a bare T, compile time" row for that half. (defonce absent (Option i64) nil) (defn opt-of [flag bool] (Option i64) (if flag (Some 7) nil)) (defn via-param [o (Option i64)] i64 (match o (Some v) v None -1)) (defn as-dyn [o (Option i64)] dyn o) (defn box-it [x i64] dyn x) (defn unbox-opt [d dyn] (Option i64) d) (defn maybe-nil [flag bool] dyn (if flag 5 nil)) (defn take-i64 [n i64] i64 n) (defn show [o (Option i64)] () (print (match o (Some v) v None -1)) (println "")) (defn main [] () ;; nil -> None, at a global's declared type, a return type and a parameter. (show absent) ; -1 (show (opt-of true)) ; 7 (show (opt-of false)) ; -1 (print (via-param nil)) (println "") ; -1 (print (via-param (Some 3))) (println "") ; 3 ;; None -> nil, crossing into dyn; Some x -> the boxed x. (print (= (as-dyn None) nil)) (println "") ; true (print (as-dyn (Some 9))) (println "") ; 9 ;; A value round-tripped through both crossings: typed -> dyn -> (Option T). (show (unbox-opt (box-it 42))) ; 42 ;; The trap: a dyn that turns out to be nil only when the program runs, ;; reaching a bare i64. flan_dyn_need_i64 owns the wording. (print (take-i64 (maybe-nil false))) (println ""))