type returns the JVM class (Clojure semantics) (#244)

(type x) was jolt's internal taxonomy keyword (:string/:set/:jolt/inst), which
breaks any library dispatching a multimethod on [(type a) (type b)] against
java/clojure.lang classes (e.g. clojure.tools.logging.test's matchers). Make the
PUBLIC clojure.core/type Clojure's (or (:type meta) (class x)).

The taxonomy keyword stays the core model: natives-meta.ss keeps jolt-type and
exposes it as __type-tag, which print-method/print-dup dispatch on (so #uuid/#regex/
records still print). The JVM mapping lives in the java host layer — host-class.ss
defines the public type next to (class …), and a jinst now reports java.util.Date
(was :jolt/inst). So the core emits the taxonomy and the java layer remaps it in one
place. unit.edn's type suite updated to the class names. make test green.

Co-authored-by: Yogthos <yogthos@gmail.com>
This commit is contained in:
Dmitri Sotnikov 2026-06-26 21:14:06 +00:00 committed by GitHub
parent 6c03dffd00
commit 687dc60af6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 56 additions and 36 deletions

View file

@ -65,6 +65,19 @@
(def-var! "clojure.core" "class" jolt-class)
;; The PUBLIC clojure.core/type — Clojure's (or (:type meta) (class x)). This is the
;; java host layer's job: the core taxonomy (natives-meta.ss jolt-type, kept under
;; __type-tag for print-method) is JVM-free, and the JVM class mapping lives HERE,
;; next to (class …). The inst/array/byte-buffer host files extend `class` (a
;; class-arm or jolt-type fallthrough) and re-point `type` at this same fn, so the
;; remap of every value — :jolt/inst -> java.util.Date etc. — happens in one place.
(define ty-meta-key (keyword #f "type"))
(define (jolt-type-pub x)
(let* ((m (jolt-meta x))
(override (if (jolt-nil? m) jolt-nil (jolt-get m ty-meta-key jolt-nil))))
(if (not (jolt-nil? override)) override (jolt-class x))))
(def-var! "clojure.core" "type" jolt-type-pub)
;; bare class-name tokens -> canonical JVM class-name strings.
(define class-token-alist
'(("String" . "java.lang.String") ("Number" . "java.lang.Number")

View file

@ -280,6 +280,10 @@
(register-hash-arm! jinst? (lambda (x) (jolt-hash (jinst-ms x))))
;; #inst is a java.util.Date — (class x) / (type x) report that, not the internal
;; :jolt/inst tag (which print-method still dispatches on via __type-tag).
(register-class-arm! jinst? (lambda (x) "java.util.Date"))
;; java.time.Instant is nano-precise: two Instants are = when their epoch-nanos
;; match (so an Instant and one shifted by a single nanosecond differ).
(define (jt-instant-tag? x) (and (jhost? x) (string=? (jhost-tag x) "instant")))
@ -303,7 +307,6 @@
(define %it-type jolt-type)
(set! jolt-type (lambda (x) (if (jinst? x) inst-type-kw (%it-type x))))
(def-var! "clojure.core" "type" jolt-type)
;; instance? java.util.Date -> a jinst; java.time.Instant/LocalDateTime -> the
;; matching jhost tag. The instance? macro passes the class-name symbol.

View file

@ -319,7 +319,6 @@
(define io-kw-file (keyword "jolt" "file"))
(define %io-type jolt-type)
(set! jolt-type (lambda (x) (if (jfile? x) io-kw-file (%io-type x))))
(def-var! "clojure.core" "type" jolt-type)
;; (instance? java.io.File f): the instance? macro passes the class-name symbol;
;; match "File" / "java.io.File" (and any *.File) against a jfile.

View file

@ -156,7 +156,6 @@
;; (jolt-type …) for arrays, so extending jolt-type covers both.
(define %na-type jolt-type)
(set! jolt-type (lambda (x) (if (jolt-array? x) (na-array-class-name x) (%na-type x))))
(def-var! "clojure.core" "type" jolt-type)
;; instance? over an array class token ([I, [C, …). An array token reaches us as
;; a string ("[C", from (Class/forName "[C")) — the dispatcher leaves it a string

View file

@ -132,4 +132,10 @@
((procedure? x) ty-fn)
(else ty-object))))
;; jolt-type is the keyword TAXONOMY (:string/:set/:jolt/inst/…) — jolt's native
;; value model, with no JVM in it. print-method/print-dup dispatch on it (via
;; __type-tag). The PUBLIC clojure.core/type is Clojure's (or (:type meta) (class
;; x)) — a JVM class — but that mapping belongs to the java host layer (host-class.ss
;; rebinds `type` next to `class`), so this core layer stays JVM-free.
(def-var! "clojure.core" "__type-tag" jolt-type)
(def-var! "clojure.core" "type" jolt-type)

View file

@ -967,11 +967,11 @@
(guard (e (#t #f))
(def-var-with-meta! "clojure.core" "line-seq" (letrec ((line-seq (lambda (rdr) (let fnrec2450 ((rdr rdr)) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "string?") rdr)) (jolt-seq (jolt-invoke (var-deref "clojure.core" "str-split") "\n" rdr)) (jolt-invoke (var-deref "clojure.core" "make-lazy-seq") (lambda () (let fnrec2451 () (jolt-invoke (var-deref "clojure.core" "coll->cells") (let* ((line (jolt-invoke (var-deref "clojure.core" "-read-line") rdr))) (if (jolt-truthy? line) (jolt-cons line (line-seq rdr)) jolt-nil))))))))))) line-seq) (let* ((_o$2452 (keyword #f "doc")) (_o$2453 "Returns the lines of text from rdr as a lazy sequence of strings, as by\n read-line. (Jolt extension kept from the old kernel stub: a plain string\n splits into its lines.)")) (jolt-hash-map _o$2452 _o$2453))))
(guard (e (#t #f))
(jolt-invoke (var-deref "clojure.core" "defmulti-setup") (jolt-symbol #f "print-method") (lambda (x writer) (let fnrec2454 ((x x) (writer writer)) (let* ((t (jolt-get (jolt-invoke (var-deref "clojure.core" "meta") x) (keyword #f "type")))) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "keyword?") t)) t (jolt-invoke (var-deref "clojure.core" "type") x)))))))
(jolt-invoke (var-deref "clojure.core" "defmulti-setup") (jolt-symbol #f "print-method") (lambda (x writer) (let fnrec2454 ((x x) (writer writer)) (let* ((t (jolt-get (jolt-invoke (var-deref "clojure.core" "meta") x) (keyword #f "type")))) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "keyword?") t)) t (jolt-invoke (var-deref "clojure.core" "__type-tag") x)))))))
(guard (e (#t #f))
(jolt-invoke (var-deref "clojure.core" "defmethod-setup") (jolt-symbol #f "print-method") (keyword #f "default") (lambda (o w) (let fnrec2455 ((o o) (w w)) (begin (record-method-dispatch w "write" (jolt-vector (jolt-invoke (var-deref "clojure.core" "__pr-str1") o))) jolt-nil)))))
(guard (e (#t #f))
(jolt-invoke (var-deref "clojure.core" "defmulti-setup") (jolt-symbol #f "print-dup") (lambda (x writer) (let fnrec2456 ((x x) (writer writer)) (let* ((t (jolt-get (jolt-invoke (var-deref "clojure.core" "meta") x) (keyword #f "type")))) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "keyword?") t)) t (jolt-invoke (var-deref "clojure.core" "type") x)))))))
(jolt-invoke (var-deref "clojure.core" "defmulti-setup") (jolt-symbol #f "print-dup") (lambda (x writer) (let fnrec2456 ((x x) (writer writer)) (let* ((t (jolt-get (jolt-invoke (var-deref "clojure.core" "meta") x) (keyword #f "type")))) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "keyword?") t)) t (jolt-invoke (var-deref "clojure.core" "__type-tag") x)))))))
(guard (e (#t #f))
(jolt-invoke (var-deref "clojure.core" "defmethod-setup") (jolt-symbol #f "print-dup") (keyword #f "default") (lambda (o w) (let fnrec2457 ((o o) (w w)) (jolt-invoke (var-deref "clojure.core" "print-method") o w)))))
(guard (e (#t #f))