This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-05-15
Channels
- # babashka (3)
- # beginners (28)
- # calva (8)
- # cider (16)
- # clj-on-windows (4)
- # clojure (69)
- # clojure-europe (29)
- # clojure-norway (42)
- # clojure-uk (4)
- # community-development (5)
- # conjure (3)
- # cursive (18)
- # datomic (68)
- # emacs (23)
- # events (1)
- # honeysql (7)
- # introduce-yourself (1)
- # jobs (1)
- # lsp (11)
- # music (1)
- # observability (3)
- # off-topic (35)
- # other-languages (33)
- # releases (1)
- # remote-jobs (2)
- # ring (18)
- # shadow-cljs (16)
- # timbre (5)
- # tools-deps (9)
I have a function get
in my namespace, and I get a warning get is already in clojure.core.get when I use it. clj-http.client also has a "get" function, and when I use that one ther is no warning. How comes?
by default you get all of the functions from clojure.core in your own namespaces. This lets you not have to refer to helpful functions like assoc
and others with ungainly prefixes. The consequence of this, though is that if one of your functions has the same name, when your namespace is evaluated, it will create the mapping for clojure.core/get, and then your own get. This warning is that "hey, you are clobbering the established. It's just a warning.
user=> (defn get [])
WARNING: get already refers to: #'clojure.core/get in namespace: user, being replaced by: #'user/get
#'user/get
A way to fix this is to just prevent creating the binding for the clojure.core functions you intend to shadow.
user=> (ns foo (:refer-clojure :exclude [get]))
nil
foo=> (defn get [])
#'foo/get
foo=>
for more info, check out (doc ns)
which includes this:
> If :refer-clojure is not used, a
> default (refer 'clojure.core) is used.
You can read (doc refer)
to see how that establishes mappings of the public vars into the current namespace
Ahhh they have the exclude get! https://github.com/dakrone/clj-http/blob/b8e494725258940b1707e0e1413b056e613cfc2d/src/clj_http/client.clj#L3C1-L4C1
Didnt get
it at first 🙂
Thanks guys!
And for completion, then they can still use core/get fully quallified: https://github.com/dakrone/clj-http/blob/b8e494725258940b1707e0e1413b056e613cfc2d/src/clj_http/client.clj#L80C5-L80C33
I want to do write a sign/verify function that works in both clj & cljs. I know of some javascript libraries that I can use for this, but I'm not sure what to use in jvm. it seems that this can be done directly with java.security, but there's also bouncy castle. What's the usual/standard approach here?
The library doesn't matter. If signing and verifying must work across platforms, you have to use the same algorithms. Given that you have already figured out what you have to do in CLJS, just repeat the same thing in CLJ.
yeah, you're right. I'm probably worrying about the wrong thing here
I'm introducing io.github.cognitect-labs/test-runner to a project. I've added a :test
alias as documented at https://github.com/cognitect-labs/test-runner?tab=readme-ov-file#configuration. When I run clj -X:test
I get the following error:
Syntax error compiling at (clojure/tools/namespace/find.clj:22:1).
No such var: parse/clj-read-opts
Full report at:
/var/folders/vs/_krz484j6k52q0gyd3zxpz5w0000gn/T/clojure-10978643298024136801.edn
Full report in 🧵.$ cat /var/folders/vs/_krz484j6k52q0gyd3zxpz5w0000gn/T/clojure-10978643298024136801.edn
{:clojure.main/message
"Syntax error compiling at (clojure/tools/namespace/find.clj:22:1).\nNo such var: parse/clj-read-opts\n",
:clojure.main/triage
{:clojure.error/phase :compile-syntax-check,
:clojure.error/line 22,
:clojure.error/column 1,
:clojure.error/source "find.clj",
:clojure.error/path "clojure/tools/namespace/find.clj",
:clojure.error/class java.lang.RuntimeException,
:clojure.error/cause "No such var: parse/clj-read-opts"},
:clojure.main/trace
{:via
[{:type clojure.lang.Compiler$CompilerException,
:message
"Syntax error compiling at (clojure/tools/namespace/find.clj:22:1).",
:data
{:clojure.error/phase :compile-syntax-check,
:clojure.error/line 22,
:clojure.error/column 1,
:clojure.error/source "clojure/tools/namespace/find.clj"},
:at [clojure.lang.Compiler analyze "Compiler.java" 6825]}
{:type java.lang.RuntimeException,
:message "No such var: parse/clj-read-opts",
:at [clojure.lang.Util runtimeException "Util.java" 221]}],
:trace
[[clojure.lang.Util runtimeException "Util.java" 221]
[clojure.lang.Compiler resolveIn "Compiler.java" 7405]
[clojure.lang.Compiler resolve "Compiler.java" 7375]
[clojure.lang.Compiler analyzeSymbol "Compiler.java" 7336]
[clojure.lang.Compiler analyze "Compiler.java" 6785]
[clojure.lang.Compiler analyze "Compiler.java" 6762]
[clojure.lang.Compiler$MapExpr parse "Compiler.java" 3116]
[clojure.lang.Compiler analyze "Compiler.java" 6814]
[clojure.lang.Compiler access$300 "Compiler.java" 38]
[clojure.lang.Compiler$DefExpr$Parser parse "Compiler.java" 596]
[clojure.lang.Compiler analyzeSeq "Compiler.java" 7124]
[clojure.lang.Compiler analyze "Compiler.java" 6806]
[clojure.lang.Compiler analyze "Compiler.java" 6762]
[clojure.lang.Compiler eval "Compiler.java" 7198]
[clojure.lang.Compiler load "Compiler.java" 7653]
[clojure.lang.RT loadResourceScript "RT.java" 381]
[clojure.lang.RT loadResourceScript "RT.java" 372]
[clojure.lang.RT load "RT.java" 459]
[clojure.lang.RT load "RT.java" 424]
[clojure.core$load$fn__6908 invoke "core.clj" 6161]
[clojure.core$load invokeStatic "core.clj" 6160]
[clojure.core$load doInvoke "core.clj" 6144]
[clojure.lang.RestFn invoke "RestFn.java" 408]
[clojure.core$load_one invokeStatic "core.clj" 5933]
[clojure.core$load_one invoke "core.clj" 5928]
[clojure.core$load_lib$fn__6850 invoke "core.clj" 5975]
[clojure.core$load_lib invokeStatic "core.clj" 5974]
[clojure.core$load_lib doInvoke "core.clj" 5953]
[clojure.lang.RestFn applyTo "RestFn.java" 142]
[clojure.core$apply invokeStatic "core.clj" 669]
[clojure.core$load_libs invokeStatic "core.clj" 6016]
[clojure.core$load_libs doInvoke "core.clj" 6000]
[clojure.lang.RestFn applyTo "RestFn.java" 137]
[clojure.core$apply invokeStatic "core.clj" 669]
[clojure.core$require invokeStatic "core.clj" 6038]
[clojure.core$require doInvoke "core.clj" 6038]
[clojure.lang.RestFn invoke "RestFn.java" 457]
[cognitect.test_runner$eval234$loading__6789__auto____235
invoke
"test_runner.clj"
1]
[cognitect.test_runner$eval234 invokeStatic "test_runner.clj" 1]
[cognitect.test_runner$eval234 invoke "test_runner.clj" 1]
[clojure.lang.Compiler eval "Compiler.java" 7194]
[clojure.lang.Compiler eval "Compiler.java" 7183]
[clojure.lang.Compiler load "Compiler.java" 7653]
[clojure.lang.RT loadResourceScript "RT.java" 381]
[clojure.lang.RT loadResourceScript "RT.java" 372]
[clojure.lang.RT load "RT.java" 459]
[clojure.lang.RT load "RT.java" 424]
[clojure.core$load$fn__6908 invoke "core.clj" 6161]
[clojure.core$load invokeStatic "core.clj" 6160]
[clojure.core$load doInvoke "core.clj" 6144]
[clojure.lang.RestFn invoke "RestFn.java" 408]
[clojure.core$load_one invokeStatic "core.clj" 5933]
[clojure.core$load_one invoke "core.clj" 5928]
[clojure.core$load_lib$fn__6850 invoke "core.clj" 5975]
[clojure.core$load_lib invokeStatic "core.clj" 5974]
[clojure.core$load_lib doInvoke "core.clj" 5953]
[clojure.lang.RestFn applyTo "RestFn.java" 142]
[clojure.core$apply invokeStatic "core.clj" 669]
[clojure.core$load_libs invokeStatic "core.clj" 6016]
[clojure.core$load_libs doInvoke "core.clj" 6000]
[clojure.lang.RestFn applyTo "RestFn.java" 137]
[clojure.core$apply invokeStatic "core.clj" 669]
[clojure.core$require invokeStatic "core.clj" 6038]
[clojure.core$require doInvoke "core.clj" 6038]
[clojure.lang.RestFn invoke "RestFn.java" 408]
[cognitect.test_runner.api$eval228$loading__6789__auto____229
invoke
"api.clj"
1]
[cognitect.test_runner.api$eval228 invokeStatic "api.clj" 1]
[cognitect.test_runner.api$eval228 invoke "api.clj" 1]
[clojure.lang.Compiler eval "Compiler.java" 7194]
[clojure.lang.Compiler eval "Compiler.java" 7183]
[clojure.lang.Compiler load "Compiler.java" 7653]
[clojure.lang.RT loadResourceScript "RT.java" 381]
[clojure.lang.RT loadResourceScript "RT.java" 372]
[clojure.lang.RT load "RT.java" 459]
[clojure.lang.RT load "RT.java" 424]
[clojure.core$load$fn__6908 invoke "core.clj" 6161]
[clojure.core$load invokeStatic "core.clj" 6160]
[clojure.core$load doInvoke "core.clj" 6144]
[clojure.lang.RestFn invoke "RestFn.java" 408]
[clojure.core$load_one invokeStatic "core.clj" 5933]
[clojure.core$load_one invoke "core.clj" 5928]
[clojure.core$load_lib$fn__6850 invoke "core.clj" 5975]
[clojure.core$load_lib invokeStatic "core.clj" 5974]
[clojure.core$load_lib doInvoke "core.clj" 5953]
[clojure.lang.RestFn applyTo "RestFn.java" 142]
[clojure.core$apply invokeStatic "core.clj" 669]
[clojure.core$load_libs invokeStatic "core.clj" 6016]
[clojure.core$load_libs doInvoke "core.clj" 6000]
[clojure.lang.RestFn applyTo "RestFn.java" 137]
[clojure.core$apply invokeStatic "core.clj" 669]
[clojure.core$require invokeStatic "core.clj" 6038]
[clojure.core$require doInvoke "core.clj" 6038]
[clojure.lang.RestFn invoke "RestFn.java" 408]
[clojure.run.exec$requiring_resolve_SINGLEQUOTE_
invokeStatic
"exec.clj"
36]
[clojure.run.exec$requiring_resolve_SINGLEQUOTE_
invoke
"exec.clj"
29]
[clojure.run.exec$exec$fn__165 invoke "exec.clj" 83]
[clojure.run.exec$exec invokeStatic "exec.clj" 82]
[clojure.run.exec$exec invoke "exec.clj" 78]
[clojure.run.exec$_main$fn__220 invoke "exec.clj" 228]
[clojure.run.exec$_main invokeStatic "exec.clj" 224]
[clojure.run.exec$_main doInvoke "exec.clj" 192]
[clojure.lang.RestFn invoke "RestFn.java" 397]
[clojure.lang.AFn applyToHelper "AFn.java" 152]
[clojure.lang.RestFn applyTo "RestFn.java" 132]
[clojure.lang.Var applyTo "Var.java" 705]
[clojure.core$apply invokeStatic "core.clj" 667]
[clojure.main$main_opt invokeStatic "main.clj" 514]
[clojure.main$main_opt invoke "main.clj" 510]
[clojure.main$main invokeStatic "main.clj" 664]
[clojure.main$main doInvoke "main.clj" 616]
[clojure.lang.RestFn applyTo "RestFn.java" 137]
[clojure.lang.Var applyTo "Var.java" 705]
[clojure.main main "main.java" 40]],
:cause "No such var: parse/clj-read-opts",
:phase :compile-syntax-check}}
$ clj -X:deps tree :aliases '[:test]'|grep namespace
. org.clojure/tools.namespace 1.3.0
(as in check that it is actually getting that file from the tools.namespace 1.3.0 jar and not something else)
clj -A:test
Clojure 1.11.1
user=> (require ')
nil
user=> ( "clojure/tools/namespace/parse.cljc")
#object[java.net.URL 0x33b082c5 "jar:file:/Users/martin/.m2/repository/org/clojure/tools.namespace/1.3.0/tools.namespace-1.3.0.jar!/clojure/tools/namespace/parse.cljc"]
(
also check this to rule out any AOT classes
Oh yeah, there's something funny there:
user=> ( "clojure/tools/namespace/parse__init.class")
#object[java.net.URL 0xcfbc8e8 "jar:file:/Users/martin/.m2/repository/something/something/0.3.0-SNAPSHOT/something-0.3.0-SNAPSHOT.jar!/clojure/tools/namespace/parse__init.class"]
(I've redacted the actual library name to protect the maybe-not-so-innocent.) This is an internal artifact published to priovate Maven repo, included as transitive dependency.By the way, I love the back to first principles approach you took to finding the cause. This is gold for learning and understanding!
Anybody tried https://github.com/google/j2cl/blob/b3ff9e233cef3e67e495476da14f13250a56c5e9/docs/getting-started-j2wasm.md with Clojure? It's a Java to WasmGC compiler.
seems like it would run into a similar issue to jvm clojure on android, you can compile the parts of clojure that are written in java to run on this other runtime, but the clojure compiler still emits jvm bytecode
Right, but you couldn't AOT to bytecode and then compile that to Wasm?
or does J2CL work on java source rather than jvm bytecode?
I assume graalvm will eventually be able to target Wasm, but who knows?
there was a guy maintaining a clojure on android project a long time ago, and at one point he had a patched version of clojure where it would write every generated class file to disk were he could run the tool that converted it to dalvik bytecode on it then load it, so he could run a clojure repl on android (at least at the time for dalvik it was jvm bytecode to dalvik bytecode not java source to dalvik bytecode)
you could run a decompiler on the class files to get java source then run the tool on them 😐
Except there is no Java expression of some Clojure bytecode (like local clearing)
you could write asm(just the subset of asm clojure uses) to emit wasm instead of jvm bytecode and use this to pivot the java code to wasm without having to rewrite it all
https://www.cs.tufts.edu/comp/150FP/archive/andrew-appel/bootstrapping.pdf might be a good read if you were going to undertake something like that
FWIW, I recently wrote some tooling to do clojurescript to wasm: https://github.com/manetu/lambda-sdk-clj
In this case it generates code specific to our lambda environment, though you could easily adapt it to general WASI
It leans heavily on the shoulders of giants, such as shadow-cljs and quickjs, but it does work if you want a clojure(script) to wasm experience
The magic is here: https://github.com/manetu/javascript-lambda-compiler
That's pretty cool @U13AR6ME1 how large are your artifacts? Would it benefit from a tree shaking step?
We use shadows, where available. Most of our lambda functions end up in the range of 1-3MB as WASM
correct, we use shadow to compile clojurescript -> esm, and then we have a fork of javy to compile ESM to WASM
Seeing this in the javy docs sounds pretty appetizing: "Javy can create very small Wasm modules in the 1 to 16 KB range with use of dynamic linking."
under the covers, the javy tooling compiles the ESM to a quickjs bytecode, and that is what ships in the WASM payload
Yeah, we dont try to use the javy dynamic stuff…it is interesting but it creates a coupling to the dynamic split we wanted to avoid
A usage report on wasm, from someone impling scheme on wasm, was that the future utility will depend on wasm tools ability to tree shake
For our use case, a multi-MB payload wasnt a problem. But I totally get that this can be an issue in other use cases
clojurescript does end up being one of the larger payloads, i think between including the quickjs runtime and the clojurescript substrate
we currently support go, typescript, and clojurescript…with go being the most compact and clojurescript being the largest
you can probably follow my clojurescript-sdk instructions to get the basic flow working…just substitute javy for our mjsc fork
> Do you know if javy has web workers? Javy uses the quickjs engine, and I believe quickjs does support web workers