Created
November 7, 2022 17:44
-
-
Save jgpc42/841c277d465d90241d67999e5073b1d2 to your computer and use it in GitHub Desktop.
Simple mutable data class with clojure.asm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*clojure-version* ;; => {:major 1, :minor 10, :incremental 3, :qualifier nil} | |
(System/getProperty "java.version") ;; => "14.0.1" | |
(import [clojure.asm ClassVisitor ClassWriter Opcodes Type] | |
[clojure.lang DynamicClassLoader RT]) | |
(defn type-to-desc [t] | |
(case t | |
:int "I" | |
;; ... and so on | |
(-> (Type/getType t) .getDescriptor))) | |
(defn mutable-acc-type [class-name types] | |
(let [base-type "java/lang/Object" | |
cv (doto (ClassWriter. ClassWriter/COMPUTE_FRAMES) | |
(.visit Opcodes/V1_7 | |
(bit-or Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL) | |
(.replace class-name \. \/) | |
nil base-type nil))] | |
(doto (.visitMethod cv Opcodes/ACC_PUBLIC "<init>" "()V" nil nil) | |
(.visitCode) | |
(.visitVarInsn Opcodes/ALOAD 0) | |
(.visitMethodInsn Opcodes/INVOKESPECIAL base-type "<init>" "()V" false) | |
(.visitInsn Opcodes/RETURN) | |
(.visitMaxs -1 -1) | |
(.visitEnd)) | |
(dorun (for [[i t] (map vector (range) types)] | |
(doto (.visitField cv Opcodes/ACC_PUBLIC (str "m" i) (type-to-desc t) nil nil) | |
(.visitEnd)))) | |
(-> (RT/makeClassLoader) | |
(.defineClass class-name (.toByteArray cv) nil) | |
(.newInstance)))) | |
(comment | |
(def obj (mutable-acc-type "my.pkg.Foo" [:int Object String])) | |
[(.m0 obj) (.m1 obj) (.m2 obj)] ;; => [0 nil nil] | |
(do (set! (.m0 obj) 42) | |
(set! (.m1 obj) [1 2 3]) | |
(set! (.m2 obj) "fred")) | |
[(.m0 obj) (.m1 obj) (.m2 obj)] ;; => [42 [1 2 3] "fred"] | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment