This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-08-16
Channels
- # announcements (3)
- # babashka (48)
- # beginners (35)
- # calva (3)
- # chlorine-clover (5)
- # clj-kondo (9)
- # cljdoc (20)
- # cljsrn (1)
- # clojure (55)
- # clojure-europe (33)
- # clojure-nl (3)
- # clojure-norway (6)
- # clojure-spec (7)
- # clojure-uk (27)
- # clojurescript (95)
- # closh (1)
- # conjure (1)
- # cursive (16)
- # datomic (30)
- # emacs (7)
- # honeysql (1)
- # hugsql (2)
- # introduce-yourself (2)
- # jobs (1)
- # lsp (30)
- # malli (22)
- # nbb (11)
- # news-and-articles (1)
- # off-topic (8)
- # pathom (21)
- # polylith (41)
- # portal (4)
- # practicalli (4)
- # protojure (1)
- # re-frame (14)
- # releases (1)
- # restql (1)
- # reveal (24)
- # sci (1)
- # sql (21)
- # vim (11)
- # xtdb (33)
A question about gen-class
. I'm trying to use Quil and I noticed that a huge amount of time is spent on... changing color of the lines.
The sampling results are on the screenshot. And here's the relevant code:
(gen-class
:name "quil.Applet"
:implements [clojure.lang.IMeta]
:extends processing.core.PApplet
:state state
:init quil-applet-init
:constructors {[java.util.Map] []}
:exposes-methods {keyTyped keyTypedParent
mouseDragged mouseDraggedParent
keyPressed keyPressedParent
mouseExited mouseExitedParent
mouseClicked mouseClickedParent
mouseEntered mouseEnteredParent
mouseMoved mouseMovedParent
keyReleased keyReleasedParent
mousePressed mousePressedParent
focusGained focusGainedParent
frameRate frameRateParent
mouseReleased mouseReleasedParent
focusLost focusLostParent
sketchFullScreen sketchFullScreenParent})
(defn -meta [this]
(.state this))
So it seems to me that Clojure doesn't know that this
above is an instance of quil.Applet
. Is that observation correct? How should it be fixed?https://clojure.wladyka.eu/posts/how-to-improve-algorithm-performance/#avoid-reflections
The pic shows that the reflection happens inside Quil itself, right in that -meta
function - assuming I'm reading the sampling results correctly.
Meaning, that Clojure doesn't assume that this
is an instance of quil.Applet
. I would like to confirm that.
I do not control the source code of Quil. :) I'd have to learn how to build it first - and before going down that potentially complicated path, I'd like to confirm my guess.
Changing the color of a line is IO. IO is generally the most expensive part of your code, right? I’ve no idea whether it’s unreasonably expensive in this case, though, or whether you’ve got other, similar IO that’s less expensive.
I’ve been annoyed with rendering times as well while tinkering with quil
, but I assume it’s par for the course when you’re used to iterating on mostly pure functions 🙂
How is it IO? It's just storing a constant to be used for the following rendering operations. You can see from the screenshot above that the vast majority of the time is spent in the reflection, not in some IO.
Oh, sorry. I didn’t look into the details 😕 I thought you were talking specifically about changing the image.
Pardon the noise!
It is inside gen-class
. Which works only during AOT. So unless *warn-on-compile*
was set when Quil was built, it won't show anything.
Unless, of course, I misunderstand how it all works. Either way, there are no warnings. But that Reflector
call is still there.
I'm curious why some reader tags throw when evaluated on their own. For example, take the #ordered/map
tag (reader kv defined https://github.com/clj-commons/ordered/blob/12044526cdda3f0ff08176666210022397621997/src/data_readers.clj#L2, https://github.com/clj-commons/ordered/blob/12044526cdda3f0ff08176666210022397621997/src/flatland/ordered/map.clj#L149). If I eval the following code, I get an exception thrown (full stacktrace in thread).
(do #ordered/map ([:b 2] [:a 1] [:d 4]))
Syntax error (IllegalArgumentException) compiling fn* at (src/example.clj:6:3).
Unable to resolve classname: IPersistentMap
The map is read and the data reader fn is called as expected.
(def omap #ordered/map ([:b 2] [:a 1] [:d 4]))
=> #'example/omap
(type omap)
=> flatland.ordered.map.OrderedMap
It's only when evaling just the tagged literal that the ex is thrown. Any idea why this is happening?Full stacktrace
Syntax error compiling fn* at (/src/example.clj:6:3).
at clojure.lang.Compiler.analyzeSeq(Compiler.java:7119)
java.lang.IllegalArgumentException: Unable to resolve classname: IPersistentMap
at clojure.lang.Compiler$HostExpr.tagToClass(Compiler.java:1129)
at clojure.lang.Compiler.tagClass(Compiler.java:8693)
at clojure.lang.Compiler$ObjExpr.emitValue(Compiler.java:4810)
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)
at clojure.lang.Compiler.analyze(Compiler.java:6793)
at clojure.lang.Compiler.eval(Compiler.java:7178)
at clojure.lang.Compiler.eval(Compiler.java:7171)
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 nrepl.middleware.interruptible_eval$evaluate$fn__939.invoke(interruptible_eval.clj:91)
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.doInvoke(main.clj:368)
at clojure.lang.RestFn.invoke(RestFn.java:1523)
at nrepl.middleware.interruptible_eval$evaluate.invokeStatic(interruptible_eval.clj:84)
at nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:56)
at nrepl.middleware.interruptible_eval$interruptible_eval$fn__965$fn__969.invoke(interruptible_eval.clj:155)
at clojure.lang.AFn.run(AFn.java:22)
at nrepl.middleware.session$session_exec$main_loop__1067$fn__1071.invoke(session.clj:190)
at nrepl.middleware.session$session_exec$main_loop__1067.invoke(session.clj:189)
at clojure.lang.AFn.run(AFn.java:22)
at java.base/java.lang.Thread.run(Thread.java:829)
I'm not sure, but I think that in one scenario, the namespace context is being set correctly, and in the other it isn't? The OrderedType
type has metadata with class information on it saying IPersistentMap
, and in the form that doesn't throw the error it's resolving that to clojure.lang.*
? But I think it has something to do with it being emitted, because the code successfully runs.
if you redefine the ordered-map
function like this:
(defn ordered-map
"Return a map with the given keys and values, whose entries are
sorted in the order that keys are added. assoc'ing a key that is
already in an ordered map leaves its order unchanged. dissoc'ing a
key and then later assoc'ing it puts it at the end, as if it were
assoc'ed for the first time. Supports transient."
([] empty-ordered-map)
([coll]
(prn '->> coll (into empty-ordered-map coll))
(reduce #(assoc %1 (first %2) (second %2)) {} coll))
([k v & more]
(apply assoc empty-ordered-map k v more)))
you get this output
flatland.ordered.map=> (do #ordered/map ([:b 2] [:a 1] [:d 4]))
->> ([:b 2] [:a 1] [:d 4]) #ordered/map ([:b 2] [:a 1] [:d 4])
->> ([:b 2] [:a 1] [:d 4]) #ordered/map ([:b 2] [:a 1] [:d 4])
{:b 2, :a 1, :d 4}
also, notice that you don't get the error if you eval from within the flatland.ordered.map
namespace
fyi, I opened an ask.clojure https://ask.clojure.org/index.php/10945/why-do-some-reader-tags-throw-when-evaluated-on-their-own
I'm writing a blog post and want to showcase how Clojure is built from just a few "keywords", meaning that there's only a few built in definitions in the Clojure language, and the rest are from clojure/core.
I remember Rich Hickey telling the exact number of those base keywords in some talk but can't find it anywhere. Anyone know what it's at the moment?
I mean words like class
interface
void
etc.
the source of truth: if it's interned to compiler state here, it is part of the compiler and not defined in clojure code https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L40
If I have this code:
(ns test)
(set! *warn-on-reflection* true)
(definterface Foo
(methodA []))
(defn make-foo
[]
(proxy [Foo] []
(methodA [] 1)))
(defn method-a
[^Foo foo]
(.methodA foo))
(comment
(method-a (make-foo)))
And then I re-evaluate the namespace, I get:
class test.proxy$java.lang.Object$Foo$cf6fbe2b cannot be cast to class test.Foo (test.proxy$java.lang.Object$Foo$cf6fbe2b is in unnamed module of loader clojure.lang.DynamicClassLoader @1aa836af; test.Foo is in unnamed module of loader clojure.lang.DynamicClassLoader @63c807fb)
Am I using definterface or type hinting wrong?My guess is that you have a reference to the result of (make-foo)
somewhere and pass it to some place that expects Foo
. You reload test
, you get new Foo
, but the old reference remains, mentioning the old Foo
. A pretty common problem.
And you re-evaluate this namespace in its entirety, and without holding any references to method-a
?
@U2FRKM4TW method-a
is the only place it's referenced and I'm re-evaluating the namespace in its entirety 🙂
is there some reason to use proxy here vs reify?
also I think the proxy method impl needs to take an additional first "this" argument
@U064X3EF3 I thought proxy was anaphoric?
https://clojuredocs.org/clojure.core/proxy examples here suggest so.
Why doesn't reify have this problem? Is the problem with Proxy referencing the wrong Foo?
@U064X3EF3 Oh, I need proxy
because I'm doing java.io.FilterInputStream and need to pass an InputStream.
https://clojure.atlassian.net/browse/CLJ-2379 I've run into this I suppose?
When doing input steam stuff it can be nicer to implement a channel interface and use one of the channel to input stream adapters nio ships with
https://docs.oracle.com/javase/7/docs/api/java/nio/channels/ReadableByteChannel.html and https://docs.oracle.com/javase/8/docs/api/java/nio/channels/Channels.html#newInputStream-java.nio.channels.ReadableByteChannel-
@U0NCTKEV8 You mean, https://docs.oracle.com/javase/8/docs/api/java/nio/channels/Channels.html#newChannel-java.io.InputStream- right? I'm starting with an InputStream.
I'd prefer to stay with an InputStream as I expect my users have one (e.g. to pass it to cheshire)
The thing is, http://java.io is a mess of concrete inheritance and things like filterinputsream which is basically an abstract base class, and every interface has too many methods
(sorry, http://java.io has no interfaces, every abstract base class has too many methods)