“being a dynamic typed language, it’s harder to refactor after” How so @bday2099? This sounds like an experience report, not a surmise. Could it be that, growing up on static typing, your code ends up somehow reliant on static typing, even when it is not available? I have certainly coded in statically typed languages and I get “if it compiles it is prolly right” as an excellent crutch, but perhaps that crutch inhibits development of the ability to design at a deeper clarity where dynamic typing presents nothing but wins.
As for “corrupt the REPL state”, I just do not rely on REPL state, nor do I program “in the REPL”. AS soon as my code gets past (+ 2 2) I have a test function that, yes, gets evaluated ad hoc “in the repl”, but the test function starts from scratch each time. No long-lived state to keep straight.
“I am gonna have to be much more disciplined when writing Clojure code” Yer doin’ it wrong. 🙂
Yeah, these seem like weird questions to me... I've been doing primarily Clojure for a decade now in production. Dependency conflict just isn't a thing: Clojure folks value stability/backward-compatibility; when I have problems, it's nearly always a Java library that isn't even paying lip service to SemVer (which is broken anyway). No idea why you find refactoring in Clojure harder: I find that Clojure is great for allowing a design to evolve, starting in REPL experiments and then expanding in terms of provide more/require less. I almost never corrupt my REPL state: I eval every source file change as I make it (and I never type into the REPL); I occasionally remove a ns because I want to change aliases or something but I have REPLs running for a week or more with no problem. As for Graal, I neither know nor care: I write backend software that runs for a long time so the JVM is perfectly optimized for that. @bday2099
what is the name of the clojure function which concatenates the elements of a sequence in some fashion but interposes an optional delimiter such as converting [1 3 2 4]
to "1,3,2,4"
? Basically how should I print the elements with comma between adjacent elements, but no comma at beginning nor end?
@jimka.issy (cl-format nil "{a^,}" nums) 🙂
i've never made myself learn the looping options of format
but I love it when i see it in action
I once did a mildly hairy cl-format
for production code but before making the PR thought I should rewrite for the benefit of the Klojure Kids, one of whom had already said he did not know it existed (but seemed enthusiastic). The rewrite was monstrous, so I left it in: better they should learn cl-format
and be empowered forever.
I love/hate CL:FORMAT
the same goes for CL:LOOP
one nice thing that motivates me to use clojure's cl-format
is the fact that ~a
expands lazy sequences. I hate getting the occasional error message containing the non-content of the lazy sequence which my code wasn't expecting. 😞 using cl-format
for all error messages eliminates this risk.
I eschewed LOOP for years. It is brilliant. Quirky, but hey, it's a DSL for iteration, worth the time. Give it a month?
interpose
I found it, it's called join
Oh, nm 😛
interpose is interesting as a generalisation of join
Why not just pr-str
? It will generate [1, 2, 3, 4]
with spaces? I don't need the spaces.
what's wrong here? ((symbol (first '("java.util.Date."))))
what do you expect to happen when you call a symbol with no args?
it's eval that turns the symbol into the constructor, but you aren't using eval here
(symbol (first '("java.util.Date.")))
-> the symbol java.util.Date
. so a minimal example of what you are doing here is ('a)
which results in the error "Wrong number of args (0) passed to: clojure.lang.Symbol"
I see
why does ('a 10)
work?
because symbols can be called, they look themselves up in their argument
user=> ('a '{a 10 b 20})
10
even better
user=> ('java.util.Date. '{java.util.Date. 42})
42
oh right, like keywords
If your question is: Why doesn't that throw an exception, because 10
is not a collection, then the answer is that those expressions, as well as the get
function, have always done so (i.e. have always returned nil in that situation rather than throwing an exception), and hopefully an FAQ answer written in the near future will have the answer to why it was designed that way. It is surprising to many people when they first encounter it.
@andy.fingerhut to enable nil punning?
That might be it. That would explain why ('a nil)
doesn't throw an exception, but not necessarily why ('a 10)
doesn't throw an exception.
the typical answer in things like this is that the extra type check makes for less hotspot improvement
hello! beginner question, is there a macro i can use to transform every binding in a let into defs?
Sure, the JVM JIT compilers are quite limited in the code sizes of methods that they can inline.
@imparato.andrea Nothing built into Clojure. I don't know of a 3rd party library that can do so, but my knowledge there isn't complete.
What leads you to want to do so, out of curiosity?
@imparato.andrea for a similar result (but not exactly what you asked for):
(ins)user=> (defmacro locals [] (into {} (map (juxt keyword identity) (keys &env))))
#'user/locals
(ins)user=> (let [a 0 b 1] (locals))
{:a 0, :b 1}
then you can add def to make the map visible globallyif you are doing this for any reason other than debugging, I strongly suggest not doing so, and explicitly making def at the top level
it makes code easier to understand, debug, and extend when the bindings are explicit and in expected places
for debugging, combining locals
as defined above with tap>
is a great combo
so to my original question, how would I eval java.util.Date.
in that example?
eval
exists, but it's generally better to avoid it (it's very expensive and can be a security issue to have it in an app)
There is a Java reflection API that you can pass strings to, and get back objects representing constructors, methods, fields, etc., and other methods that let you call such a constructor object, or method object.
better to restructure so that you can eg. use a lambda #(java.util.Date.)
which can be used as a proper value
sometimes when i use the repl to debug i want to save the bindings in a let “automatically” so when i evaluate some code inside the let I have them. For example:
(let [a (f)
b (g a)]
a)
if you are constructing arbitrary classes, that's another thing that you might want to reconsider
if i want to evaluate (g a)
i need to have a
defined
I’ll give it a try! thx!
thanks for the pointers
Yea, the thing is normally with something like (+ 1 2)
, evaluating this means evaluating each argument, resulting in (#function[x] 1 2)
, and then trying to apply the first argument (which is what we want after evaluation; the actual function, not a symbol) to the rest.
But interop symbols like java.util.Date.
don't actually evaluate to the method in question (and in fact, should throw some error on evaluation), so its actually defined as a sort of edge case where when evaluating a list like (java.util.Date.)
, it will check to see if you're trying interop and then will just directly look up and use the proper java function right there (without using eval), rather than running the equivalent of (eval ..)
on the symbol first and applying whatever comes out.
@zdot101 they evaluate to invocation of a method, but on the jvm methods are not first class - the point is there's no "java function" to use, it's a property of an object, and you need to find and use that object
As long as its clear I'm not saying otherwise
Well, as I think on it and reread, there may be one detail I want to poke a bit and be sure we're on the same page (when I get back online I guess)
@zdot101 I'm being a stickler about "function" because a key design aspect of clojure is the IFn / function abstraction, and the fact that jvm methods are not first class (they belong to an object and must be escorted by the object that owns them at all times), clojure solves this by making a special "function object" with an "invoke" method
bringing it back to the initial example, #(java.util.Date.)
creates a new function object of no args, whose invoke method instantiates a new date
Saying 'java function' is not meaning to make any implication that those functions themselves can be divorced from their class
what I'm saying is that, especially in a #beginners channel, saying "function" for method is unhelpful - it erases a key distinction to understanding clojure
and nowadays we have java.util.Function as well (doing something similar to what IFn does...)
https://vlaaad.github.io/reveal/#cursive
I'm trying to understand this, can someone please help?
It says
> Create a “local repl” run configuration with “clojure.main” repl type, make it “Run with Deps” with remote-repl
alias, and in Parameters specify -m vlaaad.remote-repl :port 5555
.
When I set my REPL up like this:
If I choose clojure.main, it greys out run with deps and I get a Run Configuration Error ?
With those settings, the module drop down list is empty
There is a #reveal, which is probably a directer way to get help 🙂
oh thanks!
that or #cursive
man, clojure tooling is so confusing for beginners!
I want to use some typical lazy-sequence functions like take-while and reduce, but on short sequences ( < 32 ) where each element is computationally intensive. Is there a straight-forward way to avoid Clojure's chunking behaviour?
E.g. I want to use take-while
on the output of a reduce
and it's important that take-while stops exactly at the first element that returns negative, instead of automatically realizing the first 32 elements of the lazy sequence returned by reduce.
reduce does not return a lazy seq
if your goal is to reduce and stop during the reduce, you might want to consider either detecting and returning a reduced
value inside the reduce, or using transduce
with transducers and something like halt-when
or use loop
and exit without recurring
(in general, if you care about chunking, you shouldn't be using lazy seqs)
Wrong assumption about the reduce, thanks for pointing that out! Putting it all together, think I'll just resort to the loop-recur option.