This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-02-18
Channels
- # admin-announcements (3)
- # announcements (7)
- # aws (1)
- # beginners (76)
- # boot (340)
- # cider (9)
- # clara (35)
- # cljs-dev (7)
- # cljsjs (16)
- # cljsrn (11)
- # clojars (1)
- # clojure (192)
- # clojure-dev (6)
- # clojure-madison (8)
- # clojure-russia (373)
- # clojurebridge (1)
- # clojured (9)
- # clojurescript (172)
- # community-development (1)
- # core-async (2)
- # cursive (7)
- # data-science (2)
- # datomic (12)
- # devcards (1)
- # dirac (63)
- # emacs (3)
- # events (10)
- # gsoc (3)
- # hoplon (1)
- # jobs (1)
- # juxt (20)
- # ldnclj (4)
- # lein-figwheel (12)
- # leiningen (1)
- # off-topic (21)
- # om (232)
- # onyx (64)
- # parinfer (8)
- # proton (21)
- # re-frame (8)
- # reagent (1)
- # ring (3)
- # ring-swagger (3)
- # slack-help (4)
- # spacemacs (6)
- # testing (3)
@george.w.singer: I think people generally mean the type of the input arguments and return value when they refer to the signature of a function.
Thanks!
Is @stuartsierra 's component framework very widely used?
I am using it for the first time and I'm having trouble understanding some aspects of it, or wondering why they are not a bit simpler. In particular, the component vs system dichotomy feels a bit odd. And I don't understand why components don't declare their dependencies by implementing something that's part of the Lifecycle protocol, rather than using metadata and special functions.
Are there particular reasons for these aspects of the design? Any good pointers on how to use it well? Simpler variations that are now all the rage?
ok. good to know.
alexisgallagher: https://github.com/tolitius/mount looks like an interesting alternative...though I didn't use any of them
Eeenteresting.
read https://www.reddit.com/r/Clojure/comments/3zppdn/the_beauty_of_clojure/ for a discussion about component and boot
The discussion on that reddit thread is quite insightful.
Actually, scratch that. It's super duper insightful.
IMHO the mount
proponents have missed the point, but that thread covers it better than I can summarize here.
@ghadi: I would not jump the global variables everywhere
misconception gun, and that is not at all what this reddit thread concludes. simple
sometimes takes time to understand and appreciate.
Clojure vars are not bad, they are good. They are general purpose. And if the one does not like keeping states in Clojure vars there is always an alternative: https://github.com/tolitius/yurt
tbh I find the fundamental nature of the var to be one of the things that puzzles me most, despite that I've been using clojure on and off for years. They're one of the concurrency primitives. But they also seem to be used to define pretty much every single constant thing in the language (like function definitions). I think it's the number of indirections in chains like name -> symbol -> var -> atom -> value that confuses me.
Perhaps I need to process it in meditation.
Have had some troubles recently with macros. Reduced it down to a very simple test case:
app-application.core=> (let [foo inc] (eval `(~foo 1)))
2
app-application.core=> (let [foo (memoize inc)] (eval `(~foo 1)))
IllegalArgumentException No matching ctor found for class clojure.core$memoize$fn__5708 clojure.lang.Reflector.invokeConstructor (Reflector.java:163)
@alexisgallagher: very true. they can be abused, as anything else can. meditation
will definitely help to be the one with the force
looks like an ArrayBlockingQueue: https://github.com/http-kit/http-kit/blob/0e53d3d883901a229c189c263b2a4f6c07e66a0e/src/java/org/httpkit/server/RingHandler.java#L160
right, but that is only if the queue fills up, which would mean something is off with the balance of writes vs. reads
i.e. if it did not block, there is a risk of blowing up the heap, getting out of file handles, etc..
busy does not mean reads are not catching up, just means there are lots of writes and reads
@jonahbenton: thanks, didn't think of that one!
@kul, I remember there is a timeout
option (on the server start) that is applied to requests..
hmm.. it does not seem to be used on start, only on stop: https://github.com/http-kit/http-kit/blob/11daa3c293248b31d6201e12fe24a49f9dba569a/src/org/httpkit/server.clj#L10
@kul, actually requests do have timeouts: https://github.com/http-kit/http-kit/blob/73619b7d6cd3fb02da03ed420099764db26fedbf/src/java/org/httpkit/client/Request.java#L34
have not explicitly used them with http-kit, which means that its defaults worked quite well for me
@kul, actually in case the queue fills up, requests won't be blocked, they will be rejected with HTTP 503: https://github.com/http-kit/http-kit/blob/0e53d3d883901a229c189c263b2a4f6c07e66a0e/src/java/org/httpkit/server/RingHandler.java#L170
@kul it's true that original author doesn't have time to maintain http-kit project at the moment. However, there is some activity to get the project back to live.
That's good to hear @mhjort as we'd looked at http-kit but were a bit concerned about that...
{[] :c '() :b}
=> IllegalArgumentException Duplicate key: [] clojure.lang.PersistentArrayMap.createWithCheck (PersistentArrayMap.java:71)
@alexisgallagher: you might want to check out weavejester's approach to using component, cf. https://www.booleanknot.com/blog/2016/01/24/how-i-use-component.html
Someone experience with the client side generated clojure code from swagger? I’m trying to see how to incorporate it into my project. Should I use it as a separate library somehow, or would it be better to put the code directly into my project?
I just copied the result into the src
dir of my project. Works for now. I can look into automating that process
@ordnungswidrig: that's a result of the unfortunate decision of having vectors compare equal to lists
@kul I don't know much about Catalina, so I don't know if/how it's similar to it, but I wrote https://github.com/nberger/ring-logger (started as a fork of http://github.com/pjlegato/ring.middleware.logger, it's quite different nowadays)
@nberger: is it known bug/feature that ring-logger throws exception on urls like "smth/?hello"? https://gist.github.com/910d3696a06efef269c9 — here is the diff with offending request
@larhat it was not known to me. Feel free to create an issue/send PR, I'll take a look into it soon anyways
@schaueho: thanks. Will check it out. I spent longer than I care to admit wrestling with the components + jetty + routes issue, and I feel I always learn something from wesvejester's taste.
Hey, I'm looking for a way to make a short bit of code a little more elegant/idiomatic. I have a function that will return either nil or a value, and I want to map it over some input and collect the non-nil values in a seq.
So for purposes of an example, the function could be defined as (defn f [x] (rand-nth [x nil]))
What I've got right now is (remove nil? (map f [:a :b :c :d]))
, which doesn't seem terrible and is pretty clear, but I keep thinking there's a way to make it more concise by using reduce.
with reduce just make f look at the incoming input value and if it isn’t nil conj it onto the accumulator
reading the article http://danboykis.com/?p=2263 ("The Beauty of Clojure”), and I’m struggling to understand something—why do people think protocols and deftype/defrecord are OO?
Yeah, that's what I was thinking, I guess I was looking for a version of conj
that doesn't append nil
Aha! That sounds perfect
That is perfect! Thanks @ghadi
>Returns a lazy sequence of the non-nil results of (f item). Note, this means false return values will be included. f must be free of side-effects.
Hmm, I actually do have side effects inside the definition of f, I'm doing some database work over a batch of inputs and then trying to accumulate errors
you could use what I pasted above in the snippet wrapped in a call do doall
, (doall (reduce …)
or you may want to use doseq
and collect the results by swap!
ing into an atom
hey @ddellacosta - there are some superficial resemblances between protocols and records/types and Java interfaces and classes and if you are coming from an OO mindset where those specific features are all you see, then protocols and records/types can look OO to you.
jonahbenton: I see. They have always seemed a lot more similar to typeclasses in Haskell to me
as the types they are applied to are data types, not objects, and state is clearly separated
yeah, I’ve had similar impressions. I found it easier to reason about it if I thought of them as typeclasses.
seems to render the point of that article kind of defunct
yeah, I think so too. They miss the point of OO. It was never about classes and interfaces in the C++/Java way.
I believe Allan Kay even said that Lisp, Erlang and SmallTalk were the only OO languages. So implying that defrecords and protocols are the equivalent of Classes and Interfaces in Java, in my opinion, make clojure less OO.
I dare not dive into the quagmire of “what is and isn’t OO” 😄
@ddellacosta I wrote that article, why do you think it's defunct?
danboykis: well, if you’re starting with the premise that Component is not the right choice because it is too OO, and it’s not actually OO, then the rest of the argument seems to lose it’s motivation.
but! I will be clear that I don’t actually know what OO is. So maybe it is too OO.
more generally—not specific to your article—I find a lot of these articles on Mount vs. Component to be uncompelling
component and mount both seem to allow a ton of flexibility, so it seems hard to evaluate on the grounds of how “truly Clojure-like” one or the other is
yeah, I’m generally wary of articles that try to highlight how great some library is by casting aspersions on another one
and it can descend into No true Scotsman territory really easily
@ddellacosta: I agree OO is not one single thing (kind of like FP isn't either) but once you start creating data types with methods and Dependency Injection graphs, I call that OO
danboykis: fair enough, but I’m referencing your original article, where you say > However, after using component for a project at work, I noticed that my code stopped looking like idiomatic Clojure code and more like OO Java I used to write. While features like reify, defprotocol, deftype, and defrecord exist they exist for the purposes interop with Java, type extensions and library APIs. In my opinion the bulk of Clojure code should strive to utilize functions and be data oriented.
@ddellacosta: if you like component I'm not advocating you don't continue using it, if it's not compelling to you that's fine
and the implication there is that reify, defprotocol, defrecord are OO somehow—that’s all.
@ddellacosta: that blog post reflected my experience, I even said it in the beginning that I am biased
I’m not trying to be contentious here. Furthermore, I’m completely undecided on any of these things—I haven’t actually used either significantly, although we are trying out component now to see if it helps with structuring our system.
Mostly I wanted to point out that defprotocol, deftype and etc. are very much data oriented and functional, and as such not grounds for dismissing something as OO. That’s it!
…at least, as far as I understand. That’s why I asked why people considered those features to be OO
I consider ApplicationContext like DI to be OO, you may disagree but I think it's generally accepted as a OO pattern
haha, I have no idea what ApplicationContext is
also if you take a look at the docs: http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/defrecord
if you are talking about spring’s magical DI, then that is another thing. And component is nothing like spring.
danboykis: I’m not saying you can’t use it for something that can be called OO. The point is that those Clojure language features very much support functional programming.
and yeah, talking about patterns is not going to convince me we’re talking about OO—pattern is too vague of a notion to tell me anything
the article does not claim that the use of records and protocols is not idiomatic, although it is quite an easy angle of attack when paraphrasing (@ddellacosta nothing you've said, but a few often do). In fact both mount and yurt use deftypes, records and protocols which are great
tolitius: hmm…the chunk I quoted seems to be saying that pretty explicitly.
ddellacosta: I think you can do FP in a lot languages that doesn't mean they are FP
I want to be clear here though—I’m not advocating component over mount. I have no dog in this fight.
@ddellacosta: no, it is not talking about records and protocols, but rather about component. there is a difference
@ddellacosta: I agree, I am not talking about them eitehr
danboykis: think we’re well off the point I started with, so I’m taking my leave of this debate.
sorry to start an argument—forgive me. cheers all 😄
yeah, I’m confused at this point too about what was the point of that statement. Have to get back to work.
clojure protocols and records are general purpose tools. they can be misused as anything else can.
hey @danboykis i missed the discussion but thought it was a good piece, it's always useful to highlight differences between approaches with real code. thanks for writing it.
(defn dense-element-multiply!
[alpha a-data a-offset x-data x-offset beta y-data y-offset op-len]
(let [^long data-len op-len
^long a-offset a-offset
^long x-offset x-offset
^long y-offset y-offset
^double alpha alpha
^double beta beta
^doubles a-data a-data
^doubles x-data x-data
^doubles y-data y-data]
(dotimes [idx data-len]
(aset y-data (+ idx y-offset)
(+ (* beta (aget y-data (+ idx y-offset)))
(* alpha (aget x-data (+ idx x-offset))
(aget a-data (+ idx a-offset))))))))
public static void alphaAXPlusBetaY( int op_len, double alpha,
double[] a, int a_offset,
double[] x, int x_offset,
double beta,
double[] y, int y_offset)
{
for (int idx = 0; idx < op_len; ++idx) {
int y_off = y_offset + idx;
y[y_off] = alpha * x[x_offset + idx] * a[a_offset + idx] + beta * y[y_off];
}
}
What do you suppose the performance difference is between these two version of the same function, one in java and one in clojure?you're asking what accounts for actual measured difference?
Well, I was first asking for guesses as to the performance difference across a range of vector lengths 10-10000.
And more productively I was wondering if someone saw something I did that would dramatically change this comparison.
That is reasonable but you will notice the code compiles clean with these warnings:
(set! *warn-on-reflection* true)
(set! *unchecked-math* :warn-on-boxed)
Here is the test code:
(defn perf-test-element-multiply
[]
(doseq [elem-count [10 100 1000 10000 100000]]
(println "elem-count" elem-count)
(let [^netlib_ccm.core.DenseVector y (m/array :netlib (repeat elem-count 1))
^netlib_ccm.core.DenseVector x (m/array :netlib (repeat elem-count 2))
^netlib_ccm.core.DenseVector a (m/array :netlib (repeat elem-count 3))]
(print "clojure:")
(time (dotimes [iter 1000]
(nc/dense-element-multiply! 1.0
(.data a) 0
(.data x) 0
1.0
(.data y) 0
elem-count)))
(print "java :")
(time (dotimes [iter 1000]
(Ops/alphaAXPlusBetaY elem-count 1.0
^doubles (.data a) 0
^doubles (.data x) 0
1.0
^doubles (.data y) 0))))))
elem-count 10
clojure:"Elapsed time: 0.263458 msecs"
java :"Elapsed time: 0.124357 msecs"
elem-count 100
clojure:"Elapsed time: 1.909401 msecs"
java :"Elapsed time: 0.259004 msecs"
elem-count 1000
clojure:"Elapsed time: 18.399427 msecs"
java :"Elapsed time: 1.52352 msecs"
elem-count 10000
clojure:"Elapsed time: 182.669039 msecs"
java :"Elapsed time: 14.149774 msecs"
elem-count 100000
clojure:"Elapsed time: 1845.416527 msecs"
java :"Elapsed time: 143.310439 msecs"
@jonahbenton: thanks
hey @chrisn would be interestin to see the disassembly, e.g. http://insideclojure.org/2014/12/15/warn-on-boxed/
@jonahbenton: there it is. The clojure version is a lot lot more complex.
@chrisn yeah- lots of what should be unnecessary casting. have to jump off, will try to re-engage later
why are you letting the primitives rather than typehinting them in the signature?
there are workarounds for that
that's definitely affecting your times to some degree
you can group all the longs into a long[] for example
and there are other more tedious paths (like declaring an interface with primitive methods, and a deftype that holds primitives and implements that interface)
OK, so to work around what appears to be a compiler bug with let you can do some work arounds like definterface and reify?
it's not a compiler bug, it's an implementation choice
I would expect a let with type hints to work the same as a type hinted function once past the let.
IFn has one arity for every combination of Object, double, and long - this is a combinatorial explosion of arities
3^4 was the pragmatic stopping point
or whatever the math is
If you read the assembly you will see that the casting happens in the loop after all variables have been type hinted.
yeah I saw that, I was trying to figure out what was causing that
instead of using ^long on the let bindings, you might try instead doing "x-offset (long x-offset)" and see if that yields a different result
there could be a bug here, not sure
elem-count 10
clojure:"Elapsed time: 0.168278 msecs"
java :"Elapsed time: 0.150324 msecs"
elem-count 100
clojure:"Elapsed time: 0.648329 msecs"
java :"Elapsed time: 0.307831 msecs"
elem-count 1000
clojure:"Elapsed time: 5.586705 msecs"
java :"Elapsed time: 1.514433 msecs"
elem-count 10000
clojure:"Elapsed time: 44.18003 msecs"
java :"Elapsed time: 14.140744 msecs"
elem-count 100000
clojure:"Elapsed time: 433.436932 msecs"
java :"Elapsed time: 143.524602 msecs"
can you post the disassembly for that? just the method part
(let [^long x x] ..)
is semantically different than (let [x (long x)] ..)
. in the first we're telling the compiler "treat x as a long", meaning it will be cast to long when it's going to be used, in the second we're actually casting x t long
I can't reply to the "should it" question, my opinion probably differs from that of Rich. I can only tell you that this is what the implementation does
when you type hint a local, that will result in a cast at the call site. one cast for each time that local is used in an interop/prim call
what’s the preferred way to apply a transducer to a channel? right now I’m creating the channel to be returned, passing in the transducer and then just pipe into it, but that seems a bit janky
you can use map
if you’re just transforming data. If the transducer performs a filter then piping is the preferred method
@bronsa, @alexmiller thanks for looking at this and I think bronsa's description of the difference between ^long and (long x) is very clear. That is a very useful bit of knowledge along with the use of no.disassemble will really help a lot.
What is the rationale for not having strings in Clojure be seqs, like lists, vectors, etc? I don't see why it could not work, nor that it would be a performance issue. Curious to learn
it would be a performance issue
strings are seqable and so can be used to produce a seq if desired, but are far more efficient being stored using Java strings in the JVM
The Google Summer of Code 2016 organization application is due tomorrow and David Nolen and I worked on completing it today. However, this requires community help to get anywhere. Right now we need: 1) project ideas http://dev.clojure.org/display/community/Project+Ideas+2016 2) mentors for those ideas Presuming Clojure is accepted as an org, students will then be able to propose those projects in March.
there is also now a #C0N1QHE3W channel