Fork me on GitHub
#clojure
<
2018-06-29
>
Bravi00:06:51

hi everyone. is there a shorter version to this?

(let [[butlast-args last-arg] [(butlast args) (last args)]])

andrewzhurov18:07:30

I believe destructuring does not give such an ability But well, you can not use it here at all ad-hoc (butlast args) (last args) seems fine for me or (let [x (butlast args) y (last args)])

Bravi20:07:48

it does actually 🙂

Bravi20:07:40

I’m placing them in a vector and hence destructuring

johnj00:06:15

(let [[x y] [(butlast a) (last a]])

😀 4
Bravi00:06:08

that’s what i have 😄

johnj00:06:28

yeah, joking 😅

Bravi00:06:39

i thought there’d be a function specifically for doing that coz i’ve seen clojure do magic 😄

johnj00:06:12

you could write last-two

johnj00:06:07

ah nevermind, was confused about what butlast did

Bravi00:06:23

funny thing was i just typed butlast assuming there’d be a function like that

Bravi00:06:25

and there was..

johnj00:06:09

what data structure is args?

dpsutton00:06:12

you could play with split-at (dec (count coll)) but i'm not sure how you can make this more terse

noisesmith01:06:57

((juxt pop peek) (vector args))

noisesmith01:06:52

user=> ((juxt pop peek) [1 2 3 4 5])
[[1 2 3 4] 5]

johnj01:06:04

not fair, no local bindings but nice 😉

noisesmith01:06:15

what I'm saying is that (juxt pop peek) is more concise than split-at etc.

noisesmith01:06:17

user=> ((fn [& args] (let [[b l] ((juxt pop peek) (vec args))] {:b b :l l})) :a :b :c :d :e)
{:b [:a :b :c :d], :l :e}

seancorfield01:06:46

(and fairly efficient too, compared to last/`butlast`)

roklenarcic07:06:56

anyone using hugsql? Is there a way to import a file of definitions in another file? I have a bunch of snippets that I want to be used in each hugsql file I make.

curtis.summers13:06:48

HugSQL doesn't directly support an "include" of other SQL files, BUT you can concatenate two or more HugSQL files together as a string and use def-db-fns-from-string. Something like: (hugsql/def-db-fns-from-string (str (slurp "file1.sql") (slurp "file2.sql)))

kenny15:06:16

If I have a ns that looks like this:

(ns my-ns.core
  (:gen-class))

(defn -main
  [& args]
  (println "------")
  (prn "ARGS:" args)
  (println "------"))
And I run this from a REPL:
(binding [*compile-path* "target/classes"] 
  (compile 'my-ns.core))
=> my-ns.core
How do I run that -main function? I tried doing this but got Error: Could not find or load main class my-ns.core. Also tried replacing the - with _, no dice.
java -cp 'target/classes/*' my-ns.core

dominicm15:06:52

@kenny java -cp target/classes my_ns.core would be what I expect.

kenny15:06:10

Ah, the * was causing the issue. Now getting Exception in thread "main" java.lang.NoClassDefFoundError: clojure/lang/Var. Do I also need to include Clojure on the cp?

dominicm15:06:09

depends how much you AOT, I've noticed that when I AOT I am only getting the immediate dependencies of my main. I'm not sure if this is intentional behaviour though.

bronsa15:06:02

you won’t transitively compile clojure itself, as it’s already compiled

bronsa15:06:08

so clojure needs to be on the classpath

dominicm15:06:25

@bronsa I noticed that only things I did :require on from my main were AOT'd, is that correct?

4
kenny15:06:31

Is there some sort of cache for compile? I have noticed that sometimes things in my :require are included in *compile-path* and sometimes they are not.

dominicm15:06:48

@bronsa is this what leiningen works really hard to workaround. I recall some workaround it performs.

bronsa15:06:16

@kennny no compilation cache but clojure won’t re-compile a clj file if the class file is more recent

kenny15:06:06

Which class file is it using to determine that?

dominicm15:06:16

@bronsa hmm, this is not quite what I'm seeing though. main depends on A. A depends on B. Only main and A get AOT'd when I compile main.

bronsa15:06:59

see the non-thread discussion

bronsa15:06:05

I reckon it’s the same issue

bronsa15:06:19

(i.e. you have B already loaded when you compile main

dominicm15:06:45

I'd agree, expect that I'm doing clojure -e '(compile …)'

bronsa15:06:47

do you have a user.clj?

dominicm15:06:09

Only for the :dev alias, which I'm not loading.

bronsa15:06:14

or is B spec or a clojure namespace?

dominicm15:06:01

sorry, I don't understand the question.

bronsa15:06:13

is the namespace that’s not getting loaded a clojure. namespace?

dominicm15:06:49

Oh, I think I see what it is facepalm I'm using integrant, which has a load-namespaces which is dynamic. Sorry for the noise. It's good to know I'm doing the right thing though (otherwise)

bronsa15:06:29

@kenny the one you’re compiling

bronsa15:06:50

if you’re compiling my-ns.core that would be my_ns/core__init.class

kenny15:06:34

So if I delete the contents of target/classes it would recompile everything?

bronsa15:06:49

just the transitive deps of my-ns.core

bronsa15:06:57

provided they aren’t loaded already

kenny15:06:11

Still doesn't include core async in target/classes :thinking_face:

bronsa15:06:12

if they are already loaded they won’t be recompiled

bronsa15:06:55

@kenny it might be that you have already required core.async before compileing my-ns.core

kenny15:06:13

Ah, yes. I definitely did that.

bronsa15:06:23

that’s the issue

kenny15:06:55

That makes sense 🙂

bronsa15:06:09

you can replace your :requires with e.g. :require core.async :reload-all to force reloading

bronsa15:06:32

or you can use tools.namespace to force unloading of the transitive dependencies for my-ns.core

kenny15:06:37

Gotcha. Adding clojure to the cp doesn't seem to fix the issue.

java -cp target/classes:~/.m2/repository/org/clojure/clojure/1.9.0/clojure-1.9.0.jar my_ns.core
Exception in thread "main" java.lang.NoClassDefFoundError: clojure/lang/Var
        at my_ns.core.<clinit>(Unknown Source)
Caused by: java.lang.ClassNotFoundException: clojure.lang.Var
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        ... 1 more

kenny15:06:22

I assume order shouldn't matter for the cp args

dominicm15:06:24

@kenny ~ won't expand when squished like that.

bronsa15:06:34

use $HOME instead

👍 4
dominicm15:06:26

Or ${HOME} if you want to be super safe.

kenny15:06:43

I assume I need to do the same for Spec with Clojure 1.9?

bronsa15:06:16

any reason you’re not using clj+`deps.edn` btw?

Nick Cabral15:06:06

@metametadata your byplay library looks really interesting! Somewhat related to background job processing, I'm evaluating different scheduling libraries (scheduling as in "run this task 5 days from now"). Just wondering if you have any experience or preference with libraries like quartzite or monotony?

metametadata19:06:28

byplay is somewhat abandoned, plus it doesn't support scheduling, I can't recommend it 🙂 I recently briefly evaluated other solutions for work and would just go with Quartz or maybe a Clojure wrapper on top of it. It's mature, supports persistence and scheduling.

Nick Cabral01:06:23

That's what I was leaning towards, thanks for the input ☺️

👍 4
kenny15:06:00

Just trying to get a deeper understanding of how this works. Also, I wrote a clj uberjar task that does not work when dependencies on included and I want to figure out why.

bronsa15:06:27

:thumbsup:

kenny15:06:37

Any ideas here?

java -cp target/classes:$HOME/.m2/repository/org/clojure/clojure/1.9.0/clojure-1.9.0.jar:$HOME/.m2/repository/org/clojure/spec.alpha/0.1.143/spec.alpha-0.1.143.jar uberjar_sample.core
https://pastebin.com/8NmzsFLS

kenny15:06:47

Error was too long for slack ^

kenny15:06:07

Basically Caused by: java.lang.ClassNotFoundException: org.objectweb.asm.Type. Haven't seen that class before.

bronsa15:06:51

that’s a missing dependency from tools.analyzer

kenny15:06:14

I assume core.async is using that. Is there a reason that wasn't included when I AOT'ed my ns?

bronsa15:06:24

it’s a java library :)

kenny15:06:54

Ah. So that needs to be manually added to the CP as well?

dominicm15:06:58

@kenny if you want a convenient way to "dump out" the libs juxt/pack.alpha just added support for doing that in a particular branch. It's also good for uberjars, if you're looking for a library for that.

dpsutton15:06:19

I thought clojure had org.objectweb.asm.Type

dpsutton15:06:59

oh it does but it renames it i think

kenny15:06:06

@dominicm Might be helpful to take a look. Which branch?

bronsa15:06:39

@dpsutton tools.analyzer.jvm uses org.objectweb.asm, not clojure.asm

dominicm15:06:43

@kenny it's called "skinnyjar", latest commit is 800afc066907e31fe90ce4df4f519e6224116867

bronsa15:06:59

clojure bundles org.objectweb.asm but it renames it

bronsa15:06:25

the reason why t.a.jvm doesn’t use the bundled one is that up until 2 days ago clojure shipped an ancient version of ASM and we were using modern APIs that just didn’t exist in the version bundled with clojure

dpsutton15:06:54

ah. that's why ghadi bumped it.

bronsa15:06:19

the ASM version got bumped because the class version and minimum jvm requirement got bumped from 1.6 to 1.8 which means we can now start using modern bytecodes (indy) which the old version of ASM just didn’t support

bronsa15:06:20

+ there was a bug in the emission of certain static method invocations due to the old ASM not fully supporting 1.9 bytecode verification changes

seancorfield17:06:06

@kenny Why are you trying to manually compile Clojure code and run it with java? That seems like a very painful way to work.

kenny17:06:53

@seancorfield Oh it is 🙂 I wanted to better understand what was going on behind the scenes.

metacritical18:06:32

@kenny I think one way if you want to learn what is going on is to just read the source of ‘lein run’ or ‘lein test’ task. Instead of going through this painful procedure.

kenny18:06:57

That exercise provided me with exactly the information I needed 🙂

4
4
seancorfield20:06:15

@kenny Compiling Clojure is painful in all sorts of ways. We don't AOT anything at World Singles now. We still build (uber) JAR files for deployment tho' (from a mono-repo).

kenny20:06:22

@seancorfield Cool. And you run the uberjar with clojure.main instead?

seancorfield20:06:26

Yes. java -jar path/to/my.jar -m my.app.entry

seancorfield20:06:06

(we still highlight clojure.main as the entry point)

seancorfield20:06:20

It also has the benefit that if you want to explore the app interactively for any reason, you can run it without -m and get a REPL that has all the dependencies and source directly available.

8
jmckitrick21:06:06

I have a unit test with clojure.test that starts with instrument and ends with unstrument to mock out some function calls. However, it seems to sometimes call the underlying functions I’m mocking and accessing the database, which I’m trying to avoid. Any idea how to make sure there’s no race condition happening here?

hiredman21:06:37

combing instrument and with-redefs sounds like a bad idea

hiredman21:06:23

that being said, I doubt there is a race condition there, my guess is the race condition is you are spinning up threads to do something in your test, and don't ensure dynamic extent of the thread is the same as the dynamic extent of the test

jmckitrick21:06:38

I’m still figuring out the best way to get spec.test into our pipeline.

hiredman22:06:39

I suspect you have a bug there

hiredman22:06:49

in that you well set state to the string "third"

hiredman22:06:18

(swap! state update-in [:task-list] conj "third") will likely do what you meant

muld3r22:06:58

No, I'm adding the string "third" to the list ["first" "second"]. Let me try your approach.

hiredman22:06:38

oh, right, I didn't read the parens right

muld3r22:06:42

(swap! state update-in [:task-list] conj "third") this only replaces the vector

dpsutton22:06:34

common to see (fnil conj []) in the case the key isn't already present

dpsutton22:06:09

also no need for an update in if the path is one segment. update :task-list

hiredman22:06:16

Clojure 1.9.0
user=> (def state (atom {:task-list ["first" "second"]}))
#'user/state
user=> (swap! state update-in [:task-list] conj "third")
{:task-list ["first" "second" "third"]}
user=> @state
{:task-list ["first" "second" "third"]}
user=> 

hiredman22:06:32

not sure what you mean by "only replaces the vector"

muld3r22:06:17

My bad, sorry about that 😉 This works indeed. Thanks a lot!! Clojure is sometimes a bit overwhelming to find elegant solutions

hiredman22:06:46

update is a newer addition, that in my opinion was silly

muld3r22:06:14

In what way?

Alex Miller (Clojure team)22:06:42

I was on the fence but I use it all the time

hiredman22:06:03

like, we had update-in, it works fine, but someone decided to create a jira issue because they wanted a version that only worked for a single path segment, and then spend however many months to shepherd that change through and get it merged, and then it caused issues with different clojure libraries because it introduced a commonly used name in to clojure.core

hiredman22:06:08

what a waste of time

muld3r22:06:25

Ah well, but that's more of a political/project structural issue.

hiredman22:06:49

so now, everytime someone writes code that uses update-in and works just fine with a single segment, the first comment is someone going "but actually you should use update"

mikerod01:06:17

@hiredman assoc-in and update-in were slower I thought. update is perhaps a bit faster. Looking at impl now it isn’t a big difference though. Except update was implemented with more explicit arities

hiredman22:06:56

what an even bigger waste of time

dpsutton22:06:11

sulks shamefully

muld3r22:06:14

To me Clojure feels somewhat "hacky", like 'emacs lisp', coming from OO languages and having some little experience with Haskell and Scala. But I guess this is a more of an evolutionary approach.

hiredman22:06:21

I think it would be hard to reconcile the idea it is hacky with rhickey, but it is definitely coming from a very different place

hiredman22:06:29

if you haven't see "are we there yet?" from almost 10 years ago, it is still very good, and I think puts on display a lot of the thought that went in to clojure

muld3r22:06:40

Yeah, I've watched many talks he has given and my impression is that he is less likely inclined to the way academic groups would design a language. But I like that a lot, as for example Scala seems to artificial from time to time. And not to mention Java itself, which is very robust, but lacks innovation. Once again thanks for your help @hiredman!

muld3r22:06:25

Haha that's a good one! 😃 -> Java DEV are so Type A 😉

kevinludwig23:06:16

Im looking for a way to get the full path to leaf nodes of a map of maps, so for example if I have {:a 1 :b {:c {:d 2}}} it would return [[:a] [:b :c :d]]

kevinludwig23:06:57

e.g. the result would be vectors suitable to pass to get-in to retrieve any individual value from the original map

kevinludwig23:06:16

suggestions on approach appreciated, don't need full solution

hiredman23:06:22

people ask this a lot, I am not entirely sure why

hiredman23:06:28

user=> 
((fn map-paths [path m]
   (if (map? m)
     (for [[k v] m
           i (map-paths (conj path k) v)]
       i)
     [[path m]]))
 []
 {:a {:b 1
      :c [3]}
  :w {:x 1}})
([[:a :b] 1] [[:a :c] [3]] [[:w :x] 1])
user=> 

kevinludwig23:06:47

thanks, more than I expected to receive

kevinludwig23:06:51

and to answer your question, in this case I want to convert an object structure to a java properties list