This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-07-02
Channels
- # beginners (130)
- # calva (3)
- # cider (13)
- # circleci (1)
- # cljsrn (19)
- # clojure (106)
- # clojure-europe (10)
- # clojure-losangeles (1)
- # clojure-nl (9)
- # clojure-uk (33)
- # clojurescript (16)
- # code-reviews (24)
- # conjure (11)
- # cursive (41)
- # data-science (9)
- # datomic (63)
- # fulcro (19)
- # graphql (12)
- # helix (4)
- # kaocha (2)
- # leiningen (3)
- # malli (8)
- # meander (1)
- # off-topic (17)
- # re-frame (16)
- # reitit (12)
- # sci (32)
- # shadow-cljs (73)
- # spacemacs (31)
- # sql (38)
- # tools-deps (26)
- # xtdb (28)
ns refer... i'm not sure what you mean @nsaritzky... externs? please provide an example
(ins)user=> (doc ns-refers)
-------------------------
clojure.core/ns-refers
([ns])
Returns a map of the refer mappings for the namespace.
nil
I recently came across the var-set
function available for vars. What are the practical differences between var-set
and def
ing a var again?
@yokoyama.km I have never seen var-set
or var-get
in any code I've seen. They operate on a Var
-- so (var foo)
or #'foo
-- and that Var must already exist.
And it must be a thread-local binding apparently.
def
creates a global:
user=> (def foo)
#'user/foo
user=> (var-set #'foo 42)
Execution error (IllegalStateException) at user/eval152 (REPL:1).
Can't change/establish root binding of: foo with set
user=>
(just to show that var-set
can't be used like def
)
Yes, I saw a mention of this in Clojure Applied (pg. 68) as the set function of a Var, but I haven't see any examples of its usage so far
The doc states that "the var must be thread-locally bound", and the examples show its usage along with with-local-vars
Interesting. Ah, that is also very rarely used I think...
Yes, I've never seen vars used that way. Thank you, @seancorfield
OK, here's the use case I guess:
user=> (def ^:dynamic foo)
#'user/foo
user=> (binding [foo 42] (println foo) (var-set #'foo 13) (println foo))
42
13
nil
user=> foo
#object[clojure.lang.Var$Unbound 0x18fdb6cf "Unbound: #'user/foo"]
user=>
The var has to be dynamic, and you can only use var-set
in a context where it has a thread-local binding.
(thank you -- I've never had cause to figure that out in nearly a decade of using Clojure!)
Updated the REPL session above -- I had a stray foo
definition, so that's now a correct fresh REPL session.
I can't imagine when I would ever use this tho' @yokoyama.km
I used var-set
in some performance sensitive code where I was implementing some imperative pseudocode from a research paper, and it would have taken me many hours to change the algorithm into a different form: https://github.com/jafingerhut/cljol/blob/master/src/clj/cljol/ubergraph_extras.clj
I am not saying that is recommended way to write code from scratch, but it seemed appropriate in this case to me.
I believe it only uses var-set
on vars created via with-local-vars
IIRC
usually when people want these semantics, I see them using atom
in a let, but when the let isn't starting new threads, local vars and var-set do the same thing but faster
I wonder how it compares to volatile!
though
I think I remember seeing it used in clojure core or maybe the server ns. Maybe to establish root bindings for the print vars?
i'm misremembering apparently. i thought i remembered some thread-local stuff and a var-set recently. i try to read lots of code
@bones You'll need to compile it (using javac
for example) and then make sure the folder where the .class
file ends up is on your classpath when you start the REPL
@bones Yes, :paths
should includes the directory where the class file(s) can be found.
(I can't test that right because I don't have a Java compiler of the right version on my Windows box)
That’s all good, thanks for your help. If/when that file is stored in Github, do I then use the deps
key to locate and use it?
Thank you, @seancorfield, for investigating this further. Maybe with-local-vars
has the same effect (and does not require the var to be dynamic)? I'll try it out on repl later
@bones OK, fixed my local javac
:
seanc@DESKTOP-QU2UJ1N:~/clojure/bones$ cat example/Greet.java
package example;
public class Greet {
private String message;
public Greet(String n) {
message = "Hello, " + n + "!";
}
public String say() {
return message;
}
}
seanc@DESKTOP-QU2UJ1N:~/clojure/bones$ javac example/Greet.java
seanc@DESKTOP-QU2UJ1N:~/clojure/bones$ ls -l example/
total 4
-rw-r--r-- 1 seanc seanc 810 Jul 1 19:54 Greet.class
-rw-r--r-- 1 seanc seanc 172 Jul 1 19:54 Greet.java
seanc@DESKTOP-QU2UJ1N:~/clojure/bones$ clj -Sdeps '{:paths ["."]}'
Clojure 1.10.1
user=> (import 'example.Greet)
example.Greet
user=> (def x (Greet. "bones"))
#'user/x
user=> (.say x)
"Hello, bones!"
user=>
Note that the current directory is the "root" for finding example.Greet
as an example.
(hah, you wouldn't believe how many attempts it took me to get that Java code to compile! I haven't written Java for years!)
Ah okay, so because you refer to it as example/Greet
you can specify the current dir (`"."`) as the root.
Yes, because the Java class name is example.Greet
and it matches the directory structure -- like Clojure 🙂
You mean via a git dependency in deps.edn
? You can't "depend" on Java source. You need to arrange for it to be compiled before you can use it from Clojure.
Ah okay, so is it safe for me to think :deps
is for Clojure files and as for Java I’ll follow what you’ve exampled above? I also noticed you used import
as opposed to require
, is that also a Java specific thing?
Yes, you require
Clojure, you import
compiled classes.
seanc@DESKTOP-QU2UJ1N:~/clojure/bones$ rm example/Greet.class
seanc@DESKTOP-QU2UJ1N:~/clojure/bones$ ls -l example/
total 0
-rw-r--r-- 1 seanc seanc 172 Jul 1 19:54 Greet.java
seanc@DESKTOP-QU2UJ1N:~/clojure/bones$ clj -Sdeps '{:paths ["."]}'
Clojure 1.10.1
user=> (require '[clojure.java.shell :as sh])
nil
user=> (sh/sh "javac" "example/Greet.java")
{:exit 0, :out "", :err ""}
user=> (import 'example.Greet)
example.Greet
user=> (def x (Greet. "compiled!"))
#'user/x
user=> (.say x)
"Hello, compiled!!"
user=>
(not recommended -- just showing it is possible 🙂 )
And just to confirm -- above I rm
'd the .class
file before I started and
user=> (sh/sh "ls" "-l" "example/")
{:exit 0, :out "total 4\n-rw-r--r-- 1 seanc seanc 810 Jul 1 20:04 Greet.class\n-rw-r--r-- 1 seanc seanc 172 Jul 1 19:54 Greet.java\n", :err ""}
user=> (println (:out *1))
total 4
-rw-r--r-- 1 seanc seanc 810 Jul 1 20:04 Greet.class
-rw-r--r-- 1 seanc seanc 172 Jul 1 19:54 Greet.java
nil
user=>
so you can see the sh/sh
call to run javac
created it in the expected location.Hi, all. Can anyone give me a hint on how to set the content-type of an S3 object put using aws-api? I’m clutching at straws now…
(defn- put-object [s3 bucket-name prefix content-string content-type]
(aws/invoke s3 {:op :PutObject
:request {:Bucket bucket-name :Key prefix
:Body (.getBytes content-string)
:Headers {"content-type" content-type}}}))
… does nothing for the content-type, which the AWS console tells me is stubbornly “application/octet-stream”.{:op :PutObject
:request {:Bucket bucket-name
:Key k
:Body body
:ContentType content-type}}
You star - thanks very much. Just in time for my demo!
Hey team, noob q: I am watching Rich's "Maybe Not" talk -- Really liked where he was going with the idea of separating the schema with what should be required. Has there been some progress on his exploration? Would love to read / watch along if there's usergroup that's discussing it, or try it out if there's a beta
yes, work is ongoing on spec 2 in https://github.com/clojure/spec-alpha2
also see https://github.com/clojure/spec-alpha2/wiki/Schema-and-select and https://github.com/clojure/spec-alpha2/wiki/Differences-from-spec.alpha
kind of off on other things for the last few months but planning to get back to it soon
Has anyone had success using :parameters metadata in gen-class, I found this https://clojure.atlassian.net/browse/CLJ-970 after finding this example https://groups.google.com/forum/#!topic/clojure/Xv1pKATfP0c which I think suggests it is in place since 1.5, I'm on 1.10.0 My actual reason is a bit more complicated but the following was the simplest thing I could think to try
(gen-class
:name worker-operator.beans.IntList
:state state
:init init
:prefix "int-list-"
:main false
:extends ^{:parameters [java.lang.Integer]} java.util.ArrayList)
(defn int-list- [] [[] nil])
But it still seems to compile a class file like:
public class IntList extends ArrayList {
Which means the java .getGenericSuperclass
doesn't workthat is an open ticket, it has not been applied
so I wouldn't expect this to work
if you'd like to vote for it, see https://ask.clojure.org/index.php/1941/extend-implement-parameterized-types-generics
Ahh okay, thanks, I thought the 'affected versions' was when it had merged
Do you know if there is any alternative in the meantime or do I need to just write java?
Hello people! I am relatively new to Clojure (mostly playing it during my nights) and I am really liking it so far. To be fair, I ended up learning it because I was really interested in trying out Datomic, and Java/Scala was not really an option. Anyway — I am coming from TypeScript and Haskell (just to give some minimal background) and I do have some questions that I would love to get clarified: 1. I fail to understand if it's a good idea or not to use an effect system in Clojure. I see blog posts saying that in general you just should not. Coming from Haskell (where it's almost mandatory) and from TypeScript (where I decided to use one, with very good results: https://dev.to/vncz/forewords-and-domain-model-1p13) I'd be interested in understanding if people generally use one or are ok with thrown exceptions here and there. I have read around that "error is just data" (at least in Datomic). I would be super ok with it but I haven't been able to see/understand if this is the best practice or if somebody does it and somebody just throws exceptions. Any clarification would be super appreciated! 2. Coming from mostly JavaScript/Node — non blocking the thread is really the thing. I can see that CSP are a thing (curiously enough, I did a presentation about how using CSP in JavaScript is totally possible and doable) and just like effects, I fail to understand what is the best practice. Go with channels whenever there's an async operation or just block the thread since the JVM can allocate another one if required and handle another web request. Thanks a lot!
These are big questions. The problem with effects is that the underlying VM allows exceptions anywhere and clojure makes little attempt to hide or prevent access to the functionality of the VM. You can opt in and do it by convention, but that's not nearly the same as the promises a compiler makes.
clojure's core.async can be used for coordination, but is not a general purpose tool for not blocking. In particular, IO or CPU intensive operations inside go blocks (the one context where core.async provides non-blocking semantics) can starve the thread pool and lead to pathological behavior
core.async isn't a tool for non-blocking code, it's a coordination device that helps you code be clearer (and more likely correct) when some other aspect of your code requires asynchronous execution.
I think it's best to think of async as a form of design / tech debt in your architecture, and core.async helps you pay less interest on that debt
(I am suspecting my answers are too cynical now ... core.async can be used for making non blocking code, but is more often than not used wrong, because of incorrect assumptions about what it provides)
Thanks a lot for the clarification @noisesmith
On the point 1 — in Node/JavaScript there's essentially the same problem that is — everything can throw and there's no way to know ahead of the time if not by inspecting the source code. The same goes with Haskell (sounds weird, but it is). It's possible to deal with it though, even throwing code can be wrapped, with the typical example being try { return Either.right(operation())} catch(e) {return Either.left(e)}
; That does not discourage me.
I was more asking if there were other reasons for that 🙂
so that's true, but without a compile time type checker, we run into another variataion of the same problem: you can opt into using Either, but there's no guarantee that you've used it correctly or haven't forgotten a value was an Either vs. the raw contents
so once again, it's a convention, the compiler and vm won't help you except by blowing up when the path is hit at runtime
@noisesmith Ok let's put the situation in turn, what do you usually do? 🙂
I usually use immutable values and operations that don't throw. When I use code that is prone to throwing, or values that mutate, I try to segregate them and write a different kind of code, that's more verbose and makes subtle errors less likely.
I treat it as a problem of style rather than an enforcement of language features (I think Zach Tellman's book "Elements of Clojure" articulates this approach better than I could)
precisely, doing that as much as possible
@U050ECB92 I noticed! I'd be interested in understanding why 🙂
a core philosophical choice in clojure is that functionality isn't closed off, we are "consenting adults" and can use all underlying features of the vm
That's a good point effectively. Go use it if you want, nobody will prevent you that :thinking_face:
there's a trade off to the choice, of course
I think Scala does a good job of demonstrating some of the costs of the alternate choice, when you didn't author your own vm
Thanks a lot for he answers, they all make sense and I thought the same — just wanted a confirmation 🙂
the compiler breaks compatibility frequently, and is full of complex and hard to use constructs that try to enable strictness while also allowing access to the things users need in the vm
there are some things that are enforced by the compiler, that have no reified existence in the bytecode
which means that languages other than Scala can't easily integrate with all Scala code
In terms of dealing with exceptions not on the main thread, I remembered this blog post: https://stuartsierra.com/2015/05/27/clojure-uncaught-exceptions
any reason why
(future (doseq [thing things] ....))
this would only pull the first thing ?what are people using to manage static sites in clojure? looking for something extremely simple that supports hiccup with live reloading
@kbosompem try using @
to deref the future afterward - if it blows up you won't see the exception until you deref
and most likely if your doseq stops at the first item, there was a hidden error in the future that @
would expose
(ins)user=> (def f (future (/ 1 0) (println "OK")))
#'user/f
(ins)user=> (realized? f)
true
(ins)user=> @f
Execution error (ArithmeticException) at user/fn (REPL:1).
Divide by zero
@noisesmith thanks!
@kbosompem if your code doesn't rely on accessing the return value of the future, often the best thing is to add a try/catch, and log from there on failure.
remember that Error is not a subtype of Exception and will require a separate catch clause
Hey, can someone explain what's the rationale behind using naming like var#
instead of var
inside of macros?
it's not a naming thing -- it's a special feature of syntax-quote https://clojure.org/guides/weird_characters#gensym
The 'special characters' section of the Clojure cheat sheet mentions this, with a link to more info, along with other special syntax in Clojure, and most of the core functions and macros: http://jafingerhut.github.io/
usually (require 'some.ns :reload)
or (load-file "/absolute/path/to/some/file.clj")
depending on where the ns came from
most people just use editor shortcuts, but I think it's useful to know how to do this in a repl directly (if nothing else it means I can help people no matter what editor they use)
so that would ostensibly work in a repl, but doesn’t seem to in a command-line-launched/clj context
if it's not working, the namespace wasn't loaded from the location you thought it was, using "load-file" usually forces the right thing
or, the code that is using the definition from that ns captured the value in a var, and doesn't see updates to it
(common issue with web servers and handler functins, solved by passing #'app
to the server starting fn, rather than app
)
yeah, I’ve require
ed and aliased the namespace I’m trying to reload in my ns declaration. is that what you mean by capturing the value in a var and not seeing updates?
the exercise
function here sees changes when passed the var, but not when passed the functionitself
user=> (defn report [n] (println "this is execution" n))
#'user/report
user=> (defn exercise [f change-f]
(future (dotimes [i 5]
(f i)
(Thread/sleep 100)))
(Thread/sleep 200) (change-f))
#'user/exercise
user=> (exercise report
#(defn report [n]
(println "this is the new definition executing" n)))
this is execution 0
this is execution 1
this is execution 2
#'user/report
user=> this is execution 3
this is execution 4
user=> (exercise #'report
#(defn report [n]
(println "this is yet another new definition executing" n)))
this is the new definition executing 0
this is the new definition executing 1
this is the new definition executing 2
#'user/report
user=> this is yet another new definition executing 3
this is yet another new definition executing 4
future / sleep are used in order to demonstrate a change mid exeuction
of course never call defn inside another function like that, I'm just breaking rules in order to construct a clearer example
noob q:
If I require [clojure.string :as str]
I can still use the clojure.core/str
function in the same namespace.
How does this work?
(ns your.namespace.here
(:require [clojure.string :as str]))
(defn foo [name] (str "hi" name))
when the compiler sees an unqualified symbol str
it resolves to clojure.core/str, but if the compiler processes a namespaced symbol str/includes?
it looks to see if there is an alias defined for the namespace part of the symbol
Hey team, noob logging question. I am trying to set up logging for google cloud. To do that, I followed their tutorial, and saw that I needed to configure a logback.xml file, which includes an appender that routes the logs over to gcloud
https://github.com/stopachka/jt/blob/master/resources/logback-production.xml
One thing I notice:
1. If I actually called it logback.xml, in dev it would try to send the logs to gcloud, which would fail
So what I did:
I called it logback-production.xml
, and in my deploy, I run the following command
java -Dlogback.configurationFile='logback-production.xml' ... -cp jt.jar clojure.main -m jt.core