- types.janet: make-hierarchy, derive*, ancestors, descendants, isa?, underive - evaluator.janet: defmulti extended with :default and :hierarchy options + keyword dispatch-fns wrapped as (fn [x] (get x kw)) for Janet compat + hierarchy-based dispatch walks isa? chain when no direct match - core.janet: real derive, isa?, ancestors, descendants implementations replacing stubs; core-remove-method, core-remove-all-methods, core-prefer-method added; new core-bindings entries - 5 test sections (22-26): hierarchy ops, basic dispatch, :default, hierarchy dispatch, remove-method — all pass - 317 tests, 0 failures
1.2 KiB
Janet break can't be used inside let blocks — break returns from the innermost loop, and in a let, there's no loop. Pattern: use (var found nil) + (while ... (if condition (do (set found val) (break)))) then check found after loop.
§
core-binding macro: use array-map (plain struct) NOT hash-map/PHM for the binding frame. PHM's phm-get doesn't work with push-thread-bindings' var-get lookup. Symptom: "error: dynamic binding" with no useful message. Fix: emit (array-map [var sym] val ...) instead of (hash-map ...).
§
Janet and returns the last truthy value (not boolean true). (and (table? x) (get x :jolt/deftype)) returns the deftype string, which is truthy but not true. Wrap with (if (and ...) true false) when the return value must be a boolean. This hit core-map? and would hit any predicate returning the result of and.
§
set! field mutation: (set! (.-x obj) val) is read as (set! (. -x obj) val) — the target is an array with . as head. Check for this case BEFORE the existing (.-field obj) shorthand check (which is just (. obj -field)). The reader transforms .-prefixed symbols differently than expected: .-x becomes a symbol -x inside a (. -x obj) array form, NOT a standalone .-x symbol.