clojure-dev

Issues: https://clojure.atlassian.net/browse/CLJ | Guide: https://insideclojure.org/2015/05/01/contributing-clojure/
2020-09-07T01:04:46.027900Z

Classes like PersistentTreeSet PersistentTreeMap PersistentVector all have create methods, and the default print-dup method for objects of some of those types generate #= strings that contain calls to the create methods of those classes, like so:

user=> (binding [*print-dup* true] (print (sorted-set 3 2 1)))
#=(clojure.lang.PersistentTreeSet/create [1 2 3])nil

👋 1
2020-09-07T01:06:35.029600Z

This also happens when printing a primitive vector, except as far as I can tell, class clojure.core.Vec has no create method, and classes created with deftype (as clojure.core.Vec is) cannot have static methods. Does that sound correct?

user=> (binding [*print-dup* true] (print (vector-of :byte 1 2 3)))
#=(clojure.core.Vec/create [#=(java.lang.Byte. "1") #=(java.lang.Byte. "2") #=(java.lang.Byte. "3")])nil

alexmiller 2020-09-07T13:33:02.036100Z

The first part about PersistentTreeSet etc is correct. The Vec stuff, not sure

2020-09-07T01:12:12.031800Z

On a perhaps only tangentially related note (in the sense that I discovered both behaviors while investigating if it is possible to make tagged literals for (vector-of :byte 1 2 3) ), I am having trouble figuring out why the following exception occurs:

$ cat deps.edn 
{:deps {org.clojure/clojure {:mvn/version "1.10.1"}} :paths ["."]}

$ cat data_readers.clj 
{bs user/read-bytes}

$ clojure -e "(defn read-bytes [bs] (apply vector-of :byte bs)) (class '#bs [-1 0 1])"
#'user/read-bytes
Syntax error compiling fn* at (REPL:1:51).
Can't embed object in code, maybe print-dup not defined: clojure.core$reify__8311@6ccdb29f

Full report at:
/var/folders/rv/2vbzx7zj64x4hss7rdl1xywc0000gn/T/clojure-8633821538019017760.edn

2020-09-07T11:26:03.034500Z

I couldn't figure out why the array manager would ever try to get printed, especially since the vec object print-dups just fine

2020-09-07T11:26:30.034700Z

Also removing the quote makes the error go away

2020-09-07T11:27:13.034900Z

Which I guess is probably due to two separate compiler codepaths

2020-09-07T13:57:49.036300Z

Removing the quote probably leads to a different non-ideal behavior, which is that the primitive vector is eval'd, and eval for such vector returns a PersistentVector. The quote was my experimental attempt to keep the primitive vector

2020-09-07T13:59:33.036500Z

Thanks @hiredman for the details. That is helpful, and seems likely the reason why the exception is occurring.

2020-09-07T14:00:16.036700Z

I guess there isn't really a way without modifying Java source code for Clojure's implementation to cause the compiler to use the print-dup method of a deftype type?

2020-09-07T14:01:46.036900Z

I am not sure if it were possible, whether it would 'solve the problem', as the problem is only vaguely defined as 'it might be cool if it were easier to have tagged literals for primitive byte vectors that could be conveniently used in Clojure source code'.

2020-09-07T14:12:21.037100Z

> eval for such vector returns a PersistentVector ☝️ that could be changed, right?

2020-09-07T14:22:55.037300Z

Only by changing Java code in Clojure implementation, I believe?

2020-09-07T14:23:53.037500Z

And not clear to me yet whether it would avoid the exception when trying to use a vector of bytes in-line in source code.

2020-09-07T14:25:25.037700Z

I'm currently in a situation where it isn't clear to me whether the output of print-dup ought to be used for in-line occurrences of data structures, or at least for which subset of JVM objects it should, and which it should not.

2020-09-07T14:25:50.037900Z

If Clojure core folks believe eval'ing a primitive vector should return a primitive vector, that would be cool.

2020-09-07T14:26:59.038100Z

or at least I am not aware of any reasons why such a change would lead to problems, but given my level of understanding of the interdependencies of behavior, my 'that would be cool' statement above betrays 17 levels of ignorance.

2020-09-07T14:28:33.038300Z

agreed that it requires a java change

2020-09-07T14:28:59.038500Z

I was just supposing that it was perhaps the most idealogically-correct solution, though maybe not most-likely-to-be-implemented

2020-09-07T15:49:10.038700Z

In a few further experiments, it seems that print-dup behavior is pretty much independent of the reason for the exception -- the Compiler class code for emitValue does not seem to use print-dup in any way I can see, at least not for objects whose types are created by deftype.

2020-09-07T15:50:45.039Z

For objects with types created via deftype, it will currently always try to do emitValue on every field of the object. The values of those fields might use print-dup behavior defined for them, but that depends upon what the class of those fields happens to be.

2020-09-08T12:24:40.039200Z

but print-dup is presumably the fallback case, and thus gets used for the reify

2020-09-08T13:57:16.039400Z

That is correct.

2020-09-08T13:57:26.039600Z

I have added some more analysis of the cause of the exception here: https://github.com/jafingerhut/vec-data-reader

2020-09-07T01:14:05.032Z

More details on the stack backtrace in a thread, in case people are interested:

$ clojure
Clojure 1.10.1
user=> (defn read-bytes [bs] (apply vector-of :byte bs))
#'user/read-bytes
user=> (class '#bs [-1 0 1])
Syntax error compiling fn* at (REPL:1:1).
Can't embed object in code, maybe print-dup not defined: clojure.core$reify__8311@5f7b97da
user=> (pst)
Note: The following stack trace applies to the reader or compiler, your code was not executed.
CompilerException Syntax error compiling fn* at (1:1). #:clojure.error{:phase :compile-syntax-check, :line 1, :column 1, :source "NO_SOURCE_PATH", :symbol fn*}
	clojure.lang.Compiler.analyzeSeq (Compiler.java:7115)
	clojure.lang.Compiler.analyze (Compiler.java:6789)
	clojure.lang.Compiler.eval (Compiler.java:7174)
	clojure.lang.Compiler.eval (Compiler.java:7132)
	clojure.core/eval (core.clj:3214)
	clojure.core/eval (core.clj:3210)
	clojure.main/repl/read-eval-print--9086/fn--9089 (main.clj:437)
	clojure.main/repl/read-eval-print--9086 (main.clj:437)
	clojure.main/repl/fn--9095 (main.clj:458)
	clojure.main/repl (main.clj:458)
	clojure.main/repl-opt (main.clj:522)
	clojure.main/main (main.clj:667)
Caused by:
RuntimeException Can't embed object in code, maybe print-dup not defined: clojure.core$reify__8311@5f7b97da
	clojure.lang.Util.runtimeException (Util.java:221)
	clojure.lang.Compiler$ObjExpr.emitValue (Compiler.java:4893)
	clojure.lang.Compiler$ObjExpr.emitValue (Compiler.java:4808)
	clojure.lang.Compiler$ObjExpr.emitConstants (Compiler.java:4934)
	clojure.lang.Compiler$ObjExpr.compile (Compiler.java:4612)
	clojure.lang.Compiler$FnExpr.parse (Compiler.java:4106)
	clojure.lang.Compiler.analyzeSeq (Compiler.java:7105)
	clojure.lang.Compiler.analyze (Compiler.java:6789)
nil

2020-09-07T01:16:18.032200Z

Defining a print-dup for class clojure.core.Vec that prints out a string like #user/bs [1 2 3] causes the same exception, so however that ...reify... object is involved in the exception seems independent of print-dup behavior of class clojure.core.Vec ,but I am not certain about that.

2020-09-07T01:50:10.032400Z

why's the single-quote in front of #bs?

2020-09-07T01:53:59.032600Z

This is a good puzzle. The behavior goes back to clojure 1.4 But I can't play with it anymore tonight :(

2020-09-07T02:41:09.032800Z

Yeah, no urgency on this, more of a puzzle I am curious about and may spend a little time on looking for answers. Inspired by this question here: https://ask.clojure.org/index.php/9567/possible-create-tagged-literal-reader-for-clojure-core-vec

2020-09-07T05:16:30.033200Z

That is the same exception you get if you return a function object from macro that closed over some value

2020-09-07T05:17:46.033400Z

For pretty much the same reason, you have a reify that closes over some value (from the gvec implementation) being passed to the evaluator, and it doesn't know how to embed that in byte code

2020-09-07T05:21:05.033600Z

You should see the same thing with something like (eval (fn [] ~(read-bytes ....)))`

2020-09-07T05:25:42.033800Z

And the reify that it is throwing on is likely the array manager reify in gvec

2020-09-07T05:35:22.034300Z

Actually the exception is a little different from the closed over fn case, but I think that is till correct. Deftypes actually have special handling in the compiler if I recall for being constructed into byte code, so the generic print-dup path is never hit for gvec