Welcome! Please see the About page for a little more info on how this works.

0 votes
in Clojure by
retagged by

When a non-empty queue is evaluated, the compiler does not attempt to execute it (as it would a Seq), but it is seen as a PersistentList and therefore sent to clojure.lang.Compiler/emitListAsObjectArray. This is an error, since a queue is not a list.

=> (eval (conj clojure.lang.PersistentQueue/EMPTY 1)) Syntax error (ClassCastException) compiling fn* at (REPL:1:1). class clojure.lang.PersistentQueue cannot be cast to class java.util.List (clojure.lang.PersistentQueue is in unnamed module of loader 'app'; java.util.List is in module java.base of loader 'bootstrap')

The stack trace is:

`
Syntax error compiling fn* at (1:1).

at clojure.lang.Compiler.analyzeSeq(Compiler.java:7119)
at clojure.lang.Compiler.analyze(Compiler.java:6793)
at clojure.lang.Compiler.eval(Compiler.java:7178)
at clojure.lang.Compiler.eval(Compiler.java:7136)
at clojure.core$eval.invokeStatic(core.clj:3202)
at clojure.core$eval.invoke(core.clj:3198)
at user$eval242.invokeStatic(NO_SOURCE_FILE:1)
at user$eval242.invoke(NO_SOURCE_FILE:1)
at clojure.lang.Compiler.eval(Compiler.java:7181)
at clojure.lang.Compiler.eval(Compiler.java:7136)
at clojure.core$eval.invokeStatic(core.clj:3202)
at clojure.core$eval.invoke(core.clj:3198)
at clojure.main$repl$read_eval_print__9110$fn__9113.invoke(main.clj:437)
at clojure.main$repl$read_eval_print__9110.invoke(main.clj:437)
at clojure.main$repl$fn__9119.invoke(main.clj:458)
at clojure.main$repl.invokeStatic(main.clj:458)
at clojure.main$repl_opt.invokeStatic(main.clj:522)
at clojure.main$main.invokeStatic(main.clj:667)
at clojure.main$main.doInvoke(main.clj:616)
at clojure.lang.RestFn.invoke(RestFn.java:397)
at clojure.lang.AFn.applyToHelper(AFn.java:152)
at clojure.lang.RestFn.applyTo(RestFn.java:132)
at clojure.lang.Var.applyTo(Var.java:705)
at clojure.main.main(main.java:40)

Caused by: java.lang.ClassCastException: class clojure.lang.PersistentQueue cannot be cast to class java.util.List (clojure.lang.PersistentQueue is in unnamed module of loader "app";
java.util.List is in module java.base of loader "bootstrap")

at clojure.lang.Compiler$ObjExpr.emitListAsObjectArray(Compiler.java:4701)
at clojure.lang.Compiler$ObjExpr.emitValue(Compiler.java:4874)
at clojure.lang.Compiler$ObjExpr.emitConstants(Compiler.java:4938)
at clojure.lang.Compiler$ObjExpr.compile(Compiler.java:4616)
at clojure.lang.Compiler$FnExpr.parse(Compiler.java:4110)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:7109)
... 23 more`

1 Answer

0 votes
by

Logged as https://clojure.atlassian.net/browse/CLJ-2628 with some options.

by
Thanks for looking at this. I have some comments on the alternatives on the ticket:

- If PersistentQueue implements j.u.List then this will continue to print a list, even when that is not what is being returned. So if a macro tries to return a queue (even inside another seq) it will get converted to a list. So it wouldn't be possible to return a queue from a macro. That's already the case now:
=> (defmacro m [] clojure.lang.PersistentQueue/EMPTY)
=> (m)
()
user=> (type (m))
clojure.lang.PersistentList$EmptyList

- How would a specialized PQ emit work?

Right now, the test in emitValue is checking for ISeq, or IPersistentList. There are only 2 types that implement IPersistentList: PersistentList and PersistentQueue. PersistentList is already an ISeq, so the check for IPersistentList is the specific cause of the problem here. Removing it would let it fall through to RT.printString(value) which is where most objects without a literal representation fall through too.

This leads to another question (one that I'm passing along from someone else, but I've thought about myself): has thought been given to a literal representation for queues?
ClojureScript has: #queue [1 2 3]
For a structure that's built into the language, then it might be worthy of its own special reader macro, such as #[1 2 3]
This would provide a path for emitting a structure that could be read back
by
>  If PersistentQueue implements j.u.List then this will continue to print a list

true, I haven't thought about all the tradeoffs, just throwing out ideas

> How would a specialized PQ emit work?

That method has lots, could add another. Again, no idea on tradeoffs without more eval.


There is an old ticket for read/print support on queues:

https://ask.clojure.org/index.php/3365/implement-reader-literal-support-persistentqueue-structure

The question I ask myself is whether queues are important enough to warrant adding syntax to Clojure. I don't have a good answer for that - ultimately it's not my call. :) But any further comments specific to that can go there.
...