This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-04-06
Channels
- # announcements (1)
- # babashka (7)
- # beginners (93)
- # bristol-clojurians (1)
- # cider (7)
- # clj-kondo (42)
- # cljs-dev (9)
- # clojure (67)
- # clojure-europe (4)
- # clojure-france (4)
- # clojure-germany (2)
- # clojure-italy (3)
- # clojure-nl (10)
- # clojure-uk (62)
- # clojurescript (11)
- # clojurex (3)
- # conjure (77)
- # cursive (16)
- # datomic (105)
- # docker (4)
- # editors (3)
- # events (5)
- # fulcro (34)
- # jobs (1)
- # juxt (7)
- # kaocha (7)
- # lambdaisland (3)
- # lein-figwheel (2)
- # leiningen (19)
- # malli (14)
- # meander (6)
- # mid-cities-meetup (6)
- # off-topic (20)
- # pedestal (2)
- # reagent (17)
- # reitit (7)
- # remote-jobs (1)
- # shadow-cljs (17)
- # spacemacs (23)
- # specter (2)
- # tools-deps (34)
Is it possible to wrap the clojure.core.match
and cljs.core.match
macro with a single macro in a .cljc
file that will use the correct one in the correct runtime?
I am currently trying this:
;; mylib.match.cljc
(ns mylib.match #?(:clj (:require [clojure.core.match :as m])
:cljs (:require-macros [cljs.core.match :as m]
[mylib.match :refer [match]])))
#?(:clj (defmacro match [& args] `(m/match ~@args)))
;; mylib.core.cljs
(ns mylib.core
(:require [mylib.match :refer [match]]))
(println (match 2 1 true 2 false))
which works from .clj
but when compiling .cljs
I get
WARNING: No such namespace: clojure.core.match, could not locate clojure/core/match.cljs, clojure/core/match.cljc, or JavaScript source providing "clojure.core.match"
on build and
TypeError: Right-hand side of 'instanceof' is not an object
on run.
I assume this is because the macro compilation pass will be following along the #?(:clj
reader path so it includes the clojure.core.match
macro in the .cljs
source.One common approach is to define a helper:
(defn cljs-env?
"Take the &env from a macro, and tell whether we are expanding into CLJS."
[env]
(boolean (:ns env)))
(defmacro match [& args]
(let [cljs? (cljs-env? &env)]
(if cljs?
`(cljs.core.match/match ~@args)
`(clojure.core.match/match ~@args))))
And then export the macro for CLJS in the ns:
(ns mylib.match
#?(:cljs (:require-macros [mylib.match]))
(:require
#?(:clj [clojure.core.match]
:cljs [cljs.core.match])))
If you do a lot of that I would recommend macrovich https://github.com/cgrand/macrovich it helps a lot
awesome thank you both!
is it possible tell deps.edn
to always (require '[x :refer [y]])
? e.g. if I want access to clojure.pprint/pp
in the repl
Does putting
(ns user
(:require [clojure.pprint :refer [pp]]))
in your project's src/user.clj
or dev/user.clj
work for you?I usually copy Duct's setup[1]:
• In user.clj, there's a (dev)
function that swaps over to (ns dev)
• In dev.clj, I require project dependencies, and create a (go)
function that starts my system (eg. with Integrant)
• Any extra functions like pp go in dev.clj
Reason for user/dev split: I can start a REPL even if my project doesn't compile.
[1]: https://github.com/duct-framework/docs/blob/master/GUIDE.rst#starting-the-repl
not really. It is for computaitionally intensive tasks, that is mentioned in pmap’s docstring.
https://clojure.org/about/concurrent_programming here you can find a good starting point for your solution
@U3QUAHZJ6 you may also find this video helpful on this topic https://www.youtube.com/watch?v=eRq5UBx6cbA
Is there a way to call a specific namespace function in an uberjar, passing it arguments from the command line when invoking it with java -jar myuberjar.jar
?
java -cp myuberjar.jar clojure.main -m my-project.core
?
If you're using ubderdeps you can also create an executable JAR by giving it the --main-class
See: https://github.com/tonsky/uberdeps#using-the-generated-uberjar and: https://github.com/tonsky/uberdeps#creating-an-executable-jar
@UE27GJZR8 for that usage you want -cp
instead of -jar
, otherwise that is correct
also this doesn't work with Capsule jars (the solution is to not use Capsule)
Yes you're right you need -cp
No, clojure.tools.cli
doesn't. I don't know how widely applicable adding parsing might be for that case, since the most common type of positional parameter is likely to be a filename?
@U1QMBJY01 Feel free to describe your use case here https://ask.clojure.org/index.php/activity/contrib-libs/tools-cli and we can have a discussion about it (that's the jumping off point for issues that get into JIRA for Contrib libs).
Will do. And my usecase is exactly that, I've got two files as positional arguments and it would be nice if I could get precisely that verified in http://tools.cl
Question asked: https://ask.clojure.org/index.php/9217/is-it-possible-to-parse-positional-arguments-in-tools-cli
Thanks. Will take a look and have a think about it.
(in this case, the reader produces a set with two lists in it, each containing a symbol)
as long as at the evaluation time, two (rand) give different value then it would be fine. the reader checker seems redundant.
it is redundant, but also useful in some cases. and it's not possible for the reader, pre-eval, to determine whether it's one of those cases or not
it is literally non-sensical to read #{1 1} - that is not a valid literal set
that accidentally ensnares cases like #{(rand) (rand)}
but a) those cases are rare, b) it is not generically possible to determine the difference pre-eval, and c) if you really want to do that, use (hash-set (rand) rand)) instead
Does anyone have any suggestions for using core.async
instead of callbacks for processes that may take hours or days?
the only suggestion I can think of is you’ll probably want to create and manage your own threads. I’ve found that the default threadpool core.async
used by go
blocks usually doesn’t give you right control for long running applications.
for things that run for days, you probably want something outside the VM to store reloadable state, nothing in clojure directly addresses this
adding to what @U7RJTCH6J says - not only is the thread pool for go loops relatively inflexible, it's specifically not intended for long running tasks, and you can break core.async by using it that way (async/thread provides a relatively easy escape hatch for that though)
you can also create threads pretty easy with
(def my-thread (java.lang.Thread. (fn [] ...)))
;; start with .start
(.start my-thread)
you can then check if .isAlive
and a few other things.do you know how many blocked threads I can have in Java 8 -- or how much memory per thread would be used up (might be a better measure).
it probably depends on the OS, but I think the number of blocked threads can be a lot. you don’t have to create a new thread for each task. you can do something like
(defn start-task-runner [ch]
(java.lang.Thread.
(fn []
(loop [work (<!! ch)]
;; stop when channel is closed
(when work
(work)
(recur (<!! ch)))))))
(def worker-ch (chan))
(def my-thread (start-task-runner worker-ch))
(>!! worker-ch (fn [] (stuff-to-do!)))
one other note about creating your own threads is that you’ll probably want to do something similar about thread bindings that the async/thread
macro does
(defn thread-call
"Executes f in another thread, returning immediately to the calling
thread. Returns a channel which will receive the result of calling
f when completed, then close."
[f]
(let [c (chan 1)]
(let [binds (clojure.lang.Var/getThreadBindingFrame)]
(.execute thread-macro-executor
(fn []
(clojure.lang.Var/resetThreadBindingFrame binds)
(try
(let [ret (f)]
(when-not (nil? ret)
(>!! c ret)))
(finally
(close! c))))))
c))
(defmacro thread
"Executes the body in another thread, returning immediately to the
calling thread. Returns a channel which will receive the result of
the body when completed, then close."
[& body]
`(thread-call (^:once fn* [] ~@body)))
I think memory per thread is also OS dependent.
Thanks for your replies @U7RJTCH6J!
there's a lot of advantage to not using go blocks to execute tasks, but I don't really see the benefit to using Thread directly instead of the expanding / cached pool that async/thread uses
there may not be. having the Thread itself gives you access to .isAlive
, .getStackTrace
, .join
and .interrupt
which you could implement on top of the async/thread
, but it’s useful to get those for free. you might not need those for your production environment, but they can be really useful for development and debugging. you might be able to get access to thread even if you use async/thread
, but I don’t think it’s a good idea to rely on async/thread
using any particular Executor.
@UGNMGFJG3 when I had to do some long running java tasks I had some logging/recovery/alarm logic on the outside of the thread and I had everything pushed to a queue that the thread consumed from
@U7RJTCH6J fair enough, but clojure's future lets you use all of those, plus conveying bindings and using a nice caching executor
and you can get the Thread object from inside any context via (Thread/currentThread)
I tend to think core/async will be superceded by jvm fibers if we are alive when they come about
yea, it’s probably better to start with future
and async/thread
and you can switch to holding onto Thread references if you need it. where i’ve found keeping a reference to the thread useful in the past is that I’ve been doing tasks in the background and at some point, one of the background tasks drops the ball and I need to figure why. if I have a list of the threads, then I can more easily inspect them and build dev tools around it.
getting access to the current thread is less useful for what I’m thinking about since it’s usually some other thread that isn’t doing what I want
holding onto Thread references is mostly about being able to build a nice dev workflow that makes dev and debugging easier
I was thinking of a pattern like (let [executor (promise) thread-c (async/thread (deliver executor (Thread/currentThread)) ...)] ...)
which is clumsy but not hard to add in during dev