Fork me on GitHub
Nir Rubinstein11:01:19

2 seemingly simple questions: 1. Why is ({:a 1} :a) faster than (:a {:a 1})? 2. Per the documentation, the = operator dispatches to equals function of the concrete class. That being the case, why is (= "a" a) much slower than (.equals "a" a) (when a is (def a "a")


clojure.core/= only dispatches to equals of the concrete class as a last resort, after checking several other cases.


If you look at the source code for clojure.core/= you see it calls this Java method, assuming we are talking about Clojure/Java, not ClojureScript:


What method did you use to measure the relative speed of ({:a 1} :a) and (:a {:a 1}) ? Realize that microbenchmarks like that can be a bit challenging to get useful performance results from, given how short they are, JIT compilation on the JVM, various JVM options that can modify JIT behavior, etc. Criterium is a good library to use for as stable of results as people know how to achieve:


Funny, I did a benchmark yesterday where I saw the reverse for 1.


Also I discovered that (foo :x) doesn't work for defrecords..


Huh, that defrecord thing surprises me a bit, but I use defrecord so rarely that I probably would not have noticed.


Also one surprising thing: (:x foo :default) does not return :default when :x is nil in the defrecord foo

Nir Rubinstein11:01:14

Thanks a lot guys!!!


Are pre- and postconditions not available for fn, only for defn? I tried to add a {:post [...]} block to an fn with a spec2 check, but it seems like it gets ignored completely

Alex Miller (Clojure team)14:01:41

prepost map goes after the arglist - is that where you have it?


Seems to work, this gives an assertion failure:

((fn [x] {:post [(= % 1)]} (inc x)) 2)

Alex Miller (Clojure team)14:01:24

user=> (def f (fn [i] {:post [(int? %)]} (if (odd? i) (str i) i)))
user=> (f 1)
Execution error (AssertionError) at user/f (REPL:1).
Assert failed: (int? %)
user=> (f 2)

Alex Miller (Clojure team)14:01:46

it's easy to forget the vector in :post too


Hm I had the vector... Maybe a spec2 problem? I'll test some more, and if I run into something I'll report


Hi everyone. Anyone know how to stop clojure truncating tracebacks? I'm doing a lein test and getting a traceback ending in ... 102 more. How do I see those 102 more?

Alex Miller (Clojure team)14:01:27

the 102 more are repeated in one of the other nested exception stack traces (so you are likely actually seeing those elsewhere already)


Ah ok. Thanks for that. It was a nested exception, yes.


Hmm what was that again when I get a "No matching ctor found for class" for a function?


That means Java was trying to construct a class, and it couldn’t find a constructor that takes the types of arguments you gave it.


in prismatic/schema, is there any type annotation for functions?


in the example above s/fn is an invalid option, but I'm looking for something that would do it, to describe that the function returns a function


@zignd Maybe you can use (s/pred ifn?)


Thanks! Works perfectly!


I’ve been out of the loop a bit, so I’d like to ask if Luminus is still one of the best out-of-the-box template/framework options for Clojure.


As an offshoot of that question about Luminus, for folks who are exploring the built in deps/cli tools over leiningen, will something like be able to create similar full stack, composable templates like Luminus?


Hmmm, it actually looks like you can create the actual preexisting Luminus templates with this clj-new tool?


Yes, clj-new can execute Leiningen templates (and Boot templates), as well as newer clj-template templates. If you find one that won't run, it's a bug and I'll (try to) fix it. Also, be aware that if clj-new runs a Leiningen template, it's not magically going to produce a deps.edn file -- it'll be a project.clj-based project!


I see. So I would be looking to create a bespoke template with clj-new that mirrors the Luminus ones if I wanted the same structure?


You could just run clj -A:new luminus chasote/webapp and then create an appropriate deps.edn based on whatever ends up in project.clj.


Got it. Thanks for the clarification


The :dependencies vector would become the main :deps entry and then each profile would become an alias -- but you'd have to figure out the equivalent to Leiningen plugins yourself.


I'm not entirely sold on moving over yet but so far I like the deps tools and have been switching my editor integration to also take advantage of the built in socket (p)repl tools too (I'm using neovim/conjure). It's not quite ready yet (shadow-cljs doesn't work with the prepl) so I'm also trying to convert a shadow-cljs project to figwheel-main (which does work) which has been difficult.


If I recall correctly, you've switched to socket based repl workflow too?


Yeah, I use Atom (since 2015? When I switched away from Emacs) and ProtoREPL is no longer maintained so I switched to Chlorine which works with a Socket REPL.


So now I can use Atom/Chlorine locally and also on any remote process started with a Socket REPL JVM option.


No nREPL, no Compliment. Just out-of-the-box Clojure.


I don't do any ClojureScript -- I suspect that's the area where deps.edn is weak in comparison to lein-based or shadow-based tooling.


Yep, which is a strong interest of mine so I think I might be switching too early. Just as a thanks though, know that one motivation for gravitating towards certain tooling is if you are actually involved because I've seen how helpful you are on here.


One day I may go back to ClojureScript -- we last tried it in 2014/2015 and it wasn't really ready for primetime back then. Tooling (and the core language itself) has improved dramatically since then.


But just to confirm, luminus is still a prime contender for framework/template for Clojure these days?


@U061KMSM7 I think the answer to that is subjective. I've never used the Luminus template (except as a test case for clj-new 🙂 ). I don't particularly like some of the libraries it bundles in and I don't much care for the structure of the basic project it creates. And of course I don't use Leiningen these days. But I know there are folks who seem to like the somewhat "batteries-included" approach of Luminus.


Any other alternatives you would recommend?


Or particular libraries you would swap out?


I prefer to start from scratch and only add in the libraries I actually need. These days that's going to be Component, Ring, Compojure. Almost certainly next.jdbc. Then it will depend on what I'm building.

vemv02:01:43 seems a fair contender for "deps-based web template"


I'd say that's probably more opinionated than Luminus -- and depends on some far less widely used libraries (such as Juxt's fork of Aleph -- and Aleph itself is pretty niche) -- so it really depends on whether you buy into those libraries.

👍 4

These templates are fine if you understand what you're getting yourself into. The Juxt folks are very supportive, so you'll get plenty of help if you buy into their stack but if you decide to use New Relic for production monitoring and metrics, I wouldn't be surprised if Aleph is poorly supported by it (http-kit is not well supported, for example, which was why we switched back to Jetty).

👍 4

Yes, clj-new can execute Leiningen templates (and Boot templates), as well as newer clj-template templates. If you find one that won't run, it's a bug and I'll (try to) fix it. Also, be aware that if clj-new runs a Leiningen template, it's not magically going to produce a deps.edn file -- it'll be a project.clj-based project!


I've got question regarding component and danielsz/system


:handler        (-> (new-middleware {:middleware [not-found-handler
                                                        [fulcro-wrap-api :component]
                                                        [wrap-resource "public"]
                          (component/using [:datomic-db]))
   :wires-http-server (component/using (new-http-kit :port (config :dev :wires-http-port))
                                       {:handler :handler})]


Unfortunately, component/using within wires-http-server does not work as expected. Look at this trace:


TRACE t51411: (system.components.http-kit/new-http-kit :port 3000)
TRACE t51411: => #system.components.http_kit.WebServer{:options {:port 3000}, :server nil, :handler nil}
Execution error (NullPointerException) at system.components.http_kit.WebServer/start (http_kit.clj:11).


Why does handler is not updated?


what does new new-http-kit do?


It's standard component from danielsz/system


oh, I bet reset is starting your system and one of your components has a bad stop behavior which causes it to not restart correctly


Look - the :handler in TRACE is nil


The problem is that :handler in new-http-kit call is not updated with component/using


According to the source you need to pass the handler to the factory function


not as a component dependency


So how should I arrange dependencies in this case?


Hmm, but new-web-server is marked as deprecated...


I ended up creating my own components for simple use cases like this, where you have a clear separation between the server and handler component