This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-02-09
Channels
- # announcements (20)
- # beginners (115)
- # calva (2)
- # clj-kondo (1)
- # clojure (48)
- # clojure-uk (21)
- # clojurescript (20)
- # css (1)
- # cursive (3)
- # datascript (11)
- # datomic (6)
- # duct (26)
- # emacs (5)
- # funcool (6)
- # off-topic (45)
- # perun (1)
- # precept (4)
- # quil (2)
- # re-frame (1)
- # shadow-cljs (251)
- # tools-deps (27)
- # uncomplicate (9)
@jason358 that's really interesting, I would not have imagined the performance changing (as unless I missed something, the code itself is just straight interop), I'd like to look more into that myself
So, indeed when using ^ints I see you get a faster speed for aset
as you mention, and while I don't know the details on what sorts of optimizations Clojure makes behind the scenes (you might say that is my bedrock, when it comes to how low I've dug into Clojure internals) , I just wondered "now that it too has the info that we're setting ints, what if its optimization is too to just flat out skip to Array.setInt
, or something similar?". And then I remembered that our aset-int
is not just calling Array.setInt
, its calling that and coercing the value into an int
before it calls that, and so I am wondering if its this extra step that, when the two are possibly otherwise equal, is knocking aset-int
into second place . Well, so far I tested it and sure enough, I get the same speed for aset ^ints
and flat out calling (. java.lang.reflector.Array (setInt ^ints...))
I'm not 100% sold yet, though, as I'm getting sometimes wildly different timings for both, and I'd like to sit down and properly profile them. Anyways, so that's a possibility.
Have you used criterium before? https://github.com/hugoduncan/criterium
It is fairly quick to learn to use it, and it helps avoid a lot of pitfalls in performance measurement (in particular, it goes a long way to 'warm up' an expression, or cause the JVM's JIT compiler to optimize the byte code to native code, before starting its measurements)
Even so, I would recommend using it to measure some largeish number of iterations of aset or aset-int calls, rather than only a single one.
If you are familiar with Java, or are interested in looking at Java source created by decompiling JVM byte code, there is also https://github.com/clojure-goes-fast/clj-java-decompiler
ah thank you, I have not used criterium, although I was considering it a few minutes ago
There are other projects under the 'clojure-goes-fast' group of projects that may also interest you
This web site links to several blog articles by the author of the clojure-goes-fast projects: http://clojure-goes-fast.com
Lots of good stuff there, if you are interested. If you do dig in, you are welcome to ask about implementation details in #beginners, but #clojure channel will probably have an on-average more-in-depth target audience for such topics.
oh, I hope I didn't give the impression I'm in #beginners to ask questions (not that there's anything wrong with that) ahaha I'd def feel more comfortable asking in #clojure, I just like to follow all the channels and help out when I can 😄 this overall comment itself was just for dmitry's question (although I realize you probably know that and are just pointing out where questions related to that theme would best be answered)
java.lang.reflect.Array
accessors are notoriously slow https://bugs.openjdk.java.net/browse/JDK-8051447
@jason358 final update (hopefully), I dug into it deeper with Andy last night and sure enough its not what I said (or partially not, I have to look again now, I'm currently reviewing / doing a proepr write up of this since this was last night), but seems to have to do with aset actually having an inline implementation that calls another function entirely (`clojure.lang.RT/aset` is called, which actually just straight-up wraps arr[ind] = val
and is overloaded to run generically for Object[]
, and more specifically for the primitive arrays like int[]
. So when called with the ^ints annotation, its flat out calling
static public int aset(int[] xs, int i, int v){
xs[i] = v;
return v;
}
I wonder if it would be a good addition to take aset-int
(and the rest of the primitive aset-*
)and also add an inline to call their respective RT/aset
functions?
Thanks, I've been using just using aset
since my benchmarks clearly showed it to be much faster (because amalloy @IRC told me it might be)
why don't we use java convention for classpath package names, i.e ./org.domain.project.core?
Who do you mean by "we"? http://clojure.org does.
It is project by project whether someone does or not, and many people have obviously chosen not to.
My answer is the same either way 🙂
A few projects do, most do not.
i said we, because out of many clojure libs i've seen only few used conventional package names
we is a set of individuals, each of whom made their own choice, so there could be N different reasons.
I suspect a common one is: it is a pain when starting a small open source project to create a new official domain name, if you do not already have one
you do not necessarily know in advance whether it will become widely used. Once established, changing the name is a pain for users of a library.
Also, in practice, people are good at avoiding conflicts, and/or the newer one deferring to an existing/established one if a conflict is discovered.
I don't know statistics or examples in the Python world, but they don't use the Java convention, and have a much larger collection of library names than Clojure does, I believe, and I haven't heard that the Python world can't find a way to get along without using the Java naming conventions.
If there were billions of people not using the convention and creating a library every day, there would be many more conflicts. The actual rate of library creation for Clojure, Java, and Python are much lower than that, and people creating new libs aren't completely unaware of existing names, because they are typically collected together into package repositories/directories
In my opinion, you should use a top level ns that is something you own, via either trademark or domain name, or just maybe a conferred id via github user (which I wish we had more strongly established a convention around). And if you’re not doing that, you’re wrong. But I also don’t want to be the jerk telling people what to do all the time.
And ditto the lein/clojars convention for groupid
io.github.<username> is certainly one domain name everyone "owns" simply by virtue of creating a Github account with a unique name.
Long term (e.g. decades) I do not know whether Github would ever allow those account names to be reused.
but my previous comment implies switching from "accidental conflicts of names" to "malicious intentional conflicts of names". Avoiding accidental conflicts among cooperating people is pretty easy.
I asked folks about next.jdbc
before I went from alpha to beta. One of the things I asked about was the namespace structure, since I wondered about next.jdbc
vs something like seancorfield.next.jdbc
-- no one seemed to care and I really felt kind of uncomfortable about my name being in everyone's :require
clauses 😞
I kind of hate single part namespaces, like just the name of the lib. But I also think the full reverse domain convention of Java is excessive.
Using multi-methods
and trying to dispatch on wildcards. e.g:
(defmulti foo :type)
(defmethod foo :rectangle OR :circle (fn [x] (println "i'm rectangle or a circle")))
(foo {:type :rectangle})
=> "i'm rectangle or a circle
how can I get desired behavior? couldn't find anything on docs@UBSREKQ5Q https://clojuredocs.org/clojure.core/defmulti#example-57558046e4b0bafd3e2a0474
yeah, that's very weird rsrs. But what is happening is this: The keyword ::default
is used as a *
operator, however, when you call the defmulti with (nil :b)
the defmulti does not find a dispatcher for it, so it will go direct to the :default
implementation.
Right there, he is using the get-method
function and looking for an implementation that matches [*, :b]
which is saved in the recover
variable. after this step he is only validating that recover
is not the :default
implementation that he is current in [or it would produce a call to itself again] and then he calls this new implementation at (recover * :b)
hmm I see
you can see that this is a bit hacky, because if you try to call (recover ::default :b)
he will find the implementation and will not print that message
then what do you suggest? stick to the 'clever-disaptcher' option then?
for this specific case you show, I would go with the clever dispatcher and use a keyword like :rectangle-or-circle
in the defmethod to make my intent clear
Thanks
Maybe this worth a SO thread?
Could be a solution we don't know?
It sound more like you want to do pattern matching and not necessarily dynamic dispatch
Have you looked into using core.match
or other solutions based on it (such as defun
http://github.com/killme2008/defun)
Will do
multimethods support arbitrary keyword hierarchies - why not create a parent that :rectangle or :circle derive from?
(def shapes (-> (make-hierarchy)
(derive :rectangle :shape)
(derive :circle :shape)))
(defmulti foo :type :hierarchy #'shapes)
(defmethod foo :shape [shape]
(println "I'm a" (:type shape) "shape"))
(foo {:type :rectangle})
@aviv I would reproduce this behavior by writing a smarter dispatcher, something like:
(defn clever-dispatcher [{:keys [type]}]
(cond
(or (= type :rectangle) (= type :circle)) :rect-circle
:else :square))
(defmulti foo (fn [v] (clever-dispatcher v)))
(defmethod foo :rect-circle
(fn [x] (println "i'm rectangle or a circle")))
(foo {:type :rectangle})
but might be better to have two defmethod
[:rectangle and another to :circle] and factor out the function that implements the behavior out, then call this function inside each defmethod to "re-use" the common code.
yea I thought about those options, but thought there's maybe any wildcard support to make it cleaner
there is a wildcard example in docs, but couldn't grasp it
let's continue on thread
Is there a trick in cider/emacs to structurally edit a map? e.g, I have this line
{:padding "1em"})
and I want to turn it to
{:padding "1em"
:margin "1em"})
without traveling to the "}" mark before going down a line.
It's a really small difference, but I think it makes sense.@UAEFFG05B thanks a lot for the resources! Its probably worth to invest a little more in practicing working with paredit, and it will get more fluent, and if its still bugging me I'll try to write a snippet to deal with it
If you're looking for something good in emacs. Try adjust-parens + aggressive-indent-mode + smartparens
Hey. I have a beginner question. I'm trying to use namespaced keywords with ::
. So I have 2 modules/files: (ns ex.core)
and (ns ex.product)
in product I have:
(ns ex.product)
(defn product-price [product]
(product {:car 2000 ::ps4 500}))
(product-price ::ps4)
in core I have
(ns ex.core (:require [ex.product :as product]))
(def fee-usd 1.5)
(defn cost-of-product [p-type]
(+ (product/product-price p-type) fee-usd))
(cost-of-product :product/ps4)
in product, the call product-price
returns 500 as expected while in core I have NullPointerException
What am i doing wrong?::ps4
is fully qualified, so it should be the same as :ex.product/ps4
. The usage of ::product/ps4
should work too [merged the two answers]
yeah confirmed. both full namespace :ex.product/ps4
and ::product/ps4
works. Thank you
can keywords not be passed directly as function arguments?
e.g. a function called foo
that destructures its args, this usage throws an arity error (foo :key1 :key2)
so if I change function foo
to not destructure args and just take a vector, this works (foo [:key1 :key2])
@hiredman hmm it's macro, so maybe that's why? here's what i'm basically doing
(defmacro foo
[& args#]
`(apply foo* (cljs.core/clj->js ~args#)))
a clojure macro is a little program writing in a meta language that takes in a clojure expression and returns a new clojure expression, it is confusing because the meta language is also clojure
it might actually be slightly easier to follow in clojurescript because in cljs macros are programs written in clojure that take in clojurescript expressions and return clojurescript expressions (the meta language and language are not the same)
3. understand quoting (which determines if your expression is in the language or the meta language)
looking at your macro(trying to use apply to invoke a function on a js value, and the way you are handling varargs), and what you said about it (saying it converts cljs values to js at compile time, when the way stuff is quoted means it definitely doesn't do that, and understanding the difference between the language and the metalanguage makes that super problematic even if you got quoting right), makes me think you might need to work on all 3 points (really #3 is critical)
the js function takes a list of args, if i was calling it via js i'd just destructure them foo(...args)
from google search found that I can use apply
to have similar effect, not sure if there's a better function for that.
but yea, I'm definitely still a beginner, just wanted to use a macro for generating styles to be consistent with macros used with cljs react* wrapper I'm using. I tried following their code to have a similar effect in my own macro (https://github.com/Lokeh/helix/blob/master/src/helix/impl/props.cljc#L62-L63) so yeah, I'm not sure why you're saying it doesn't do that at all but as you mentioned, perhaps I do need a better grasp at the language first
so that code isn't a macro, and doesn't translate cljs data structures into js datas structures at compile time
the #? causes the dialect (clojure or clojurescript) to determine what the reader reads, so on clj you will get
`(->js ~(val entry))
but on cljs you will get
(->js (val entry)))
neither of which is a macroI don't write clojurescript so I am not sure if it's apply function does things differently from clojure's, but clojure's apply function takes the arguments as a seqable thing, so doing the equivalent of what you are doing (taking the collection of arguments, dumping it in to an array, and then calling apply) is bizarre.
the ... syntax in js is also not destructuring (I think I've seen it called spreading), so to avoid confusion it is best not to refer to it as that. destructuring is a binding syntax that allows you to not just bindg a name to a value, but bind names to specific parts of a value, and clojure and javascript both have some version of this
(it does look like ... is re-used as part of the destructuring syntax in js, which might be confusing)
ah yes, the word I was looking for was spreading
.
and yeah, I know it's not a macro, but that function is then being used inside a macro. so i figured the effect would be the same.
but anyway, appreciate the attempt at clarification.
will try and stick to functions for now until i become more familiar w clojure