diff --git a/CHANGELOG.md b/CHANGELOG.md index baf31495..ea14ad4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ SCI is used in [babashka](https://github.com/babashka/babashka), [joyride](https://github.com/BetterThanTomorrow/joyride/) and many [other](https://github.com/babashka/sci#projects-using-sci) projects. +## Unreleased + +- Support `hashCode` on `deftype` + ## 0.11.50 (2025-12-23) - Add support for `:refer-global` and `:require-global` diff --git a/src/sci/impl/deftype.cljc b/src/sci/impl/deftype.cljc index 4ce965f1..0f9d506a 100644 --- a/src/sci/impl/deftype.cljc +++ b/src/sci/impl/deftype.cljc @@ -35,6 +35,12 @@ (defmethod equals :default [this other] (identical? this other)))) +#?(:clj + (do + (defmulti hashCode types/type-impl) + (defmethod hashCode :default [this] + (System/identityHashCode this)))) + (defn clojure-str [v] ;; #object[user.Foo 0x743e63ce "user.Foo@743e63ce"] (let [n (types/type-impl v)] @@ -53,6 +59,8 @@ (to-string this)) #?(:clj (equals [this other] (sci.impl.deftype/equals this other))) + #?(:clj (hashCode [this] + (sci.impl.deftype/hashCode this))) sci.impl.types/SciTypeInstance (-get-type [_] diff --git a/src/sci/impl/namespaces.cljc b/src/sci/impl/namespaces.cljc index bf322cc9..3dcf2f10 100644 --- a/src/sci/impl/namespaces.cljc +++ b/src/sci/impl/namespaces.cljc @@ -837,7 +837,8 @@ {:obj (sci.lang/->Namespace 'sci.impl.deftype nil) :private true 'toString sci.impl.deftype/to-string - #?@(:clj ['equals sci.impl.deftype/equals]) + #?@(:clj ['equals sci.impl.deftype/equals + 'hashCode sci.impl.deftype/hashCode]) '-create-type -create-type '->type-impl sci.impl.deftype/->type-impl '-inner-impl sci.impl.types/getVal diff --git a/test/sci/records_test.cljc b/test/sci/defrecords_and_defype_test.cljc similarity index 98% rename from test/sci/records_test.cljc rename to test/sci/defrecords_and_defype_test.cljc index 6a3f72c9..bb182cca 100644 --- a/test/sci/records_test.cljc +++ b/test/sci/defrecords_and_defype_test.cljc @@ -1,4 +1,4 @@ -(ns sci.records-test +(ns sci.defrecords-and-defype-test (:require [clojure.string :as str] [clojure.test :refer [are deftest is testing]] @@ -223,7 +223,9 @@ (is (true? (tu/eval* "(deftype Foo []) (instance? Foo (->Foo))" {}))) (is (true? (tu/eval* "(ns bar) (deftype Foo []) (ns foo (:import [bar Foo])) (instance? Foo (Foo.))" {}))) (is (= "dude" (tu/eval* "(deftype Dude [] Object (toString [_] \"dude\")) (str (->Dude))" {}))) - #?(:clj (is (= [true false] (tu/eval* "(deftype Dude [x] Object (toString [_] (str x)) (equals [this other] (= (str this) (str other)))) [(= (->Dude 1) (->Dude 1)) (= (->Dude 1) (->Dude 2))]" {}))))) + #?(:clj (is (= [true false] (tu/eval* "(deftype Dude [x] Object (toString [_] (str x)) (equals [this other] (= (str this) (str other)))) [(= (->Dude 1) (->Dude 1)) (= (->Dude 1) (->Dude 2))]" {})))) + #?(:clj (is (true? (tu/eval* "(deftype Dude [x] Object (hashCode [_] 1)) +(deftype Dude2 [x]) (and (= 1 (hash (Dude. 1337))) (not= 1 (hash (Dude2.))))" {}))))) (deftest equiv-test (let [prog "(defrecord Foo [a]) (defrecord Bar [a]) [(= (->Foo 1) (->Foo 1)) (= (->Foo 1) (->Bar 1)) (= (->Foo 1) {:a 1})]"] diff --git a/test/sci/test_runner.cljs b/test/sci/test_runner.cljs index d0924e14..1f0fbfb7 100644 --- a/test/sci/test_runner.cljs +++ b/test/sci/test_runner.cljs @@ -14,7 +14,7 @@ [sci.parse-test] [sci.protocols-test] [sci.read-test] - [sci.records-test] + [sci.defrecords-and-defype-test] [sci.reify-test] [sci.repl-test] [sci.test-utils :refer [planck-env?]]