This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-10-27
Channels
- # announcements (13)
- # asami (12)
- # babashka (65)
- # beginners (62)
- # calva (14)
- # cider (8)
- # clara (11)
- # clj-kondo (16)
- # clojure (86)
- # clojure-europe (12)
- # clojure-gamedev (4)
- # clojure-nl (2)
- # clojure-sg (4)
- # clojure-uk (5)
- # clojurescript (206)
- # clojureverse-ops (11)
- # community-development (7)
- # conjure (12)
- # core-async (2)
- # core-logic (13)
- # cursive (49)
- # datalevin (1)
- # datomic (30)
- # deps-new (3)
- # duct (8)
- # events (5)
- # fulcro (10)
- # helix (5)
- # jobs (1)
- # klipse (5)
- # lsp (178)
- # luminus (1)
- # malli (8)
- # meander (3)
- # membrane (13)
- # missionary (1)
- # nrepl (5)
- # other-languages (4)
- # pedestal (4)
- # reitit (3)
- # releases (1)
- # reveal (27)
- # shadow-cljs (89)
- # tools-build (6)
- # tools-deps (11)
- # vim (2)
- # xtdb (64)
Hi, I’ve been trying out the clojure.tools.trace lib and it’s pretty useful. But the data structure it prints look bad bc there are no indent or highlight. I wonder is there a way we can achieve this? I think that’ll make the tools trace much more useful.
(clojure.tools.trace/trace-ns metabase.mbql.normalize)
(doto 'metabase.mbql.normalize-test require in-ns)
(normalize/normalize {:database 4
:type :query
:query {"source_table" 1
"Joins" [{"source_table" 2
"alias" :my/table
"strategy" "left-join"
"fields" "all"}]}})
Hi @U11BV7MTK, The indentation works for me too, but I was trying to find a way to have indentation for the arguments. Something like pretty print for all arguments would be great. Btw, Your logs look nice but I think the highlight is supported by your editor right? I’m actually trying to read the trace from stdout
Is there a way I could re-define a function? (i.e: clojure.tools.trace/trace
)
I tried alter-var-root
but unable to make it work in repl.
normalize-test=> (clojure.tools.trace/trace-ns clojure.set)
nil
normalize-test=> (clojure.set/union #{:a} #{:b})
TRACE t171478: (clojure.set/union #{:a} #{:b})
TRACE t171478: => #{:b :a}
#{:b :a}
normalize-test=> (alter-var-root #'clojure.tools.trace/tracer (constantly (fn [name value] (println "new function!"))))
#object[metabase.mbql.normalize_test$eval171494$fn__171495 0x359121ba "metabase.mbql.normalize_test$eval171494$fn__171495@359121ba"]
normalize-test=> (clojure.set/union #{:a} #{:b})
new function!
new function!
#{:b :a}
Oh, I got it running now. I probably alter the wrong name or something this morning.
Thanks!
Btw that’s a nice way to introduce the constantly
func 😄
Is there anyway I can take a spec and create a new spec that is the original spec with one less key?
Not sure, but you can do this the other way around:
(s/def ::loose (s/keys :req-un [::a]))
(s/def ::strict (s/merge ::loose (s/keys :req-un [::b]))
no, spec is intentionally not supportive of restriction, only addition
@U016XBH746B Even if your spec only lists, say, ::a
you can still have arbitrary other keys in your hash map and it will satisfy the Spec. [caveat: if you have qualified keys in your hash map and they match other spec names, they will be checked, even if they are not mentioned in keys
!]
Thanks, but what I wanted was to make a required key optional without changing the underlying spec. This was a bit of a hack I understand, I fixed it like Lennart sugested
dev=> (s/def :foo/bar int?)
:foo/bar
dev=> (s/def ::a int?)
:dev/a
dev=> (s/def ::thing (s/keys :req-un [::a]))
:dev/thing
dev=> (s/valid? ::thing {:a 1})
true
dev=> (s/valid? ::thing {:a "one"})
false
dev=> (s/valid? ::thing {:a 1 :foo/bar 2})
true
dev=> (s/valid? ::thing {:a 1 :foo/bar "two"})
false
☝️:skin-tone-2: This surprises some people.hey all - does anyone have any pointers for a successful REPL experience with Clojure at http://repl.it?
I have a notebook set up now, but it doesn’t look like the editor has any shortcuts to send forms over to a REPL process. The template assumes you just want to run a full file and see the output.
http://Repl.it is on my shitlist for now. Radon is a friend of mine - he worked at ThinkTopic at the same time I did.
that saves me some time 🙂
Hi, A have a design question: when wrapping a Java lib, is it more idiomatic to expose the positional arguments like:
(defn foo
([obj])
([obj ^Instant instant])
([obj ^long timestamp ^TimeUnit unit]))
or instead provide a map of options:
(defn foo [obj {:keys [instant timestamp unit])
The positional arguments in this particular case provide a nice documentation feature to specify that the timestamp and unit go together, while the instant is used on its own. I'd opt for the positional one in this case.
Yes indeed, good point. I could be tackled though by having a more nested opts
shape: :timestamp {:value :unit}
I'd always prefer proper arg lists. Better documentation, better editor support etc. In this case though I'd consider whether it were possible to present a pure Clojure API (just because some people find Java interop and imports scary). For example, could you just have a function that takes a long representing milliseconds?
@U3JH98J4R can you elaborate ? I don’t understand how I would
if you are gonna write a pure clojure api there is a built in protocol called Inst
that exposes an inst-ms
function that could be helpful - but thats it
@U0CKD1VM4 I think in general though you shouldn’t wrap java apis
there can be some utility or ergonomics gain sure, but its a lot of time and effort for the same end result
To provide an alternate answer - maps are safely future extensible
if you think it might be something that could change in the future
kwargs are yet a 3rd option :instant ...
or :instant ... :timestamp ...
and with 1.11's upcoming trailing map support, kwargs supports both named positional and map forms
@U3JH98J4R @U064X3EF3 thank you for your feedback !
How do you achieve what a normal java class/js object does like getter/setter and a few methods? Wrap record with protocol implementation in atom, or?
why do you want to do that?
doing this is generally an anti-pattern in Clojure
I read this today https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_building_practice and try to convert it to cljs. The canvas api and object read/write is there a good way to do those?
That's inherently stateful, imperative code. Idiomatic ClojureScript would look pretty different.
At some level the equivalent cljs would still have to invoke stateful methods to on the canvas itself (I don't know if there's a nice, functional reactive wrapper for that sort of low-level drawing API?) but in Clojure/Script a ball does not "update itself".
Yes and as far as my knowledge goes I come up with roughly this
(defprotocol Graphics
(draw [_])
(updateVel [_])
(collisionDetect [_]))
(defrecord Ball [x y velX velY color size]
Graphics
...)
(doseq [ball balls]
(draw @ball)
(swap! ball updateVel)
(swap! ball collisionDetect))
And in Clojure/Script we don't use getters -- because we have immutable data (and so there are no setters either).
That approach is very OOP and not idiomatic Clojure/Script.
(this is beginning to feel more like the sort of discussion that would be better suited to #beginners although you also have some #clojurescript specific aspects here since you'll need interop with JS... and I don't do cljs)
You point it out above "inherently stateful, imperative code". What's the approach in clj? the interop is not important.
Plain hash maps for the data. The transformation functions should be pure (data to data).
The only stateful/mutating code you'd need would be (run! render-ball balls)
at each step in the world evolving -- the world itself can also be plain data and it could be "reduced" over a stream of events (such as, say, a timecode).
I'm not sure these are the best examples, but here are a few: • http://www.quil.info/sketches/show/example_equilibrium (quil also supports clojurescript) • A very old example, but still interesting IMO, https://gist.github.com/michiakig/1093917
Conway's Game of Life as pure functions on plain data: https://github.com/sebastianbenz/clojure-game-of-life/blob/master/src/engine/game.clj
The tick
function at the bottom produces a new "world" from an existing "world" and it is called by the (stateful) Swing UI code to produce the data to draw on a timer (the event loop reducing the data over time).
This is the stateful, imperative piece that paints the world on the screen, and transforms the data step-by-step https://github.com/sebastianbenz/clojure-game-of-life/blob/master/src/simulator/field.clj#L47-L59
(it's unfortunate that it has to squirrel away the state in atoms because the rendering machinery -- Swing -- has no inherent notion of data traveling through the system)
But that should provide some good insight into how to separate the bouncing ball problem into a pure data + transform section and a stateful render + update section.
> inherent notion of data traveling through the system
I can't imagine any alternative to atoms (or some other reference type) except maybe loop/recur
. Is there another option?
That Quil/equilibrium example also does a pretty good job of separating those two (albeit in a single file -- but the pure data + transform stuff is all in the first half and the stateful render + update stuff is all in the second half).
@U7RJTCH6J If the driver of the system is (mostly) functional, then it can either just reduce
or loop
/`recur`.
(loop [world (set-up-world opts)]
(draw world) ; stateful/imperative
(recur (step world)))
Right, so either keep state in some reference type or loop
/`recur` (since reduce would be implemented in terms of loop
/`recur` ). Was just curious if there was something else. The reference type is useful if you want to process events in threads outside of the render thread (eg. networking, repl, etc).
Hey guys! I've got a quick question about using ring.middleware.reload
with component
:
I have used the technique that Stuart Sierra suggested for making components available to request handlers, i.e. closing the components over the handlers themselves.
The problem I am having is that I want to use the ring reload middleware for development, but now my top-level handler takes an argument (the component that it requires), but in order to use wrap-reload
, I need to use a var-quote or the var
function:
(defn my-app-routes [component-dep]
(ring/ring-handler (ring/router [(some-specific-routes component-dep)])))
(defn my-app [component-dep]
;; notice component-dep isn't being passed
(wrap-reload #'my-app-routes))
My question is - how do I pass component-dep
to my-app-routes
in order to use the component
library with ring.middleware.reload
?
Thank you!one potential sort of workaround i was thinking was, since the reload middleware is only used in the dev
profile, use the already stored system
var from com.stuartsierra.component.repl
and reference it from inside the my-app-routes
function to get the required dependency (but only in dev
) to make it such that it takes no arguments
but that feels really dirty and would require a separate code path for prod since the routes will have to take an argument (or i'd have to also store the system
var globally in prod too)
I don't use the same libraries as you, but to accomplish the same thing with pedestal and integrant, here is what I did:
1. 'web' becomes a component that depends on various things, like db-pool, cache, etc
2. Those parameters are used when initializing the web system, adding interceptors (middleware in your case), etc, and there is one that injects that system
variable into the request context so that it is available in every request handler
I also wrapped it like this, but that is just to prevent tools from exploding from bloated stringification if there is an exception or something: (reify IDeref (deref [_] system))
(wrap-reload #(#'my-app-routes component-dep) %))
TIL vars that reference functions can be called as functions
probably an extremely shallow insight but news to me nonetheless
it seems to at least partially work. it is recompiling certain namespaces but not others
I didn't realize how slow clojure.zip is - at least for my use case, it's an order of magnitude slower than a hand rolled recursive function
I kind of hoped it would be faster on account of not having to do all those recursive calls
I'm curious what a profile would point to spending so much time on
switching to fast-zip seems to help a ton - down to 2x as slow as the hand-rolled version
I hadn't heard of fast-zip
. looks neat! :thumbsup:
this is a very small set of a data as an example, maybe the zipper comes out ahead of a deeper tree
If you're optimizing for performance, I would also see how the hand rolled version compares to a version using specter
zippers seem (obviously in hindsight) very sensitive to the performance of branch?
children
and make-node
fns you give to the constructor
changing branch?
from
(or (map? x) (sequential? x))
to
(coll? x)
reduced it to 2/3 of the time. it also happened to be more correct for my case