73 lines
3.3 KiB
Plaintext
73 lines
3.3 KiB
Plaintext
;;;; A numeric cast opens a dyn box — FIX.org 2026-09-20.
|
|
;;;;
|
|
;;;; Before this, a typed parameter was the only thing in the language that
|
|
;;;; could open a box, so a program wanting a number out of a dyn wrote a
|
|
;;;; one-line function whose parameter slot did the unboxing and called that.
|
|
;;;; A cast is the operator for "convert this to that", so it is the spelling
|
|
;;;; that should have worked; here it does.
|
|
;;;;
|
|
;;;; Three behaviours, in the order main runs them:
|
|
;;;;
|
|
;;;; 1. Same kind. The box holds what the cast asks for, so the cast is the
|
|
;;;; unbox and nothing else is written or warned.
|
|
;;;; 2. Cross kind. The box holds the other number. The cast still converts —
|
|
;;;; exactly as the same cast converts a typed operand of that type — and
|
|
;;;; one line goes to stderr naming the site. The two cross-kind casts here
|
|
;;;; sit inside a dotimes that runs them eight times each, and stderr gets
|
|
;;;; two lines, because the warning is per *site*: these casts live in frame
|
|
;;;; loops and a per-value line would be a flood rather than a diagnostic.
|
|
;;;; 3. A box holding something that is not a number. That still traps, the way
|
|
;;;; a typed parameter traps on it today, and the runtime owns the sentence.
|
|
;;;; It is the last thing main does, so everything above it has printed.
|
|
|
|
;; The box. Unannotated parameters are dyn, so this is the boxing site and the
|
|
;; call below is where a typed literal crosses in.
|
|
(defn as-dyn [x] dyn x)
|
|
|
|
(defn main [] ()
|
|
(let [i (as-dyn 7)
|
|
f (as-dyn 2.5)]
|
|
;; ── 1. Same kind: the cast is the unbox ──────────────────────────
|
|
;; An int box to every integer width, and a float box to both floats.
|
|
;; None of these warns: the box holds what was asked for.
|
|
(print (i64 i))
|
|
(print "\n")
|
|
(print (i64 (i32 i)))
|
|
(print "\n")
|
|
(print (i64 (u32 i)))
|
|
(print "\n")
|
|
(print (i64 (u8 i)))
|
|
(print "\n")
|
|
(print (f64 f))
|
|
(print "\n")
|
|
(print (f64 (f32 f)))
|
|
(print "\n")
|
|
|
|
;; ── 2. Cross kind: it converts, and warns once for the site ──────
|
|
;; (f64 int-box) is 7 -> 7.0, the same widening (f64 7) does on a typed
|
|
;; operand. (i64 float-box) is 2.5 -> 2, the same truncation toward zero
|
|
;; (i64 2.5) does — range-checked by the emitter's own check_cast, because
|
|
;; the arm really is that cast with an unbox in front of it.
|
|
;;
|
|
;; Eight turns of the loop, two sites, two lines on stderr.
|
|
(dotimes [n 8]
|
|
(print (f64 i))
|
|
(print "\n")
|
|
(print (i64 f))
|
|
(print "\n"))
|
|
|
|
;; A third site, and the third warning. An int box straight to f32 is one
|
|
;; sitofp from i64, which is what (f32 x) on a typed i64 is. Written down
|
|
;; because the tempting "fix" — go through f64 and then narrow — rounds
|
|
;; twice and is a different number for values an i64 can hold and an f64
|
|
;; cannot round to an f32 the same way.
|
|
(print (f64 (f32 i)))
|
|
(print "\n"))
|
|
|
|
;; ── 3. And the box that holds no number ──────────────────────────────
|
|
;; A bool, which is what the typed parameter boundary already refuses: a dyn
|
|
;; holding true does not satisfy an i64 there and does not satisfy (i64 x)
|
|
;; here. The runtime owns the message.
|
|
(print (i64 (as-dyn true)))
|
|
(print "\n"))
|