This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-11-15
Channels
- # beginners (97)
- # boot (54)
- # cider (13)
- # cljs-dev (3)
- # cljsrn (9)
- # clojure (64)
- # clojure-berlin (1)
- # clojure-brasil (119)
- # clojure-dev (3)
- # clojure-france (5)
- # clojure-greece (1)
- # clojure-italy (5)
- # clojure-madison (1)
- # clojure-russia (15)
- # clojure-spec (25)
- # clojure-uk (57)
- # clojurebridge (5)
- # clojurescript (45)
- # code-art (1)
- # community-development (17)
- # cursive (24)
- # datomic (83)
- # emacs (11)
- # fulcro (70)
- # hoplon (7)
- # immutant (3)
- # leiningen (19)
- # luminus (5)
- # lumo (25)
- # onyx (123)
- # other-languages (7)
- # pedestal (2)
- # re-frame (12)
- # ring (15)
- # ring-swagger (51)
- # shadow-cljs (89)
- # spacemacs (23)
- # sql (4)
- # unrepl (57)
- # utah-clojurians (1)
- # vim (1)
yes, you can for example launch a clojure repl from the leiningen jar, or include leiningen as a dep of your project. But if you aren’t making a tool that is meant to be used as a leiningen plugin or extension you might be on the wrong track here. leiningen is meant to be a build tool, ideally it and its libraries don’t exist on a production server
https://stackoverflow.com/questions/47309604/dynamic-variables-in-clojure-libraries
guess i'll do the same next time i have questions, post them on SO and then link them here. as a newcomer it is very hard to find answers to some questions others might already had
@zignd Yes. SO is better in SEO and UX that slack logs. 😉
Is this a good pattern for libraries?
(def ^{:dynamic true} *var*)
(defn my-fn [{:keys [var]}]
(do-smth (or var *var*)))
Not really. Binding *defaults*
isn’t really a done thing. Normally you’d (merge defaults overrides)
.
Can even do patterns like:
(def default-sentiment-labels ["foo" "bar"])
(defn my-fn [{:keys [labels] :or {labels default-sentiment-labels}]
,,,)
@leontalbot sometimes, such global variables might be useful. Say, cls-http stores default middlewares in such a global vector. And there is a macro (with-middlewares...)
that substitutes them temporary with binding
@igrishaev Thank you.
Nice answer from Joost Diepenmaat on SO: “In my experience, having dynamic arguments /almost/ always causes more trouble than it saves down the line. You need a pretty compelling reason to have them and in this case I would definitely just make *var*
a non-dynamic default-var
. Note that clojure.java.jdbc (like the example in the docs) used to have a dynamic default db argument but that was removed ages ago.
Does anyone here have some strong thoughts on what a simultanuous put
and take
on the same channel (via alts
) should do? In IRC someone brought up the following:
(let [c (async/chan)]
(async/alts!! [c [c 42]]))
First thought is deadlock, but it actually executes both operations, and returns either [42 c]
(the result of the take
) or [true c]
(the result of the put
). This feels wrong, as the documentation clearly states it should execute at most one operation.@the-kenny This is a weird one -- I'm not saying it's not surprising, but let me offer an explanation of what's going on: alts will attempt its requested ops in a random order. For each op it checks: Did it work immediately? If so return, if not try the next one. In this specific example, one of the ops is selected and attempted (doesn't matter which), and because the channel is unbuffered, that op is enqueued (aka doesn't succeed immediately). alts moves on to the next/other op, and tries it. This op will succeed immediately because the originally attempted op is the complement. Technically, alts is upholding its contract of exactly one op succeeding, but it's the succeeding op that unblocks and runs the other op, not alts itself.
Just to put it on the record, it would be unusual to see this puzzler in the wild (as well as bidirectional usage of a channel within the same function)
Feel free to discuss that in #community-development (but we have 11,000 members and no one is going to fund this at $57,000 per month).
you can get around it to some degree if you use the irc gate. have an irc bot connected constantly and have it save logs.
What does Rich mean when Lisp is ‘tangible’. I’ve looked up the word tangible and I found ‘substantially real’. which doesn’t really make it any clearer.
In that context, it's fair to say that macros make Lisp a more 'tangible' language than others
data is directly readable without going through an interface, your runtime state is always manipulable, even your tooling is often changeable on the fly
or at least that’s what it means to me
I’d add to that that the things that make up your program state are concrete and explicit (reified as data), not ephemeral “fictions” that are enforced by a compiler but missing in the runtime data itself
ah that makes sense yes. when I’m programming in a more static / less interactive language, you can’t really play around with it, you’re not as close to the data. All you can do is watch the program unfold, unless you explicitly build hooks and monitoring into it
even just the fact that you can take an arbitrary piece of data, and say “what type is this?” or print it and expect a reasonable result
For me “tangible” means a REPL that is the whole thing of what a REPL means, coupled with homoiconicity.
For a contrasting example with Python. Python occasionally spits out results in its REPL that’s homoiconic. Or almost homoiconic. I once implemented a bunch of classes’ __repr__
magic functions with a string that was that type’s call to its constructor. This, when used in a REPL, made my Python custom classes behave in a homoiconic way.
But don’t be fooled. If python were made to be fully homoiconic by default yet because of the language, you’d have to implement it without the parenthesis, not many would ever use this feature because macros would be so much harder to write because of the grammar rules being so complicated.
I think this is what Rich was getting at.
Does that make any sense?
how do i figure out out which version clojure has decided to call when doing interop. I'm trying to understand why I have to typehint the executor as java.util.concurrent.ExecutorService
and the function as a Callable
? What's the strategy used? i.e. is typehinting Callable
not enough?
it depends, if the compiler can figure out that you are invoking the method on an Executor service, type hinting Callable is enough
if you use interop to construct an ExecutorService and bind it to a local and use that, the compiler can figure it out, if you create it as a global (via def) then it can't, but you can type hint the var if you want
what's really weird is we were trying the same JVM version inside docker and outside docker and we got different results w/ the same code
the executor issue is tricky because the class of the thing you are passing in, introduces more ambiguity instead of narrowing the scope
I think it is a little odd that you would get differences with just inside and outside of docker, but I am perfectly happy to hand wave that away as you also introducing some other difference
yeah it's really weird, we've gotten inconsistencies in other ways as well (trying tests in this order):
- ran our test using lein test (on 2.7.2) and the right version of .submit
was used
- ran our test using lein test (on 2.8.1) and the the wrong version of .submit
was used
- ran our test using lein test (on 2.7.2) and the the wrong version of .submit
was used <-- freaky
the important thing would be the build of the jvm (version and os) and the clojure version (which lein version might effect)
e.g. if you are locally running on the jvm on osx, and comparing it to the jvm on linux in docker, many (not often noticeable) things will be different
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Reflector.java#L47