This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-04-26
Channels
- # announcements (10)
- # aws (5)
- # babashka (27)
- # beginners (175)
- # boot (1)
- # braveandtrue (2)
- # calva (11)
- # cider (13)
- # clj-kondo (91)
- # cljs-dev (54)
- # cljsrn (20)
- # clojure (164)
- # clojure-gamedev (3)
- # clojure-uk (43)
- # clojurescript (185)
- # core-async (6)
- # core-typed (1)
- # cursive (1)
- # docker (2)
- # emacs (2)
- # figwheel-main (78)
- # fulcro (69)
- # off-topic (20)
- # pathom (30)
- # planck (3)
- # re-frame (6)
- # reagent (70)
- # reitit (26)
- # ring (1)
- # shadow-cljs (120)
- # tools-deps (6)
- # vim (9)
Does that seem correct? If someone has Clojure installed and working, thus I can safely assume that JAVA_HOME is set as well ?
You are asking if it is possible to set up an environment that runs Clojure without setting the JAVA_HOME env variable? I would guess it is possible, at least. I do not know whether it is common to do so.
I don't really install java, just download the jdk and set my bashrc to add the path to the bins
Hum, not exactly. I'm asking if setting up Clojure requires you to setup the JAVA_HOME environment variable.
clojure uses java, and java has to be on the path. I think java_home is a fallback used by many programs if java isn't available?
through installation I mean
I am attempting to try out a fresh install of Clojure on an Ubuntu Linux system to confirm, but I am pretty sure I can follow the Clojure getting started steps, installing a JDK in a way that does not assign a value to the JAVA_HOME env variable, and the clj
and clojure
commands will still work. Will report back what I find.
interesting
This is the code for the clojure
command to find java:
# Find java executable
set +e
JAVA_CMD=$(type -p java)
set -e
if [[ ! -n "$JAVA_CMD" ]]; then
if [[ -n "$JAVA_HOME" ]] && [[ -x "$JAVA_HOME/bin/java" ]]; then
JAVA_CMD="$JAVA_HOME/bin/java"
else
>&2 echo "Couldn't find 'java'. Please set JAVA_HOME."
exit 1
fi
fi
So it seems it first tries $(type -p java) which I do not know what that does. And if that didn't work, it tries to look for JAVA_HOME, I think that's correct, my bash isn't great
yeah, if you didn't install java via some installer, where it sets the path so it appears callable, then it falls back to the java_home. I ran into this long ago with intellij tools
On an Ubuntu 18.04 system where I had never installed Clojure before, but did have OpenJDK 11 installed via an Ubuntu/Debian package, and there was no JAVA_HOME variable assigned a value in the environment, I can follow the Linux install instructions on Clojure's get started page, and both clojure
and clj
commands run without complaint.
The output of type -p java
on that system is /usr/bin/java
, which is where the java
executable is installed by the Ubuntu/Debian package
The bash command page describes what the type
built-in command does.
buried within that many-pages-long man page 🙂
Ok cool. I could probably use that logic too. Though it seems there is also a way using java itself: java -XshowSettings:properties -version
which prints a bunch of info, one of them being where java is installed
Ya, my install instructions will mention that. I need it in the path for other reasons already.
It is more common to expect JAVA_HOME to be defined and then figure out the path to java ($JAVA_HOME/bin/java).
But I am thinking about Windows more. For Linux and MacOS, java will be available in path already. In Windows, I often had to add java to path manually.
Ya, I think I remember that for Windows. I might add a fallback to JAVA_HOME in the future, but I think it wouldn't be too bad to ask to add java to the path. Especially in Emacs, you can add stuff to your path within your emacs config as well, so that might be a better way to go.
If you are assuming bash exists, then type
command exists, too.
Wndows without WSL tends to be enough different from macOS/Linux that it often needs it own way of doing things.
ya, I don't know how much I should bother for windows. Do people even use Emacs on windows 😛
I have before, but not recently. It exists.
If you do not polish/test/support Windows, you will not be alone 🙂
How can I debug "Error building classpath. Could not find artifact ... in central"? I'd like to know what the resolved dependency is that doesn't have its own dependency in central.
Anyone knows what is this error when using aws-cli?
(def s3 (aws/client {:api :s3}))
(aws/validate-requests s3 true)
(aws/invoke s3 {:op :ListBuckets})
=>
{:cognitect.anomalies/category :cognitect.anomalies/fault,
:cognitect.anomalies/message nil,
:cognitect.http-client/throwable
#error
{
:cause nil
:via
[{:type java.nio.channels.ClosedChannelException
:message nil
:at [.FillInterest onClose "FillInterest.java" 150]}]
:trace
[[.FillInterest onClose "FillInterest.java" 150]
[.AbstractEndPoint onClose "AbstractEndPoint.java" 354]
[.ChannelEndPoint onClose "ChannelEndPoint.java" 216]
[.AbstractEndPoint doOnClose "AbstractEndPoint.java" 225]
[.AbstractEndPoint close "AbstractEndPoint.java" 192]
[.AbstractEndPoint close "AbstractEndPoint.java" 175]
[.ssl.SslConnection$DecryptedEndPoint doClose "SslConnection.java" 1132]
[.AbstractEndPoint doOnClose "AbstractEndPoint.java" 220]
[.AbstractEndPoint close "AbstractEndPoint.java" 192]
[.ssl.SslConnection$DecryptedEndPoint onFillable "SslConnection.java" 425]
[.ssl.SslConnection onFillable "SslConnection.java" 305]
[.ssl.SslConnection$2 succeeded "SslConnection.java" 159]
[.FillInterest fillable "FillInterest.java" 103]
[.ChannelEndPoint$2 run "ChannelEndPoint.java" 118]
[org.eclipse.jetty.util.thread.strategy.EatWhatYouKill runTask "EatWhatYouKill.java" 336]
[org.eclipse.jetty.util.thread.strategy.EatWhatYouKill doProduce "EatWhatYouKill.java" 313]
[org.eclipse.jetty.util.thread.strategy.EatWhatYouKill tryProduce "EatWhatYouKill.java" 171]
[org.eclipse.jetty.util.thread.strategy.EatWhatYouKill run "EatWhatYouKill.java" 129]
[org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread run "ReservedThreadExecutor.java" 388]
[org.eclipse.jetty.util.thread.QueuedThreadPool runJob "QueuedThreadPool.java" 806]
[org.eclipse.jetty.util.thread.QueuedThreadPool$Runner run "QueuedThreadPool.java" 938]
[java.lang.Thread run "Thread.java" 834]]}}
I think it might be some kind of SSL issue? But I have no idea how to solve it. I can list the buckets using aws-cli
on the command line without issue
if I have a fully qualified symbol, how do I get a non-qualified symbol? I want to strip the namespace off.
You’re taking something that’s very specific and has well-defined semantics and turning it into something unspecific with loose semantics.
I’ve only ever seen people do this because they, they programmer, wanted things a certain way.
I think that's the most straightforward way too lol as Symbol
has
final String ns;
final String name;
so (unless I'm forgetting some hack) there's no mutating the ns (EDIT: not that anyone would want to anyways, I'm just diving into 'what's the most hypothetically direct you could get with this'), you end up needing to create a new symbol. The fastest hypothetical situation one could hope for is just to directly get name
, and directly call some sort of simple Symbol(string name)
constructor
Well, name in this case, name
indeed will call
public String getName(){
return name;
}
and (symbol ..)
will call
static public Symbol intern(String nsname){
int i = nsname.indexOf('/');
if(i == -1 || nsname.equals("/"))
return new Symbol(null, nsname);
else
return new Symbol(nsname.substring(0, i), nsname.substring(i + 1));
}
Granted, there's some extra checks there but there is no public constructor to directly give you Symbol(null,name)
I don't believe, so that's your most direct constructor for this. And technically, yeah, there's some extra checks in Clojure's symbol
and name
that could be bypassed if you really wanted to by using java interop (assuming you know the type of everything, as that's the extra checks Clojure does; both symbol
and name
do type checks first and dispatch on that type of their argument to create the symbol
or get the name
, respectively) but the idea is the same; getting that new symbol will be some combination of grabbing the name
, and passing it to a Symbol
constructor, as done here.
...I have no idea why I'd dive into this, as you already have your answer and this is a small thing ahahahah I apologize. This sort of thing just interests me, as I just like when I can establish the 'limits' on something, and use that to feel comfortable knowing 'well, it doesn't really get better than this, so no matter what happens I don't feel like I can improve this solution, I can rest knowing I'm done thinking about this "forever"' fwiw, i also looked at the Symbol.java file to see if there might not be some interop / obvious better way 🙂
You’re taking something that’s very specific and has well-defined semantics and turning it into something unspecific with loose semantics.
Hi, is it possible to have a catch all declaration in a compojure route?
Something like: (POST "/api/invoke/:rest-of-thing/" [rest-of-thing req] (invoke-post rest-of-thing req))
where rest-of-thing
can be any uri like foo/bar/baz
or /buz/3/5/id
?
Nevermind, I just found the wildcard function. Just adding a * to the route will behave like I want: /api/invoke/*
will match all routes that start with /api/invoke/
I’m testing a function that uses a core.async
channel. For the tests, I wrote a simple timeout-chan
function. Here is a simple version of its implementation:
(let [in-chan (a/chan)]
(a/go (a/<! (a/timeout 1000))
(a/close! in-chan)
(apply function-using-async in-chan))
Ultimately: keep the channel open long enough for me to pass things in and than close it.
The problem: If you pass n items to the channel, and want to be sure n items get through before the channel closes, the tests might pass sometimes and not other times
Q: how are people handling scenarios like this?relying on timeouts doesn’t seem what you want. what kind of process are you trying to test?
I have a consumer
function like
(defn consumer-fn [chan]
; take from chan
; increment counter
; transform val from chan and return it
)
My goal is to test that the increment counter step in the above is working as expectedyou shouldn’t need a timeout to check to if that’s working
for the test, you could use something like poll!
from a design perspective, it seems like consumer-fn
might be doing too many things
typically, you try to separate the “flow” of your program from the “logic” of your program
which makes things easier to test, but more importantly, makes your system easier to reason about and easier to change
specifically, I would consider having your consumer-fn
not take from a channel and then return a value
either take a value and return a value or take a channel and return a channel
preferably, taking a value and returning a value
> either take a value and return a value or take a channel and return a channel This is a good point, one which I am keen to look into.
I’m currently trying to understand poll!
a little better
I guess poll!
would make more sense if you’re taking a channel and returning a channel*
but since you’re returning a value, it might not be the right fit
if you want to put a certain number of items onto a channel, then onto-chan
might make sense. you pass it a coll, and once all of the items from the coll have been put on the channel it will close the channel.
For clarification, if I want the channel to close after n
items have been taken off the channel, would it be better to use to-chan
?
to-chan
and onto-chan
deal with putting items onto a channel. they won’t know about items being taken off of a channel
So in the case of https://clojuredocs.org/clojure.core.async/to-chan where it says that: > closing when exhausted What does “exhausted” mean in this scenario?
pretty sure that means if the sequence passed to to-chan
ends, it closes the channel
but the channel isn’t guaranteed to be closed, because you could potentially pass an infinite sequence to to-chan
. (eg. (to-chan (range))
)
if you pass a channel tht has no buffer into onto-chan, then the channel that is returned will only be closed once all of the items have been received
since the channel will be a synchronization point without a buffer
i guess it’s worth pointing out that there’s a subtle distinction between 1. putting n items on a channel and then closing the channel 2. closing a channel after n items have been taken off the channel as @U1XTUTPMY alludes to, the difference is most obvious when you have a channel without a buffer
I have seen this pattern used in the wild:
(let [v _] (async/alts!! [chan (async/timeout 1000)]))
(assert (nil? v))
(is (= 5 (count v)))
; ...other assertions
If I understand the premise here correctly, this is just keeping the channel open long enough to give our items time to pass through the channel :thinking_face:timeouts aren’t generally used for giving time for items to pass through a channel
they’re typically used if there is some time constraint that can’t be met
also, in a distributed system, you may send a request and the only way to detect failure might be to have a timeout.
> they’re typically used if there is some time constraint that can’t be met Do you have an example off hand of a scenario that required this? Just trying to better understand your suggestion :thinking_face:
this is the classic example of using timeout (and some of the other goodies)
(defn search [query]
(let [c (chan)
t (timeout 80)]
(go (>! c (<! (fastest query web1 web2))))
(go (>! c (<! (fastest query image1 image2))))
(go (>! c (<! (fastest query video1 video2))))
(go (loop [i 0
ret []]
(if (= i 3)
ret
(recur (inc i)
(conj ret (alt! [c t] ([v] v)))))))))
basically, the goal is to return a response in 80ms or less.
if all the results have returned, don’t wait for the timeout, just return, otherwise, wait up to 80ms and return any results that are available
ah, gotcha.
No, they are not compile time constants
(case Integer Keyword "keyword" Integer "integer")
=> Execution error (IllegalArgumentException) at spectrum.repl/eval27661 (form-init14549903441455335896.clj:514).
No matching clause: class java.lang.Integer
they are not. case
promises constant time dispatch and I don’t think that’s possible with classes
I don't think the reader can read a literal into a class that would make it equal, so probably not possible.
from the docs:
Unlike cond and condp, case does a constant-time dispatch, the
clauses are not considered sequentially
the expression gets evaluated, but the test constants do not
also from the docs:
The test-constants are not evaluated. They must be compile-time
literals, and need not be quoted. If the expression is equal to a
test-constant, the corresponding result-expr is returned
But there might also be a literal way to represent the class which I don't know off. Basically the evaluated result of expression gets compared to the read value of the clauses
maybe. you might have to do (.getName Integer)
, but you’re probably better off using something other than case
at that point
like a map
(get {Keyword "keyword" Integer "integer"} Integer)
Tagged literals are a reader form, not a type
They are read into objects
I guess my question is, say I do a case on some custom object. Like (case (Person. "John") (#person "John" "John"))
But I have a tagged literal for creating object of type Person. Would this now work with case? Since my clause is read into a Person object and my expression returns a Person object, would both object now be compared for equality?
No this will not work
Do we know why? Is it that the reader literal doesn't happen before the case macro? Or is it because the object returned by the literal will then be passed to the macro in a printed form?
No, person objects are not compile time constants
They cannot be stored in bytecode
It compiles to tableswitch bytecode
So how is Symbol and Keyword handled? To they compile to strings in the byte code for the comparison?
There is a lot of code to implement case - it is a nontrivial transformation and involves both a macro doing about half the work and the compiler doing more
I don’t recall all of the details
In Clojure, you can’t refer to classes as primitives – they’re referred to through symbols.
Classes are not constants (or unique - they are per-classloader) so you can’t use them as cases
I usually get the name of the class and dispatch on that string
Yeah. But I assume this would often be faster using a protocol. (I have zero data to back that up.)
Yeah, depends exactly what you’re doing
Whats the equivalent of a "rest" let destructure for map destructuring?
For example, for list its simple:
(let [[x & rest] [:a :b :c]] (println rest))
This prints (:b :c)
as expected
so that: (let [{x :a & rest} {:a :a :b :b :c :c}] (println rest))
returns {:b :b :c :c}
What do you want back?
That’s not how it works
That’s not a thing
You can dissoc :a from the full map in a second binding
Hi! I have a weird compile error: > Syntax error (IllegalArgumentException) compiling . at (src/../run.clj:7:28). > Unable to resolve classname: clojure.core$double@4d1947e7 in this code
(Math/round (months-between-approx from to))
When I remove the call to Math/round
, it is OK. The fn is:
(defn ^double months-between-approx [^Instant i1 ^Instant i2] (/ .. 30.5))
Why? Is there a problem with the ^double
type hint? But it works until I try to round it.... Thank you!!!Move ^double
after the function name (so it's in front of the arglist).
Putting metadata ahead of the function name causes it to be evaluated (to the clojure.core/double
function) and then added as a :tag
I think. Putting it before the arglists will do what you want.
^ @holyjak
user=> (defn ^double foo [] 1.0)
#'user/foo
user=> (+ 1 (foo))
Syntax error (IllegalArgumentException) compiling . at (REPL:1:1).
Unable to resolve classname: clojure.core$double@5da7cee2
user=> (defn foo ^double [] 1.0)
#'user/foo
user=> (+ 1 (foo))
2.0
user=>
Thanks a lot! Frankly, I never remember where to put the return value tag. My reasoning was that if it was before the arglist, it would be metadata on the arglist, not on the function. I should have just checked the docs 😅
And metadata on the arglist is exactly where you want it 🙂
user=> (defn ^double foo [] 1.0)
#'user/foo
user=> (-> #'foo meta)
{:tag #object[clojure.core$double 0x187e2f02 "clojure.core$double@187e2f02"], :arglists ([]), :line 1, :column 1, :file "NO_SOURCE_PATH", :name foo, :ns #object[clojure.lang.Namespace 0x5b5babb "user"]}
user=> (defn foo ^double [] 1.0)
#'user/foo
user=> (-> #'foo meta)
{:arglists ([]), :line 3, :column 1, :file "NO_SOURCE_PATH", :name foo, :ns #object[clojure.lang.Namespace 0x5b5babb "user"]}
user=> (-> #'foo meta :arglists first meta)
{:tag double}
user=>
For a lot of things, it will work before the function name -- when the metadata is the same evaluated as unevaluated. And of course there are situations where you want the metadata on the function instead of the arglist.
Just found this: clojure bot for eval clojure code on slack. Maybe we can have this on our group? https://github.com/verma/clj-slackbot
No, sorry, the Admin team are not granting tokens/integrations for any additional programs.
The restrictions on the free plan mean that it would be very hard for us to grant integrations to some programs but then have to deny so many others.
(and, to be honest, most remote code bots are open to all sorts of abuse, including causing them to spam channels and generally be rather annoying)
And, hey, every Clojure developer already has at least one running REPL on hand to try out code, right?
haha yeah It wasn't like I wanted to have this on, but in case the admins didnt' know about this
Hah, trust me, over the years we've been running this, we've seen most everything 🙂