This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-11-09
Channels
- # announcements (3)
- # asami (1)
- # babashka (19)
- # beginners (84)
- # calva (3)
- # cider (5)
- # clj-commons (22)
- # clj-kondo (29)
- # cljdoc (4)
- # cljs-dev (5)
- # clojure (65)
- # clojure-australia (1)
- # clojure-europe (44)
- # clojure-nl (2)
- # clojure-uk (2)
- # clojurescript (18)
- # code-reviews (12)
- # conjure (2)
- # core-async (12)
- # data-science (1)
- # datomic (47)
- # deps-new (1)
- # emacs (2)
- # events (4)
- # fulcro (35)
- # integrant (1)
- # jobs (5)
- # jobs-discuss (10)
- # london-clojurians (1)
- # lsp (13)
- # music (1)
- # nextjournal (1)
- # off-topic (11)
- # parinfer (3)
- # pathom (6)
- # polylith (11)
- # portal (41)
- # re-frame (4)
- # reagent (13)
- # reitit (8)
- # remote-jobs (3)
- # sci (18)
- # shadow-cljs (34)
- # spacemacs (3)
- # tools-build (12)
- # tools-deps (6)
- # vim (2)
- # xtdb (7)
:repositories ^:replace {"jcenter" {:url ""
:snapshots false
:releases {:checksum :fail :update :always}}
"maven" {:url " "
:releases {:checksum :fail :update :always}}
"clojars" {:url ""
:releases {:checksum :fail :update :always}}}
its not popping out in the docs and its an extra key so i don’t imagine anything is gonna complain if its not supported
Not used by deps
Is there a guide for running Clojure on a cluster? Say you have 20 machines fired up on EC2, all with ssh access and jvm + clojure installed. What is the standard way for running Clojure on these machines? (In Elixir / Erlang, one would setup distributed Erlang, and have them all join the same dist Erlang cluster).
One could argue that the JVM (and in some ways maybe Clojure) is not built with clustering as the primary goal (as Erlang and the OTP is). There is nothing wrong with the networking in the JVM, but it's not OTP, and the networking model is not as elegant as the one in erlang (with pattern matching etc). Clojure could do really cool things in clustering mode. There are some things built: One notable historical thing originally built in clojure is apache storm. http://storm.apache.org/ Another thing to checkout is probably OTP-like https://github.com/suprematic/otplike There is also some scope capture things that can migrate environments between processes, and a lot of tools just wait to be put into a clustering thing. I don't know if you've seen: https://www.clojure-toolbox.com/ but it lists at least some of the more canonical libraries for clojure.
i mean, depends what you need the clustering behavior for. You can set up clojure w/ akka and i’d imagine it would work the same as erlang
Would you expect those machines to communicate with each other in some way? how? You can always handle deployment and management with things like K8S where your final artifacts are docker images
This is interesting. I wonder how clustering mode would look like for Clojure if built using the concepts that we already have. I can imagine having distributed core.async
channels that have some way of managing their identity across JVMs.
Hi !
say my code contains a (def toot (SomeClass.))
would the jar contain a byte code representation of the SomeClass instance that was created during clojure compilation ? any help understanding this would be much appreciated
thanks ! how is it different than an expression doing x and returning a value (42 for exemple) ?
Not sure what you mean by "doing x", but e.g. with (def x (+ 1 2))
, the (+ 1 2)
part will also be executed at run time.
Maybe there are exceptions to that, but I'm not familiar with them.
The reference page on compilation may be interesting to you: https://clojure.org/reference/compilation The compiler generates an init class for the namespace which evaluates those top-level expressions at runtime, when you load the namespace.
ok so if I understand correctly, the evaluation happens before compilation and is only used to expand macros and such, and whatever expressions are used to initialize vars will be evaluated at runtime as one would expect, right ?
The (+ 1 2)
part is not evaluated. It's read and analyzed. If such an expression contains macros, they're expanded. And then the result is compiled.
I'm not trying to be annoying @U2FRKM4TW 😛 thanks for your patience,
(ns toot.core (:gen-class))
(def toto (do (println "hello") 42))
(defn -main "I don't do a whole lot." [] (println "Hello, World!"))
running lein uberjar on this prints the hello, the hello is also there when you run it as you'd expectWasn't suggesting that you're annoying. :) I'm not a native English speaker and my written speech can be more terse than needed. That's an interesting example. Perhaps I'm wrong then.
I see now that clojure.lang.Compiler/compile1
has this block:
Expr expr = analyze(C.EVAL, form);
objx.keywords = (IPersistentMap) KEYWORDS.deref();
objx.vars = (IPersistentMap) VARS.deref();
objx.constants = (PersistentVector) CONSTANTS.deref();
expr.emit(C.EXPRESSION, objx, gen);
expr.eval();
Notice that there's eval
at the very end there. No clue why.thanks ! maybe it's how the compiler catches errors
@U064X3EF3 Could you please help us understand the intent of the last line in the code block above? Why does compilation also need to evaluate something, while also ignoring the return value? I very vaguely remember cautionary tales about side effects at the top level of namespaces being problematic for compilation, but I can't recall the specifics and can't find anything related in the documentation.
if you (def toto (do (println "hello") 42))
at the top level in a namespace, that will be executed at load time. This happens both when you AOT a ns and when you require it. All def
's are side effecting forms because they change the current namespace, usually defining a function or whatever, but if you have arbitrary side effects that will happen both when you gen-class
and when you load the file. Does that make sense?
> that will be executed at load time But I'm talking about compile time. > All `def`'s are side effecting forms because they change the current namespace At run time that makes sense. But why would they need to be evaluated at compile time?
I think that loading is part of both compiling and requiring. Before the compiler can spit out any bytecode it will ensure that the ns loads, so it can do things like macro expansion, etc. Consider the case where we have a (def x (throw (Exception. "err")))
the code isn't going to load. I think without a type system to help decide what side effects need to be run in each phase, this is probably the best that can be done.
yeah, that's not a good explanation
"load" is the primary operation here which means to ensure that a namespace and its code is loaded in the classloader
require triggers a load (if needed), load may load either existing bytecode (aot compiled source) or source. in the case of the latter, compilation happens to make the bytecode. If we are also compiling (this is just a dynvar), then the bytecode is also written to disk.
I don't think this is directly related to the original question though
if the question is why eval - b/c that's how effects happen. in the case of a top-level def for example, you need to def the var or later top-level forms that use it can't be compiled
loading, while triggered by the load of a namespace (usually), is really a form-by-form operation where each form is compiled and evaluated in order.
compile time is not a thing separate from loading; it is a side effect of loading
> you need to def the var or later top-level forms that use it can't be compiled
But why would you need the value of a var, assuming there's no direct linking?
In other words, from the perspective of the compiler compiling some ns a
that uses b/thing
, would it make any difference if b
had (def thing (println "thing"))
as opposed to just (def thing)
?
How would the compiler know to magically do one thing but not the other?
Compiling is not a separate thing, it is a subset of loading
Loading is also evaluating
Hmm. It still doesn't sit right in my head so I probably don't have the right model of the whole process. But it's not that important, and eventually I'll probably end up compiling Clojure myself and experimenting a bit. Thanks!
the key to everything is that Clojure rotates around the evaluation of forms - the REPL is not just an interface, it is Clojure - read/eval, read/eval load is just evaluation of forms read from a file, one by one compilation is an implementation detail of eval
Alright, that makes sense. But what about explicit compilation done by calling compile
? Doesn't it make the compilation a thing in and of itself, not just an implementation detail?
I know that sounds like a separate thing but what I'm saying is that calling compile
merely means writing some of the intermediate implementation parts of load/evaluation to disk
"remember this stuff I compiled while evaluating and write it down"
which is a totally different idea than say, the Java compiler
Huh, alright, something clicks now. And it means that one can't possibly compile CLJ code in an environment where it can't be run (missing run time requirements, like files, env vars, etc), right?
well I'm not saying it's not possible but it would be different :)
thank you guys !
Execution error (ExceptionInfo) at clojure.tools.build.tasks.uber/explode (uber.clj:172).
Cannot write license/LICENSE from xml-apis/xml-apis as parent dir is a file from another lib. One of them must be excluded.
you have both a license
(or maybe LICENSE
) and a license/LICENSE
file in your exploded uber jars. license
can't be both a file and a directory at the same time, so you need to add an exclusion on one of them
See https://clojure.github.io/tools.build/clojure.tools.build.api.html#var-uber docs - :exclude ["license"]
for example
If i add exclude license it won’t accidentally ignore com/company/thing/license.clj
right?
that is a regex string
when i first debugged this issue it was helpful to run it from a repl and then go inspect the temp directory it builds up to create the jar. I don’t remember how much information was in the error message but it could be helpful to add some logging to which jar it was as well
xml-apis/xml-apis
is the lib the second file is found in
the lib the original file is from is no longer known at the point when the error occurs
correct. but being able to see which license it is was helpful for me. so having the temp dir still around made it easy to see “this is a license for X” and then being able to choose which i wanted to exclude rather than just excluding the second because some other library had already claimed it
this might be better in #tools-build btw
Is it possible to similarly access metadata in a function as in a macro?
for a macro i can use (meta &form)
I mean is it possible to do such a thing for a function?
^{:some-key :some-value}
(myfn)