This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-12-18
Channels
- # adventofcode (12)
- # asami (2)
- # babashka (95)
- # beginners (17)
- # biff (5)
- # calva (1)
- # clojure (90)
- # clojure-europe (15)
- # clojure-nl (1)
- # clojure-norway (8)
- # clojure-uk (6)
- # clojuredesign-podcast (2)
- # clojurescript (34)
- # clr (1)
- # community-development (42)
- # cursive (11)
- # data-science (1)
- # datomic (13)
- # graalvm (5)
- # hoplon (2)
- # hyperfiddle (32)
- # off-topic (1)
- # pathom (6)
- # releases (1)
- # shadow-cljs (25)
- # squint (4)
- # xtdb (10)
Looking at some multi threaded code which might show some race condition, I’m wondering (to eliminate some possibilities) is binding
thread safe, ie if I have two threads which do (binding [name (.getName thread)] …)
do I risk a race condition or will this work as expected, ie each thread only having name
contain the value of thread it’s running in?
Depends on the use case, if it happens to be more on the scraping side of things, playwright is most suitable (available on pure java via https://github.com/pfeodrippe/wally, or use a nbb/squint type of thing)
Lately I've preferred just using https://chromedevtools.github.io/devtools-protocol directly. you start chrome with a debug flag and then you get an http/ws api to do whatever you want in the browser. I think I always hit some limitation or another when trying to use webdriver for non-testing automation purposes. Though if it meets your needs etaoin is a great wrapper for it
We use Playwright at work.
Consider also whether you might like to subscribe to a browser test automation service. You can then choose a tool that supports both your local browser and the service you have in mind.
I'd say it's webdriver vs CDP, different protocols with different capabilities (CDP is more featureful but Chrome-specific)
do we have a comment (;) reading/preserving clj/edn reader? I have some big edn files with comments all over the place which I'd like to rewrite automatically? Does clj-rewrite support this?
ok, then I will look into rewrite-edn first. 😀
Oh, huh. I found this and thought that it does, my bad: https://github.com/borkdude/edamame/blob/9dcc3cb19fcfeffddf21e769e1db3f98d3cfd3e8/CHANGELOG.md?plain=1#L95
some comment forms had a ridiculous amount of children forms which caused a problem, apparently
(also, please use 🧵 for replies in future)
Question that’s been bothering me today. Is there any way to get a tagged literal to recursively eval
the same as regular Clojure collection does?
For example, I’ve got a custom record for RDF triples, with an associated tagged literal.
(def foo "")
;; when evaluating a vector, symbol `foo` is evaluated & resolved
(eval (read-string "[foo]")) ; => [""]
;; when evaluating a triple record, symbol `foo` is captured as a literal symbol.
(eval (read-string "#rdf/triple [1 foo 2]")) ; => #rdf/triple [1 foo 2]
I’ve read the source code and it appears that the answer is no, since the conditional for a IType/IRecord is baked into the analyzer and returns a ConstantExpr, but just wanted to check…tagged literal reader functions are a read-time construct to create a value - they take read (but unevaluated) data and return an object (in your case an instance of record or type)
records or types are like any other Java object and evaluate to themselves
Right.. but in this case they’re also (sorta) like a map or a vector, which eval recursively. Curious if any way to make them behave that way.
so, in short - no this is not how it works (and you probably shouldn't actually want read-time eval)
the tagged literal reader is read time
but the way the compiler will compile it is as a constant without evaluating any internal fields
functions are cool things that do eval :)
there even happens to be a positional record constructor that does exactly this :)
https://clojurians.slack.com/archives/C03S1KBA2/p1698763672356679 is a whole thread that ends up on this issue
(rdf/->triple 1 foo 2)
Yep, @U064X3EF3 that’s the fallback. I was just hoping for a construct so that writing literals embedded in code would look the same as when writing them in an EDN file. Would be a bit preferable IMO to have a way to do:
(let [foo ...]
#rdf/triple [1 foo 2])
tagged literals are about data and values. people constantly try to do trickier things with them, and mostly just get into trouble doing so
I kinda feel like this in particular is a justified attempt though since this is how you'd make e.g. a queue and I think it's perfectly reasonable to want a queue literal which can have elements be references to locals.
that's all fine, but why do you need to use a read literal for it?
this is why, for example, if you use a clojure set literal with (+ 1 2) in it, that will evaluate, but if you use an ordered set literal you get the unevaled list
Mostly just ergonomics, it's not really absolutely necessary.
It’s a way in which Clojure data structures (lists/maps/vectors) are privileged syntax… which is fine, that part of the language just isn’t extensible in this respect
correct :)
I can argue that it should be, but am fully aware that would take a well articulated problem statement and a full stack of spreadsheets, haha
tagged literals are a part of edn to be exchangeable with other languages which may not have eval
having eval in your data means you're back to programs, not data
you shouldn't want that for edn :)
I would argue the actual issue is orthogonal to tagged literals… it happens even if you construct forms by hand out of symbols and then call “eval” on them. eval in the reader fn for a tagged literal is 100% evil I agree
this is not "these types should automatically evaluate stuff", this is the behavior of these types when passed through clojure's eval
the thread I linked above ends with https://clojurians.slack.com/archives/C03S1KBA2/p1698768489212979?thread_ts=1698763672.356679&cid=C03S1KBA2 which is a pretty simple protocol that if the clojure compiler used it would allow you to define new set literals that would have their members evaled if passed through eval
Yeah this is the behavior that I would want, and I've talked about desiring this before e.g. when I was writing my ropes library
I see the distinction Alex is making, though. Clojure code is data, but not all data can be code. Right now, lists/maps/sets are special because they are data that can be eval’d as Clojure code, and that mechanism is not designed to be extensible in Clojure as it exists. Tagged literals are solving a different problem. You COULD design a “polymorphic eval” for arbitrary data structures but that would be a design change with significant ramifications.
when serializing objects to bytecode, which the compiler has to do to, if the object isn't something the compiler already has hard coded cases for (including IType and IRecord) the compiler calls printString
(the pr thing is kind of a hack, which is maybe something we could remove with constant dynamic in Java 11)
This is what I ran into when I was working with ropes, where it has support to be emitted into code, but it can't be evaluated recursively.
functions are a fine way to make custom data structures, which can act as Clojure data by implementing the right interfaces. I think it's a non-goal (or even an anti-goal) to make new syntax with custom eval semantics.
no new syntax, it is the same evaluation semantics as core data structures, so I would argue no new semantics
for my strawman, if the type satisfied the protocol (interface would maybe be better in the compiler) when passed through eval, eval would eliminate it, and eval the result of that
and it wouldn't break any existing code, because it would introduce a new interface for this, and none of the existing code implements it so they keep the same non-evaling behavior
the principle I've heard Rich espouse about is being able to read anyone else's program, which is why the read table is not open for extension. in this case, you would need the lib creating the data structure and the semantics its applying at read time to understand how it is to be evaluated. that seems like a step too far, but don't know.
it is already the case with, again, the built in clojure collection types where those get used in contexts where evaluation is expected and where it isn't
I don't understand what you're proposing then
what is the objective?
so with a clojure set #{(+ 1 2)}
is read in as a set with a list in it, then when eval'ed, it generates a set #{3}
so your objective is to ... [say words]
when #ordered [(+ 1 2)]
is read in, it would be some ordered set type containing the list (+ 1 2)
and then after calling clojure.core/eval on it, if the ordered set type implements the right interface, you get an instance of the ordered set type containing 3
honestly this could be implemented without a protocol as long as you can call seq and empty on it
forget the mechanism for a moment, I'm still unclear precisely what the goal is
(into (empty coll) (map eval) (seq coll))
the goal is to allow source code to have literals which have the same semantics as core literals
to have custom literals that have the interior evaluation semantics of core collections
if (-> #{(+ 1 2)} eval first)
is 3, then (-> #my/custom-set-type [(+ 1 2)] eval first)
resulting in the list (+ 1 2)
is kind of a drag
well again, functions
but I see the point
there are lots of ways custom colls that implement the necessary interfaces/protocols can participate in Clojure with identical semantics, this is one place where they don't have the same level of access
This is the best description of the problem statement and issue I’ve seen yet. Might be worthwhile to capture in an ask/jira ticket