This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-04-29
Channels
- # announcements (35)
- # aws (40)
- # babashka (10)
- # beginners (119)
- # calva (25)
- # cider (13)
- # clj-kondo (15)
- # cljsrn (23)
- # clojure (205)
- # clojure-dev (3)
- # clojure-europe (15)
- # clojure-germany (3)
- # clojure-italy (3)
- # clojure-nl (2)
- # clojure-uk (58)
- # clojurescript (193)
- # community-development (2)
- # conjure (147)
- # core-async (49)
- # cursive (47)
- # datomic (27)
- # duct (1)
- # fulcro (19)
- # graalvm (3)
- # graphql (1)
- # helix (3)
- # hoplon (11)
- # jackdaw (1)
- # joker (1)
- # juxt (5)
- # kaocha (1)
- # keechma (3)
- # lambdaisland (6)
- # local-first-clojure (27)
- # malli (5)
- # off-topic (41)
- # rdf (27)
- # re-frame (7)
- # reagent (15)
- # reitit (5)
- # rum (11)
- # shadow-cljs (157)
- # spacemacs (18)
- # sql (4)
- # xtdb (8)
Hi! I have a question. Let us say that i have a macro that replaces all occurrences of 'transact' to '\', sth like this:
(defmacro transmuting-macro [& body]
(let [transmuted-body (clojure.walk/postwalk
#(if (and (list? %) (= 'transact (first %)))
(-> % rest (conj `/)) %) body)]
transmuted-body))
Now i can do this:
(defn generate-error []
(transmuting-macro (let [x 1
b (transact 1 3)]
(transact 3 0))))
But exception's stacktrace cannot track what is inside, it stops at the macro invocation (line 2) and then immediately jumps to divide without providing any meaningful line number (in this case line 4).
If i put just body instead of transmuted-body in macro definition's last line the stack is preserved. So, I reckon, there is some hidden info somewhere that allows the compiler to introspect some macros but not others.
I have tried to look at meta as well as special &form and &env variables but to no avail.
Since my transmutation doesnt change anything about line numbers, just copying this information would suffice. Does anyone know how it works?My first thought is that (-> % rest (conj ...) ...)
is losing any metadata that was on the original form
@mll Did you try something like
(with-meta (-> % rest (conj `/)) (meta %))
?(and you may need to capture the metadata from (first %)
in that expression and add it to the /
symbol)
It may be that postwalk itself doesn't preserve metadata?
Hmm, I'll have to go digging. I ran into similar issues when working on expectations.clojure.test
. I seem to recall needing to read metadata from &form
(which is where the source form for the macro originates) but I can't remember how I propagated the data.
Hmm, no, looks like I sidestepped all of that in the end. Sorry @mll I have no suggestions right now.
I did some digging and it seems there is a certain pattern to metas inside the form but not outside of it
(with-meta transmuted-body (meta &form))
would be my best guess at this point @mll for the body of your let
instead of just transmuted-body
there is a bug filed for this
or at least I thought there was, not seeing it
seems like this came up recently, but I don't know where then, don't see it in ask or jira
actually I am seeing it preserved in postwalk?
isn't this just the old issue https://clojure.atlassian.net/browse/CLJ-865
https://github.com/ztellman/potemkin/blob/master/src/potemkin/walk.clj I've had to use this a couple times to fix problems. Maybe it was when I was using map
& similar on the sequences though :).
@alexmiller there we are, lists & seqs lose their meta:
user=> (clojure.walk/postwalk identity (with-meta (list 1 2 (with-meta (list 3 4) {:bar true})) {:foo true}))
(1 2 (3 4))
user=> (clojure.walk/postwalk identity ^:foo (list 1 2 ^:bar [ 3 4]))
(1 2 ^{:bar true} [3 4])
well, afaik there is no ticket about this
(s/def ::generate-labels (s/keys :req-un [::label-template
::data]
:opt-un [::api-version]))
is it possible to force (clojure.spec.gen.alpha/generate (s/gen ::generate-labels))
to generate data with all :opt
and :opt-un
? Also nested deeper. Just I would like to be able to genere full example of data.you could write an alternate spec where the optional things are required, then use its generator as the generator here
thanks for the suggestion. Probably the best is to write macro which will create this spec using real one.
I required the cljs deftest and tried unmapping it like so: (ns-unmap 'cljs.test 'deftest)
But when I try to require the clj deftest (require '[clojure.test :refer [deftest]])
Okay so how do I require the clj deftest in user ns given that the cljs deftest is already defined in that namespace?
you can use (ns-unmap 'some.ns 'sym)
or (def sym nil)
from inside that ns
ns-unmap actually removes the var entirely, def just happens to remove all aspects of the var that are usually a problem (eg test or macro metadata)
Hello everyone,
I have general question, about consuming messages from Kafka topic, is it better to collect all messages into async channel and handle it by pure methods which take channel and process it and return new output channel and so on or what is the best approach to model that ?
the gotcha of lifting a kafka consumption into eg. core.async is that you either immediately confirm you received the message (effectively lying) or risk that you might get booted from kafka because you took too long to consume the async message and confirm it (leading to error prone and complex recovery code)
the main question is what you want to do with those messages - accumulate a running state? treat them as requests for tasks to perform?
process some new data and put that back onto a kafka topic?
@noisesmith will fetch the messages and do some processing on it and then save into db
it's not safe to do db calls inside a go loop or a kafka stream - in the go loop case you risk starving the go threadpool, in the kafka stream you risk being kicked out of the cluster
so what do you think good approach to model that?
inside a go loop you can safely do longer calls with (<! (async/thread ...))
, thread returns a channel you can read and will offer a value when it completes
regarding kafka, you could confirm the consumption of the message immediately, then dispatch to a future
or send a message with put!
and handle it in the consumer (probably via thread...)
but you've already told kafka you're done with the message, so if you need fault tolerance (eg. picking up where you left off if there's a crash or the task can't complete etc.) you need something separate, as far as kafka is concerned your consumer group is no longer interested in that message
(that's the gotcha I ran into when I tried to combine kafka with core.async to make a microservice / task management infrastructure)
Volatile mutable is useful internally (which is why it makes fields private) when defining complicated deftypes
I want to build a custom ref type (similar to atom). my main use case is CLJS, but I think it would be cute to support CLJ as well
You might use volatile mutable for that, but it will depend on the specifics. You should be very careful implementing mutable stuff shared between cljs and clj, you can get away with a lot on js that is very unsafe with multiple threads
@lilactown so something like volatile
?
I'm at the level right now of "googling what the java volatile
keyword does again" because I really don't live too much in the JVM runtime
@lilactown yeah, to add to what @hiredman is saying, I see a continuum from single process js, to multi process jvm, to multi server distsys, where every concurrency semantic gets harder to implement, and more gotchas come into play
and why are you not using atom?
It is unlikely that you custom ref type will be safe to use based just on volatile(but possible), so you may was well just assume you need a lock or an atomic ref
I want some special behavior (reactivity) on deref/swap/etc. I suppose I could have my custom type contain an atom and pass some of the methods through
fwiw, compare-and-set!
is available if you want to change the semantics slightly
it allows you have to slightly lower level access to the CAS mechanism
or I could pass in a java.util.concurrent.atomic.AtomicReference
in the constructor and copy the general pattern in clojure.lang.Atom
@lilactown reactivity other than what add-watch or set-validator gives you?
I have a hard time imagining reactive semantics that aren't covered by those, I'd be fascinated to hear what you mean
it's mainly API/syntax. my goal: play with building a reagent ratom-like data structure, outside of the reagent view lib, and cljc
so e.g.:
(def foo (r/atom 0))
(def bar (r/reaction (* @foo 2))
(add-watch bar :log (fn [_ _ _ v] (prn :bar v))
(swap! foo inc)
;; out:
;; :bar 4
you may be interested in javelin/hoplon https://github.com/hoplon/javelin
there is also a version for the jvm in progress
if nothing else, the folks in #hoplon are doing some interesting experimentation and are pretty responsive if you wanted to discuss ideas in a similar space
is it the and do your reaction stuff part that will be difficult to do atomically using just an AtomicReference?
I mean, I guess you could build a spin lock using atomic reference, but at that point you can just use a Lock
I guess I’ll have to think about if what I really want is an atom, or something more akin to a fancy agent
when I think high level what I actually want in CLJS, I don’t know if I want to guarantee that changes are synchronously invoked
it could be useful for React apps to have external state that participates using the React scheduler
do you have an example of how that would be used?
some API like:
(def state (r/agent 0))
(defn my-component []
(let [[current send] (r/use-agent state)]
[:button {:on-click #(send inc)} "+"]))
updates to state
would not be immediately available, so logging the value of current
or even @state inside the handler would have the old statethe update inc
would be schedule to be run at some future time and would trigger a re-render in the component
re-frame
sort of does this
although, I think this is the wrong direction. imho my-component
should just be a normal pure function
I know hooks and subscriptions are the popular mechanism these days, but I don’t see why my-component
doesn’t just take num
as a parameter
I’m not interested in bike shedding about where and when to do that, it’s a simple example
hey lets say I have a namespaced keyword :dojo.domain.error/not-found
I want to convert it to a string but (str ns-k) -> ":dojo.domain.error/not-found"
and (name ns-k) -> "not-found"
I could drop the first char of the string of course but I wonder if there a better way of doing this
(str (namespace ns-k) "/" (name ns-k))
does that work? I get an error:
> (symbol :foo/bar)
ClassCastException class clojure.lang.Keyword cannot be cast to class java.lang.String
Clojure 1.10.2-alpha1
user=> (symbol :asdf/we)
asdf/we
user=> (str (symbol :asdf/we))
"asdf/we"
worked like a charm thanks @U050ECB92
ok, I’m still on clojure 1.9. guess I need to upgrade
Rules engines often have the idea of quiescence, meaning you introduce new information, rules fire for a while asserting and retracting, until a stable state is reached
which is kind of like a transaction (introduce novelty -> react to novelty in private -> expose new start of the world atomically) which might lead you to wanting something like more like refs then atoms
yeah I like that. I think that transactionality of the reactive graph would be a great guarantee to provide, to avoid getting into broken/inconsistent states
I need some way of computing an entire transaction without actually mutating anything
https://www.microsoft.com/en-us/research/uploads/prod/2018/03/build-systems.pdf "Build Systems a la Carte" connects to some of this
the funny thing is already started building a reactive lib that reifies the graph in a map and left it unfinished (it’s slow / has a lot of work to be done). then today I was like, “I don’t need all that, I just want ratoms without reagent” and here I am again
I think I’ve tried to scratch this itch and gotten to the same place like 3 or 4 times now
I am very skeptical of a lot of this dataflow ui stuff (but I also don't write a lot of uis), because it seems to end up building a system of continuous change which seems harder to understand than a discrete one
https://dspace.mit.edu/bitstream/handle/1721.1/44215/MIT-CSAIL-TR-2009-002.pdf is some related work as well
I think one of the benefits of reifying edges in the graph is the ability to observe changes to the whole system much more easily
I'm trying to create a web front end for a clj repl process. I will send code strings from the cljs client to the backend. I believe I have a lot to learn and feel kinda lost.
I think I can start a clojure.main/repl
process on the server.
Is it just a matter of wrapping that clojure.main/repl
call a binding that binds *in*
and *out*
to things that can be "sent" input and "receive" output? Any pointers for how I can start to approach this?
I would 100% recommend starting an nrepl server and then connecting to the nrepl server rather than working with raw *in*
and *out*
I have this unfinished thing https://gist.github.com/86aeb916b478d9e57cbce8e0e678babd
it has been a while since I was tinkering with it, but I think the main thing missing is the public/private key authentication bits
wrap-repl is ring middleware, and http-repl is a function you call to connect your repl to a remote wrap-repl
that looks great thanks, I think half the hard part for me is figuring out the java classes to use for the in/out stuff
don't forget *err*
you could use inputstream / outputstream pairs to interact with the repl, yeah
to talk to the repl, you have an outputstream that pipes to an inputstream that feeds *in*
and the reverse for *out*
and *err*
also, a repl (read, eval, print, loop) is something you can just construct, it's not magic
read the data from client, call eval on that, print (prn) the result to the client
(though there is bookkeeping for things like current ns dynamic vars etc...)
Yeah that was my first approach but I was having issues evaluating ns
forms so I figured I'd jump into the main repl stuff
Has anyone seen an example of a macro that merges the (cond-> behavior with (-> such that it threads the value from each expression into the next conditional?
Would like to reduce nesting so looking at that and potentially things like a maybe monad.
(and these are external service calls dependent on prior values)
@activeghost https://stackoverflow.com/questions/51993246/a-cond-threading-macro-alternative-that-refers-last-threaded-state-inside-pred https://github.com/Engelberg/better-cond
but I agree with @noisesmith and usually just jam together as->
and cond->
Thx. Yes, I could use those but given these are expensive I want short circuit vs (let ... (if () (let ... (if ... ()))). I kind of want a (cond-as->
"expensive"
oh, then you want some->
in there
they are external service calls, don't want to make them ahead of time. I also want control over the return value .. so (some-> would work with some munging (to allow a predicate to determine instead of nil)
I think what you want isn't a syntax rewrite, and all these threading operators can do is syntax
none of them have real semantics
you can use run!
or reduce
to call each function in a series, and then use an exception or reduced
to force short circuiting
at least that has meaning at runtime beyond moving parens around
True, will try that route first. Hadn't thought of running them as a sequence in reduce.
(reduce (fn [state f] (f state)) init [f1 f2 ...])
if any of the fs return (reduced v)
that will prevent further functions from running, and will be the return value of reduce
if you find it ugly, you could make a macro that takes each form in a body and puts it in a two-arg function
We'll see, I've done this for other things just not sequences of server calls. I can hand it a sequence of partially applied fns and avoid the macro as they all return the same shape. Thx!
also (defn rapply [state f] (f state))
might be nice to in that sort of idiom
a silly little dsl
(cmd)user=> (defn rapply [state f] (f state))
#'user/rapply
(ins)user=> (def pt (partial apply partial))
#'user/pt
(ins)user=> (defn states [init & fs] (reduce rapply init (map pt fs)))
#'user/states
(ins)user=> (states 0 [+ 1] [* 3] [/ 2.0] [reduced] [#(throw (ex-info {:oops %}))]])
0.6666666666666666
(ins)user=>
I think I've been reading too much scheme code
I've been messing with guile lately, for a weekend project that sneaks into my real time
i’m trying to see if it’s possible to do multiple swaps within a dosync (which is probably an abuse of dosync, if possible)
what's unclean about that?
swap! and dosync are unrelated
@gtzogana to be clear, what you have above already happens (except the exception goes all the way up, isn't caught by swap! itself)
is there any notion of transactional operation on more than one atom? or am i just using the wrong primitive
that's what refs are
Is it possible configure the clojure reader, so it would not ignore comment only lines?
@hoertlehner I was not aware that the Clojure reader would give back comments, ever, in any form, metadata or otherwise. How did you get it to do so for the first string?
I have not actually used a 3rd party Clojure library to get the contents of comments from Clojure code or data, but you could see whether https://github.com/cgrand/sjacket does what you want, with the warning that it might not.
It is possible to extend the built-in reader, if you are willing to copy it, modify it yourself for that purpose, and if you ever distribute it, do so under the EPL license that Clojure code is released under.
Depending on whether you prefer to write Java or Clojure code (the Clojure reader is implemented Java), the tools.reader library does most the same thing, but implemented in Clojure. It also does not do anything to preserve comments for you..
There are also other clojure parsers, I'm using https://github.com/xsc/rewrite-clj and I've heard good things about https://github.com/carocad/parcera
And depending on what your goal is, there are 3rd party libraries that might already do what you want.
The reader’s job is to turn strings into data. Retaining comments or other white space is outside its main job. As Andy said, there are parsers that retain this context that might be a better match for your needs.
https://github.com/carocad/parcera or https://github.com/xsc/rewrite-clj are ones I've seen mentioned recently