Fork me on GitHub

Hello, people. I have a thread running a loop/recur (it's a Kafka consumer). That thread is launched from a call to component/start, and I want to stop that thread (break the loop) whenener component/stop is called. What would be the best way to do this? A hack is to create an atom that is a boolean, and check it before calling recur . It works but I want to avoid global state. If the question is not clear, I can create a gist and share it. Thank you.

seancorfield02:07:43 You can try calling future-cancel on it but the loop would need to be "well-behaved" and be able to be cancelled.


Using an atom like that is not a hack it is good practice


Be sure to wait on the future in your stop, so he future has actually exited by the time it returns


Yeah, that would be my recommendation too: provide some mutable state that can be leveraged to cause the thread to stop. At work we do something similar (but the other way around) -- we wait on a promise in our main thread and the background thread running the server delivers the promise when it shuts down.


Thank you, guys. I was thinking that could exist some way involving channels, but I didn't come up with a solution.


an alternative to an atom (designed for arbitrary and async update from N threads) is a promise or delay (designed to start "uninitialized" and then to be initialized exactly once)


this can give you the same behavior (call realized? to find out if its been initialized, if so you know its time to exit) while clarifying intent (this isn't a mutable box that gets switched around multiple times, it's a one time one way switch)


you can use a promise-chan for the same purpose, but if you aren't already using core.async this isn't worth bringing it in


Thank you too, @U051SS2EU. Could you extend the explanation on using promise-chan? My issue with using channel is that it blocks on receiving from an empty channel, right?


poll! returns immediately in all cases, nil if there was no value, the value on the chan otherwise


a promise chan will start blocked (returning nil on every poll! call) then switch permanently into unblocked (returning the same value for every poll! call)


but really it isn't doing anything a bare promise wouldn't do, and if you aren't using eg. alts! already it's added complexity with no benefit


Oh, I see. So I'll try first make promise and realized? work. Thank you again.


the third function there is deliver (that turns the one way switch to realize the promise)


Yes, sure. Thank you


number_to_human(123)                                          # => "123"
number_to_human(1234)                                         # => "1.23 Thousand"
number_to_human(12345)                                        # => "12.3 Thousand"
number_to_human(1234567)                                      # => "1.23 Million"
number_to_human(1234567890)                                   # => "1.23 Billion"
Is there something similar in Clojure or Java? It seems like a pretty common task but I couldn't find anything similar yet


"intword" Perfect. Thank you very much @jmayaalv

👍 1

you can also do this with clojure.pprint/cl-format without any external library

(ins)user=> (clojure.pprint/cl-format nil "~r" 12)


(ins)user=> (clojure.pprint/cl-format nil "~r" 1234567890)
"one billion, two hundred thirty-four million, five hundred sixty-seven thousand, eight hundred ninety"
not quite what you want I guess


cl-format looks pretty interesting. I need to check it out Thanks!


it implements the format from common lisp, which is extensively documented online (I think someone wrote a whole book on that one function)


A bit surprising to know that cl- stands for Common Lisp.. I have never seen this before. Referencing to another lang pattern/convention from the core functions


haha, we could rename clojure.set/join to clojure.set/sql-inner-join

😀 1

rename for to for-but-not-like-c-for-loop

😂 2

Hi, are there any clj source code formatter that format something like

(let [foo "foo"
      barqux "barqux"]
(let [foo    "foo"
      barqux "barqux"]


Is this the correct way to define a spec to validate this?


user> (number? ##NaN)
;; => true


That's actually correct, do a google search for "Is NaN a number"

👍 1

NaN is weird in so many ways, in multiple programming languages. This Github repo is not actually recommended, unless you are somewhat obsessive-compulsive about such things:

😆 1
David Pham17:07:54

Is there an opposite to destructuring? For example I often have to write {:a a :b b} and I guess a macro could save me from the repetition. Wondered if someone already wrote it?


I defined a keyboard macro in my IDE. I type ==TAB and then whatever I type appears twice, with a colon in front of the first one


==TABfoo => :foo foo

David Pham03:07:58

Nice trick :)


Several libraries have something similar @neo2551 including one of ours...

David Pham17:07:57

Thanks I will look for it then.


there are a few ways to do it - I have this for debugging:

(ins)user=> (defmacro locals [] (into {} (map (juxt keyword identity) (keys &env))))
(ins)user=> (let [a 0] ((fn [x] (loop [q :a] (locals)))  42))
{:a 0, :x 42, :q :a}


Per the docstring of local-map in our library: Inspired by an example from @U051SS2EU on Slack. 🙂


(demonstrating it captures all varieties of local binding)


there's a version in the useful lib too

David Pham17:07:29

Thanks a lot!


Why can I use clojure.string/capitalize without requireing it?


because somebody else required clojure.string first


okay cool, I thought as much




common gotcha - pprint will get loaded by default repls, won't load when running your app


string may or not preload


> common gotcha - pprint will get loaded by default repls, won’t load when running your app ooh, that’s sneaky


best practice (outside a repl at least) is to always require and alias every ns you actually access

👍 1

Hey team, is there a "best practices for setting up clojure with postgres" tutorial you'd recommend? (am looking for recommended libraries, potential ~orm-like stuff, discussion on tradeoffs between diff choices) If something like this exists would love to know!


@stopachka We don't use "ORM" stuff because we don't have objects. next.jdbc is going to be your first stop -- that's a general JDBC wrapper and lets you read/write hash maps from/to rows in the database.

❤️ 1

Start here: -- read all the docs (seriously!)... there's some PostgreSQL-specific stuff in the Tips &amp; Tricks page but the rest should all be generally applicable.

❤️ 1

oo this looks great, on it -- thanks Sean!


I test against Embedded PostgreSQL 12.2.0 but you'll want the regular JDBC driver org.postgresql/postgresql {:mvn/version "42.2.14.jre7"}

👍 1

There's a #sql channel if you have questions.


nice! one quick q, am guessing there may also be libraries that do stuff like: 1. something that handles migrations, etc 2. maybe a macro library, that given some sql structure, gives me a bunch of helper functions for querying 3. some higher-level sql library, so we don't need to write with strings perhaps 2 & 3 are a bit superfluous -- wonder how clj community handles these


Because you mentioned postgres, also check out for an example of extending honeysql.


I use flywaydb for migrations. Works great.


nice, thanks for the recs team!


I'd recommend Migratus for migrations and I'll recommend HoneySQL too (but, caveat, I maintain that as well as next.jdbc). And, yes, the PG extensions to HoneySQL are worth looking at.

❤️ 1

There's a #honeysql channel if you need it. Also, if you want to keep your SQL out of your code (some folks prefer that approach), there's #hugsql -- which has a built-in adapter for next.jdbc (and there's a quick start guide for HugSQL in the next.jdbc docs).

👍 1

ya'll rock team! : }


I just noticed that you can't call pop on a LazySeq, even after calling doall. I have some code that operates on a list as if it were a stack, but there are times when I also must map down the "stack" (I know that is technically a violation of the stack API) and still be able to call pop on the resulting seq. Any suggestions? The only solution I have come up with is (pop (reverse (into '() (map identity '(1 2 3))))) but I don't like needing the reverse.


I suppose I could switch to using rest instead of pop and get the same result except it remains as a LazySeq. Is that good/bad? I would rather have an efficient way to create a list from a LazySeq that doesn't reverse the order.


@erp12 Use a vector instead? And mapv instead of map.


or vector and transduce


why do you need a list?


why is pop better than rest for your use case?


(agreed, for a stack, use a vector, if that's what you need)


lists are faster than vectors for this


but not if you turn them into seqs


oh, so this might actually be the rarely seen use for list*


i checked that. it still returns a seq


user> (pop (list* (map inc (range 5))))
Execution error (ClassCastException) at user/eval140786 (form-init377868074523440121.clj:18).
clojure.lang.ChunkedCons cannot be cast to clojure.lang.IPersistentStack


whoops. i see in main. sorry


np - I should have mentioned that here as well


as the doc string says "Creates a new seq ..."


if you're going to use stack verbs then I'd stick with stack api


I went with lists because of the note here:


well that's fine until you do non-stack things


@erp12 cool - sounds like an actual list is what you want, see the list* function linked on that same node


it gives you a real list without reverse etc.


that sounds worse than using a vector to me


n/m it doesn't return a list


That makes sense. Stacks are stacks. No getting around it.


Thanks all! The only time I needed to map down the stack is to coerce the elements in the event stack is being passed from the outside. That might happen rare enough to accept the cost of a round trip through a seq, or maybe I will just check the stack with a spec and then throw if the caller screwed it up.

Dimitar Uzunov19:07:46

Hello clojurians, I was wondering if this is a correct way to use a repl a running ring webserver:

(defn -main
  "Blogo blog backend"
  (future ;; Pretty cool, it unblocks me from using the repl!!
   (jetty/run-jetty app {:port 9091})))
It fixed my problem - when I run (-main) in the REPL I can still evaluate expressions in it, otherwise it somehow stops working correctly. I think this leaves me two threads - one for ring and one for me.


Passing :join? false in that options hash map will do what you want for the REPL.


But if you do it in your -main, when you run the app outside the REPL, it will just exit immediately.


So I'd recommend writing a function to call specifically from the REPL, and then calling it from -main with a different argument:

(defn start [& [join?]] (jetty/run-jetty-app {:port 9091 :join? join?}))
;; call from REPL as (start)
(defn -main [& args ]
  (start true))

Dimitar Uzunov20:07:16

Thanks! I just tried it out, works for me :)

Dimitar Uzunov20:07:48

but what do you think of using future like that if ring didn’t had :join? ?


It will mean your -main will just exit when you run it from the command line -- which is not what you want.


It also means you won't be able to stop the server within your REPL either.


run-jetty should return a handle for the server, that you can call .stop on.


See this code which has logic to start/stop either Jetty or http-kit (so it's a bit more complex that what you're doing).

👍 1
thanks 1

It captures the result of calling (jetty/run-jetty app {:port ... :join? false}) so that it can .stop it later.


http-kit works differently -- it starts in the background anyway, and returns a handle to the server that you invoke with no args to stop it.


Another reason not to use future like that is that if the server throws an exception, you won't see it -- the process inside the future will just silently die.


You only see the failure if you deref the future -- when it will throw the exception that the process failed with.

Dimitar Uzunov20:07:31

thanks! Usermanager is just I was looking for - I wanted to read some clojure example code like this.


Can someone please explain how I'd use spec in production code?


I understand it principally


And I've played about with it on the repl


But how is it actually used in the wild?

seancorfield23:07:24 talks about how we use Spec at World Singles Networks. We've been heavy users since the 1.9 alpha days.

metal 1
Ilari Tuominen05:07:43

Thanks for writing this, I really needed to read it.