Fork me on GitHub

hello clj community! is there a function like clojure.string/replace-first for the last match? replace-last?

Alex Miller (Clojure team)12:08:45

no, but you can use replace-first with proper regex to do it

Alex Miller (Clojure team)12:08:48

user=> (clojure.string/replace-first "HI FOO FOO" #"(?s)FOO(?!.*?FOO)" "BAR")

Alex Miller (Clojure team)12:08:41

5 minutes ago I could not have told you how to do that, but I googled “java string replace last” and took the top stackoverflow hit -

Alex Miller (Clojure team)12:08:00

that page explains the regex in more detail

Alex Miller (Clojure team)12:08:44

Java has a large SDK and an enormous user base - lean on it!


ahh cool thanks!


@ferdi.kuehne Actually, there is a simpler and more correct way:

user=> (clojure.string/replace-first "aabaabaaab" #"(?s)(.*)(aa)" "$1AA")


Is there any easy way to get the time, with timezone from a string with clj-time? for instance "2013-02-12T04:30:00.000-02:00"


clj-time.coerce/to-date-time seems to get it and convert to UTC, which you could add back with clj-time.core/to-time-zone but this seems a bit fiddly to me


Especially as you’d still need to specify the timezone from the string somehow


Is this what you're looking for @torvaney?

(require '[clj-time.core :as t])
(require '[clj-time.format :as f])
(f/unparse-local (f/formatter-local "HH:mm:ss") (t/time-now))
=> "17:12:29"


Yes that looks like it


Thank you

👍 4

Hey all, often when I'm working with large nested data strucutres in clj I spend a lot of time trying to find the nested part of the stucture I want and generally just trying to get a mental image of how it's organised. I would love to able to see a tree like representation of the data structure.... Does anyone have any tips or tricks to help with this aspect of clj?

mfikes16:08:41 The main thing I do is pretty-print the data, if it is not too large. The line breaks and indentation help a lot.


:thinking_face: honestly the experience in CLJS using cljs-devtools or frisk is quite a bit better than what’s available for Clojure


oo that is nice


these suggestions look like just the ticket. thanks!


datawalk looks interesting


where’s the best place for clojure code reviews?


reddit or clojureverse - or even here 🙂


#code-reviews has a few people in it


Just found out about Graal and Truffle. Turns out you can compile Clojure using Graal.


you sure can, head over to #graalvm if you’re interested in this stuff!

Nick Cabral19:08:59

@noisesmith a follow-up to my question yesterday about promises/futures vs. core.async channels: I found an older doc that echoed my exact concern (even mentioning C#'s async/await implementation, which motivated my question, as an example for solving the problem). I'm still reading through it to figure out how it was solved, but it seems the core.async channel implementation is the solution to my concern with promises/delays. I believe the conclusion you and I reached previously was incorrect. Here's the doc I'm referring to:


which part was incorrect?

Nick Cabral19:08:23

That derefing a promise/future doesn't busy-wait.


it doesn't busy-wait. busy-wait here means consuming CPU while waiting


it just blocks until something wakes it up by setting the value


you might not want to block a thread for resource or performance reasons, but it's not a CPU issue

Nick Cabral19:08:30

Yeah, it's the "you might not want to block a thread for resource or performance reasons" that I'm concerned with. The async.core channels don't exhibit that problem when awaiting values. I think my original question was confusing because I mentioned "OS threads", wording that I copied directly from the async.core documentation.

Nick Cabral19:08:05

I'm still not convinced that "dereferencing a promise consumes no CPU while waiting". What I've read so far indicates that clojure promises aren't implemented with any mechanism that allows callback-like execution upon the availability of a value. Which implies CPU consumption at some level during blocking. Have you seen something in the clojure codebase or docs that suggests otherwise?


deref doesn't loop, it sets a monitor so the thread resumes when the data is delivered


in general, if your notions of threads and asynchronous whatever come from a runtime without real concurrency (javascript, any of the interpreted languages with a GIL), your intuition about how things work and what happens when is going to match the reality of a concurrent runtime with real threads


and that context will also color how you understand documentation that you read


e.g. my reading of that async+blocks page doesn't convey any concern about busy waiting


a jvm thread is pretty cheap, and depending on your resources you can have a whole lot of them (tens of thousands or more) sitting around doing nothing without you noticing


and they can do nothing without busy waiting

Nick Cabral20:08:32

"Busy wait" came into the conversation because in my original questioned I mentioned "OS threads" like the async.core page does. That's my fault. Although as far as I know, blocking a JVM thread would indeed block an OS thread. But that's besides the point. The info I was looking for is that "promises/delays block their thread (resources are tied up) when dereferenced, whereas channels don't (similar to async/await mechanisms in .net, JS, and scala)".


blocking an os thread is not busy waiting


blocking an os thread generally means the thread is removed from the schedulers ready list until some other thread puts it back

Nick Cabral20:08:50

Right, and all of that involves pushing data around. That's okay too. The point was that it doesn't make sense to spin up multiple threads (which aren't what I'd call "cheap", although that's relative I guess) and have them all block until ready, when the language has an idiomatic way to handle async programming (via the core.async lib).


they are very cheap


core.async does spin up multiple threads, by default the threadpool that services go macro callbacks is 8 threads, and provides the thread macro for tasks dispatched to an unbounded caching threadpool

Nick Cabral20:08:08

It does that in order to implement the async behavior (I'm kind of guessing on this part, haven't gotten that far into that code yet)

Nick Cabral20:08:43

Compared to other language implementations where perhaps a state machine is used.


so the difference between using the go macro, which on parking on a channel suspends the rest of the computation and attaches it to the channel so when another operation on the channel happens it can be re-woken up, and a thread being taken out of the os ready list and waiting somewhere for another thread to re-schedule it is pretty hand wavy


Looks like the JVM maxes out at some 30 thousand threads


For straightforward parallelism core.async won't increase performance, in fact it usually makes things slower. What core.async is good for is making code that does a lot of asynchronous coordination easier to read, and lowering the overhead of code that does massive amounts of context switching

💯 4
Nick Cabral21:08:21

Agreed fully. I think we're on the same page now.


@john where did you get that number?


I doubt that is a jvm limit, more often you hit the os default limits, which are tunable

Nick Cabral21:08:58

@john thanks for the link, I had not heard of FIbers. Worth watching.


The OS is the problem with OS threads... They can't do millions of threads.


core.async code is almost certainly going to do more context switching then regular threaded code


Well, on commodity hardware I'm guessing


but they typically can do enough for whatever you want to do


I far prefer them over working with core.async


and you can use core.async with threads


core.async the library has two parts: channels and the go macro


the go macro transforms what would be code full of callbacks on channels in to something more easily read


and channels are a kind of queue


you can use channels from regular threads


(core.async uses promises to un-callbackify the api)

👍 4

Aye, for millions of concurrent clients, a few thousand threads each handling a few thousand clients via core.async is probably the way to go, right?


Though I guess it's questionable how many threads beyond the number of cores will benefit, when using core.async

Nick Cabral21:08:29

Thanks all. Lot of good info here, some of which is reinforcing my initial suspicions. I've written quite a bit of clojure for a year or so, but haven't delved much into the async-specific corners of the language. Hence my "compare this tool to that tool" question.

Nick Cabral21:08:23

Also glad to hear that just using plain old promise/deref code is common


it isn't very common


because threads are cheap, you don't write async code


so you don't need promises what have you


you call a function and return the value

Nick Cabral21:08:43

So you're saying you'd actually use Thread interop calls rather than running something with Future?


so for example, clj-http doesn't return a promise that has the result of an http call delivered to it, it just does the http call and returns the result


future has nothing to do with promise

Nick Cabral21:08:07

Maybe I'm conflating "future" and "promise" when I shouldn't be.

Nick Cabral21:08:13

They certainly seem to be used similarly


not in clojure


a promise is a container that blocks reading until it has a value delivered


it isn't a thread, doesn't create a thread, doesn't manage threads in any way


(aside from blocking)


future can be thought of as giving a thread a task to do


If I read the write-up correctly, the new java/fibers interface is going to be similar to the java/thread interface. It'll be interesting to see if a Clojure can just choose either as a backing option

Nick Cabral21:08:02

I pictured promise and delay being used like this to do something asynchronously:

(defn my-async-func []
  (let [p (promise)]
    (future (do-something-expensive)
            (deliver p "finished!"))
and the caller could deref the result at will (ie. caller wouldn't have to block until they needed to). But it sounds like that's not a common approach in your experience with clojure?


in that case it would be more common to just use the return value of future over using a promise


and even more common to just call (do-something-expensive) without a future or a promise

Nick Cabral21:08:21

Your first point totally makes sense; I should have seen that. Second point is surprising, so good to know.


if you don't need to run lots of do-something-expensive in parallel or something, there is no reason to spin off another thread to do it


(unless you are using clojurescript)


all my comments should have a parenthetical "if you are using a language on the jvm which has real threads, does not apply to a similar language on a different runtime without real threads"

👍 4
Nick Cabral21:08:04

"there is no reason to spin off another thread to do it" is exactly what led me to core.async. Desire to (1) minimize new threads if possible, and (2) don't want to block the calling thread (this is sort of just my default approach for long-running operations).

Nick Cabral21:08:12

But if #2 doesn't matter, then yeah I totally get it.

Nick Cabral21:08:11

Async/await mechanisms are so common in other code I've written, I wanted to make sure I understood when these different approaches were best used in clojure.