beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
kennytilton 2020-10-21T03:48:21.246400Z

“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.

👍 1
kennytilton 2020-10-21T03:52:34.246600Z

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.

👍 1
kennytilton 2020-10-21T03:53:41.246800Z

“I am gonna have to be much more disciplined when writing Clojure code” Yer doin’ it wrong. 🙂

👍 1
seancorfield 2020-10-21T04:27:05.247Z

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

👍 1
Jim Newton 2020-10-21T11:36:23.250400Z

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?

kennytilton 2020-10-24T18:07:05.456900Z

@jimka.issy (cl-format nil "{a^,}" nums) 🙂

Jim Newton 2020-10-25T09:50:05.473900Z

@hiskennyness😎

Jim Newton 2020-10-25T09:50:46.474300Z

i've never made myself learn the looping options of format but I love it when i see it in action

🍺 1
kennytilton 2020-10-25T13:46:18.484100Z

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.

Jim Newton 2020-10-26T08:16:24.000300Z

I love/hate CL:FORMAT the same goes for CL:LOOP

Jim Newton 2020-10-26T08:18:42.000500Z

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.

kennytilton 2020-12-27T11:46:06.011800Z

I eschewed LOOP for years. It is brilliant. Quirky, but hey, it's a DSL for iteration, worth the time. Give it a month?

walterl 2020-10-21T11:40:05.250700Z

interpose

Jim Newton 2020-10-21T11:40:06.251Z

I found it, it's called join

walterl 2020-10-21T11:40:22.251100Z

Oh, nm 😛

Jim Newton 2020-10-21T11:40:58.251300Z

interpose is interesting as a generalisation of join

simongray 2020-10-21T11:46:34.251900Z

https://clojuredocs.org/clojure.string/join

souenzzo 2020-10-21T12:11:30.252100Z

Why not just pr-str? It will generate [1, 2, 3, 4]

Jim Newton 2020-10-21T12:13:59.252300Z

with spaces? I don't need the spaces.

Jorge Tovar 2020-10-21T14:15:41.254300Z

https://dev.to/jorgetovar621/clojure-101-fep 🙂

Nassin 2020-10-21T16:55:50.257400Z

what's wrong here? ((symbol (first '("java.util.Date."))))

2020-10-21T16:57:19.257800Z

what do you expect to happen when you call a symbol with no args?

2020-10-21T16:57:38.258400Z

it's eval that turns the symbol into the constructor, but you aren't using eval here

dpsutton 2020-10-21T16:58:12.259Z

(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"

Nassin 2020-10-21T17:03:07.259500Z

I see

Nassin 2020-10-21T17:05:18.262100Z

why does ('a 10) work?

2020-10-21T17:14:05.269800Z

because symbols can be called, they look themselves up in their argument

2020-10-21T17:14:39.271100Z

user=> ('a '{a 10 b 20})
10

2020-10-21T17:16:09.274100Z

even better

user=> ('java.util.Date. '{java.util.Date. 42})
42

Nassin 2020-10-21T17:16:27.275100Z

oh right, like keywords

2020-10-21T17:16:30.275300Z

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.

Nassin 2020-10-21T17:18:06.276700Z

@andy.fingerhut to enable nil punning?

2020-10-21T17:18:44.277700Z

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.

2020-10-21T17:19:39.279200Z

the typical answer in things like this is that the extra type check makes for less hotspot improvement

Andrea Imparato 2020-10-21T17:20:01.280400Z

hello! beginner question, is there a macro i can use to transform every binding in a let into defs?

2020-10-21T17:20:30.281500Z

Sure, the JVM JIT compilers are quite limited in the code sizes of methods that they can inline.

2020-10-21T17:21:22.282800Z

@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.

2020-10-21T17:21:42.283400Z

What leads you to want to do so, out of curiosity?

2020-10-21T17:22:43.284600Z

@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 globally

2020-10-21T17:23:08.285200Z

if you are doing this for any reason other than debugging, I strongly suggest not doing so, and explicitly making def at the top level

2020-10-21T17:23:36.285700Z

it makes code easier to understand, debug, and extend when the bindings are explicit and in expected places

2020-10-21T17:24:04.286200Z

for debugging, combining locals as defined above with tap> is a great combo

👍 1
Nassin 2020-10-21T17:24:39.286900Z

so to my original question, how would I eval java.util.Date. in that example?

2020-10-21T17:25:11.287500Z

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)

2020-10-21T17:26:01.288700Z

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.

2020-10-21T17:26:06.288900Z

better to restructure so that you can eg. use a lambda #(java.util.Date.) which can be used as a proper value

Andrea Imparato 2020-10-21T17:26:24.289200Z

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)

2020-10-21T17:26:38.289700Z

if you are constructing arbitrary classes, that's another thing that you might want to reconsider

Andrea Imparato 2020-10-21T17:26:51.289800Z

if i want to evaluate (g a) i need to have a defined

Andrea Imparato 2020-10-21T17:28:21.290300Z

I’ll give it a try! thx!

Nassin 2020-10-21T17:29:07.290900Z

thanks for the pointers

Cameron 2020-10-21T17:35:05.291600Z

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.

2020-10-21T17:37:08.292500Z

@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

Cameron 2020-10-21T18:11:13.299700Z

As long as its clear I'm not saying otherwise

Cameron 2020-10-21T18:18:18.301900Z

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)

2020-10-21T18:22:11.303400Z

@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

2020-10-21T18:26:41.307Z

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

Cameron 2020-10-21T18:26:42.307100Z

Saying 'java function' is not meaning to make any implication that those functions themselves can be divorced from their class

2020-10-21T18:27:14.308400Z

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

2020-10-21T18:27:34.308900Z

and nowadays we have java.util.Function as well (doing something similar to what IFn does...)

2020-10-21T19:49:03.316700Z

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 ?

2020-10-21T19:50:00.317200Z

With those settings, the module drop down list is empty

2020-10-21T19:50:51.318Z

There is a #reveal, which is probably a directer way to get help 🙂

2020-10-21T19:50:58.318200Z

oh thanks!

2020-10-21T19:51:18.318400Z

that or #cursive

2020-10-21T19:53:37.318700Z

man, clojure tooling is so confusing for beginners!

Frederik 2020-10-21T20:40:50.321300Z

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?

Frederik 2020-10-21T20:44:12.323400Z

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.

alexmiller 2020-10-21T20:46:42.324100Z

reduce does not return a lazy seq

alexmiller 2020-10-21T20:48:35.325300Z

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

alexmiller 2020-10-21T20:49:41.326300Z

or use loop and exit without recurring

alexmiller 2020-10-21T20:49:48.326500Z

(in general, if you care about chunking, you shouldn't be using lazy seqs)

Frederik 2020-10-21T20:52:45.327200Z

Wrong assumption about the reduce, thanks for pointing that out! Putting it all together, think I'll just resort to the loop-recur option.