This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # adventofcode (150)
- # aleph (15)
- # announcements (1)
- # beginners (52)
- # cider (3)
- # clj-kondo (2)
- # clj-new (43)
- # cljsrn (2)
- # clojure (49)
- # clojure-chicago (1)
- # clojure-europe (13)
- # clojure-france (20)
- # clojure-spec (3)
- # clojure-uk (1)
- # clojurescript (16)
- # community-development (3)
- # core-matrix (1)
- # cursive (9)
- # defnpodcast (1)
- # fulcro (68)
- # graphql (1)
- # malli (7)
- # off-topic (25)
- # portal (4)
- # re-frame (15)
- # reagent (7)
- # releases (1)
- # remote-jobs (1)
- # rewrite-clj (8)
- # shadow-cljs (4)
- # vim (22)
Is there like a support group to talk to about seeing - truly seeing - Clojure for the first time? As someone who haven’t done LISPs before, but have extensive C# experience as well as a great interest in typed functional programming, I never thought a LISP with dynamic (!!!) typing would be anything for me. But having just worked through a couple of Advent of Code challenges I feel obsessed with the language. I dream about it! Lovely parens everywhere! Watching some of Rich Hickey’s talks just jolts me with insights that challenge my last ten years of professional programming experience. Seeing static types as a lovely puzzle to solve, but oftentimes a hindrance to actually solving problems - 🤯 In many ways using Clojure feels like the first time I learned Python some 20 years ago. Everything feels exciting and challenging and possible. Things just make sense. The first time ever writing a single line of Clojure I completed twelve programming challenges in Advent of Code without getting the answer wrong a single time. No off by ones, no confused abstraction usage. No null ref bombs. Just data and (already familiar) functions, packaged up in a way that feels intuitive and easy to use. No “killer feature” that actually involves a lot of complexity (looking at you, Go channels) and leads beginners down a path of power but also confusion.
> No “killer feature” that actually involves a lot of complexity (looking at you, Go channels) and leads beginners down a path of power but also confusion Well 😅, actually there are some of that, but lets say they're kept away for advance power users. You've got the same complex channels and CSP Go-routines, actually probably even slightly more complex than in Go with core.async. And you've got user defined macros I'd say are an easy way for beginner to get themselves in a place of too much power that confuses them. But yea, the language steers you towards simple things, that's really engrained to its core. So happy you're enjoying it! I've had the same happen to me, and now no other language brings me Joy anymore, only Clojure or Clojure-like languages do 😛
Hello everyone! I hope my message finds you and all your loved ones well and healthy! I am in Clojure for three months now. Of course i am still a complete n00b but i wanted to ask a question...how Clojure compares to Scala? I mean they are both functional but any differences?
Plenty of differences. I'd say that the only similarities are that they are both functional languages on the JVM. Scala is a statically-typed language with a powerful (and complicated) type system. It's also a multi-paradigm language. That means you can use in both imperative and functional style. Most Scala users learn towards the functional style, in my experience. Clojure, in contrast, is a dynamically-typed language. You can use it for imperative programming, but very few people do that, and the language heavily steers you toward functional programming. Clojure is also a Lisp. Clojure developers typically make heavy use of the REPL to interactively iterate on their programs. Scala is more traditional in that sense, relying heavily on static typing and IDE support. Clojure is a vastly simpler language than Scala. See also the Clojure rationale at https://clojure.org/about/rationale.
Oh, and importantly, Clojure puts data first, whereas Scala is more reminiscent of the traditional object-oriented approach in that respect.
Hi @U4ZDX466T and thank you so much for your response! My background is mostly JVM languages. For the last 4 years i am working on Groovy language. I have touched a bit of Scala but never truly kept me due to the complexities that you are referring. I felt that i wanted more power and more simplicity! That's why i have chosen to start learning Clojure. I have a long way to! One more thing that hooked me is the ability of this language to do hot code swap. Something that, if i am not mistaken, only the BEAM languages can do.
I think @U4ZDX466T explained the difference pretty well. I would say that in my experience, a lot of people actually use Scala in an imperative OO style, and not functional, because a lot of people choose it over Java simply to avoid the verbosity that Java has (or used to have, since its improved a lot in that area more recently). This isn't always true, die hard passionate Scala devs do use it mostly functionally, but in my work experience, places that are JVM shop (and not Scala shop specifically), where you have some teams or services that tried Scala, often end up using it in OO style. Clojure on the other hand can't be used like that. So its both a harder transition, as well as a better introduction to FP in my opinion.
Clojure can do hot-code reloading, and dynamic code loading as well. But I'd say, in Erlang, you might realistically (though even in Erlang its not really done), deploy your code changes to prod using hot-code reload. Where as in Clojure, you probably shouldn't deploy changes with hot-code reload to prod, but you will definitely use it for development, testing, and debugging.
Oh, one more difference with Scala, I have found, Clojure has much better interop with Java, where as Scala's interrop requires a lot more hoops, so I find Scala to be more of an island.
Is Clojure somewhat slow on doing lots of mathematical calculations? Currently I'm summing 500k vectors of ~20 numbers and that takes almost a second in total. Is that expected performance or am I doing something wrong? Essentially just mapping (reduce +) over a for-comprehension. This code takes 100 ms to run in my REPL, so I'm guessing I'm doing something weird in my original code...
(time (reduce + (map (partial reduce +) (map #(range % (+ % 25)) (range 500000)))))
Well, let me tell you about boxed maths https://insideclojure.org/2014/12/15/warn-on-boxed/ https://clojuredocs.org/clojure.core/*unchecked-math* The performance hit is about 100x
The code is very functional but slightly abuses lazy sequences, can we eliminate some of that overhead?
You'll gain a slight speedup by dispatching directly to more specific methods. Def-ing something like
and using it instead of
(defn qadd ( 0) ([^long x] x) ([^long x ^long y] (unchecked-add x y)))
+will already improve performance
Should also take a look at https://clojure.org/reference/java_interop#typehints
I agree with @UK0810AQ2.
As far as I understand, for best performance, intensive numeric calculations should be done in a tight
(loop [...] ... (recur ...)) within a single function (Clojure
fns box their args) with typed non-boxed locals and typed arrays (no lazy sequences, no Clojure vectors since they store boxed Objects).
Definitely, a loop would be best, I tried not to break the initial mold too much. All the
ranges do take their toll
@UK0810AQ2 Sorry for disappearing, my daughter woke up and then real life happened. Thanks for taking the time. Good to know that there’s an escape hatch when that type of performance is needed!
My assumption was that laziness would help speed up the process in terms of not having to realise all the sequences in memory before performing computation. Obviously that’s not a correct assumption based in your input...
@U01GZD00HA8 I'm in a similar situation, don't feel pressured to synchronously reply 🙂 The full answer is that like in every case, it depends. You could create a 2d array and sum it, that would be fastest. Searching on both dimensions of laziness and allocations until we find an optimum solution is an interesting exercise, for which results may vary depending on anything from your implementation, to your JVM version and choice of GC algorithm
Thanks a lot for all the input! I don't really need to solve this specific performance issue, I just wanted to understand what I could do if this issue crops up in a real case.
The boxing explains a lot, though. As long as it’s possible to avoid it and optimize for speed over safety or ergonomics in the few cases where it’s needed I’m happy.
There's nothing wrong with having a few scary, well tested and non-idiomatic functions which deal with unboxed data and perform black magic
For a slightly more advanced example, and a very good explanation of the process behind such optimizations, take a look at a recent conversation on clojureverse (in particular, the answer by joinr) https://clojureverse.org/t/my-recent-clojure-vs-c-experience/6909/3 Though, doing unboxed math, using arrays, using loop/recur and not using lazy sequences will get you far. For extremely fast performance (CPU and GPU) take a look at https://neanderthal.uncomplicate.org/
The normal Clojure vectors you get by default contain all boxed values, but there are also Clojure vectors restricted to one JVM primitive type, e.g.
(vector-of :long 1 2 3) that are more memory efficient, and I would guess are able to get one closer to the speed of iterating through Java arrays of restricted types, but I haven't compared performance between those two approaches.
Everyone else assumed that you're hitting the bottlenecks of boxed math. But I don't think that is what is happening in your case. Are you sure you're not measuring the startup time as well?
But, if the slow-down is because Clojure persistent data-structures and sequences do boxing of primitive types, I recommend this article: https://neanderthal.uncomplicate.org/articles/fast-map-and-reduce-for-primitive-vectors.html If you really want fast numerical computation, and I mean, faster than Java fast, Neanderthal and Fluokitten are what you want!
you can extend protocols to Object or nil to cover default cases for those in Clojure
Cljs in a few places supports variations of 'default' or ':default' for types because of the type hierarchy in js
It's an old article of David Nolen https://archive.org/details/hackermonthly-issue023/hackermonthly-issue023-ipad/page/n31/mode/2up
might be worth posting on https://ask.clojure.org as a request for doc improvement (or https://github.com/clojure/clojurescript-site/issues for web site doc)
> You can implement a protocol on nil > To define a default implementation of protocol (for other than nil) just use Object