#clojure log - Aug 25 2015

The Joy of Clojure
Main Clojure site
Google Group
IRC
List of all logged dates

0:00 justin_smith: TEttinger: are you suggesting that different amounts of structural sharing would happen with different jvms?

0:01 TEttinger: I'm fairly certain that's currently the case for Sun's JVM on JDK 6 and strings versus OpenJDK 6

0:01 andyf: TEttinger: I'm actually not writing much code (yet). Turns out there is a "Java Object Layout" library that does most of the "peeking under the covers" work for me. I'm mainly writing a little bit of code to use that and measuring memory footprint of a few Clojure data structures.

0:02 If I get energetic enough, I may also write some code to generate graphs that can be layed out with GraphViz to show their structure.

0:02 TEttinger: justin_smith: I know there are a lot of references to ???.sun.??? packages when profiling string-array or even char[] heavy code

0:02 justin_smith: interesting

0:03 TEttinger: one of those is the implementation of string internally I think, and it may change for large and small strings (like arraymap being used for small {} maps in clojure)

0:04 andyf: One little fact I hadn't noticed before -- Every PersistentVector, no matter how few elements it has, allocates an array of 32 references, which are all null for vectors with < 32 items.

0:06 It probably eliminates some extra cases in the code or something, but seems like a waste if the common case is short vectors.

0:07 justin_smith: andyf: isn't that what ztellman's big optimization with tuples was about?

0:07 the one that wasn't able to merge in because of 1.7 changes iirc

0:11 andyf: justin_smith: That optimization would eliminate that chunk of otherwise unused memory, yes.

0:12 It was also expected to speed things up in other ways other than avoiding that extra memory, I thought.

0:14 Olajyd: Hi TEttinger

0:15 TEttinger: hey Olajyd!

0:16 Olajyd: uhmmm vey well thanks, and you?

0:16 *very

0:16 andyf: Oops. My mistake. I didn't realize until now that this null vector I mentioned was the same null vector shared by all short vectors. It isn't a unique new one for every short vector. So not really much a waste of memory at all.

0:17 Olajyd: TEttinger, I ran into a problem and thought I should Ping you :)

0:18 TEttinger: what's up?

0:19 so far we've covered... most of the weird edge cases in clojure in like the first week and a half. so this is a good start :)

0:20 if it isn't covered by the standard library, somehow the tasks that you have been given have been almost certain to find that problem, haha

0:22 talios: if I have a sequence [1 2] - whats the easiest way of splicing that with [:a :b] to return a map of {:a 1 :b 2} - nothing simple jumps out me?

0:24 justin_smith: ,(zipmap [:a :b] [1 2])

0:24 clojurebot: {:a 1, :b 2}

0:25 talios: hah - and I just hit zipmap :)

0:25 in the docs

0:25 Olajyd: TEttinger, haha, yea.. thanks :)

0:25 talios: I knew there was something I was mssing, and I was thinking zippers or zip-with :)

0:26 Olajyd: TEttinger, here’s the code on pastebin https://www.refheap.com/108697

0:26 justin_smith: ,(defn zippedy-do-da [coll] (zipmap '[zippedy do dah zippedy day my oh my what a wonderful day] coll)))

0:26 clojurebot: #'sandbox/zippedy-do-da

0:26 justin_smith: ,(zippedy-do-da (range))

0:26 clojurebot: {zippedy 3, do 1, dah 2, day 11, my 7, ...}

0:27 talios: :P

0:27 justin_smith: sorry, that was silly

0:28 TEttinger: Olajyd: hm, just so you know, if you try to read numbers prefixed with 0, they are treated not as decimal numbers (which allow 0-9 as digits), but octal (only 0-7, with "010" representing what would normally be 8)

0:28 ,010

0:28 clojurebot: 8

0:28 TEttinger: the examples are all fine, and if they stay as strings there's no issue

0:28 Olajyd: TEttinger, ok

0:29 TEttinger, I wanted to be able to change the index 0 of `prev-col-val`

0:30 talios: oh nREPL how I love thee. NOT.

0:31 whats worse than an uber long stacktrace? ONLY showing the first line of a stacktrace, that inside PersistentHashMap

0:31 Olajyd: TEttinger, so that I can make reference to it, the `prev-col-val` seem to keep track of the previous column value, that the way I thought of solving the problem though

0:31 talios: PersistentArrayMap actually

0:31 justin_smith: talios: you can do (.printStackTrace *e)

0:31 talios: *e always points to the last exception

0:32 talios: w00t - and thats solve it. stupid repl - I'd reworked some code, then re-ran from repl history - which assumed a different data structure :)

0:35 Olajyd: TEttinger, I dont knw if thats the way to go anyway, what do you think?

0:35 TEttinger: I think I have an... unusual and small solution

0:37 Olajyd: TEttinger, this is data immuability problem right?

0:38 TEttinger: ,(defn replicate-header-value [col data] (reductions (fn [a b] (if (empty? (nth b col)) (assoc b col (nth a col)) b)) data))

0:38 clojurebot: #'sandbox/replicate-header-value

0:38 TEttinger: ,(replicate-header-value 1 [["04" "2" "3"] ["04" "" "5"] ["5" "16" ""] ["07" "" "36"] ["07" "" "34"] ["07" "25" "34"]])

0:38 clojurebot: (["04" "2" "3"] ["04" "2" "5"] ["5" "16" ""] ["07" "16" "36"] ["07" "16" "34"] ...)

0:39 TEttinger: clojurebot cuts off output if the sequence is too long, but it looks right

0:39 ,(replicate-header-value 2 [["04" "2" "3"] ["04" "" "5"] ["5" "16" ""] ["07" "" "36"] ["07" "" "34"] ["07" "25" "34"]])

0:39 clojurebot: (["04" "2" "3"] ["04" "" "5"] ["5" "16" "5"] ["07" "" "36"] ["07" "" "34"] ...)

0:40 TEttinger: ,(replicate-header-value 2 [["5" "16" ""] ["07" "" "36"] ["07" "" "34"] ["07" "25" "34"]])

0:40 clojurebot: (["5" "16" ""] ["07" "" "36"] ["07" "" "34"] ["07" "25" "34"])

0:40 TEttinger: yep, if the header has an empty string it doesn't change it

0:40 Olajyd: ok

0:40 TEttinger: ,(replicate-header-value 1 [["5" "16" ""] ["07" "" "36"] ["07" "" "34"] ["07" "25" "34"]])

0:40 clojurebot: (["5" "16" ""] ["07" "16" "36"] ["07" "16" "34"] ["07" "25" "34"])

0:40 TEttinger: do you want me to explain it?

0:40 Olajyd: yes please :)

0:41 TEttinger: reductions is one of my favorite rare-ish clojure functions. when you encounter a problem that can be solved with reductions, you sometimes have much shorter code

0:42 so it acts almost exactly like reduce, but instead of returning only the final result of calling the given function on each pair, it instead returns each result it got along the way (and the first element is the same as the first element of the collection, I think)

0:42 Olajyd: oh nice, this is the first time I’m seeing reductions though, TEttinger,

0:42 TEttinger: it's an uncommon one. I have found it comes up not often, but often enough to be useful

0:43 the fn that I pass to it likely needs explaining.

0:44 (fn [a b] (if (empty? (nth b col)) (assoc b col (nth a col)) b)) ;; reductions, like reduce, takes a pair of args. a is the previous value that reductions generated (and it will be in the final result). b is the upcoming element from the collection we pass

0:45 Olajyd: ok great, thanks

0:45 TEttinger: it checks if the nth item in the upcoming element (which is b) at position col is empty. since "" can be treated like a seq, (empty? "") returns true, since it's an empty sequence of characters.

0:46 Olajyd: TEttinger, out of curiorsity, what was I doing wrong in the problem?

0:46 TEttinger: I honestly didn't check that closely since I was pretty sure there was a less complicated way

0:47 you're right, it's immutability related

0:47 (assoc prev-col-val 0 (get row col)) doesn't change prev-col-val, it returns a new copy

0:48 so that was just doing the modification and throwing it away right after

0:48 Olajyd: hmm, now I get it :)

0:48 TEttinger: you would likely want to go about that way using loop/recur, which can be complicated sometimes, or an atom, which is effectively mutable

0:49 loop and recur are preferred for a number of reasons, but an atom is fine while you're learning

0:50 oh and the last part of the function: (assoc b col (nth a col)) ;; this just takes the upcoming arg, changes the col with the empty string to the previous value's string in the same column

0:50 the " b" at the very end is the else block of the if

0:50 so it returns the upcoming arg unaltered if it isn't empty in the column

0:53 Olajyd: TEttinger, thanks :)

0:53 TEttinger: glad to help!

0:54 Olajyd: 8) , I’ve adjusted my time so that I can meet you online, :D

0:54 TEttinger: haha nice

0:55 yeah it seemed earlier than before

0:55 great!

0:56 Olajyd: Hopefully tomorrow I’ll ping you

0:57 ttt_fff: is anyone here from a haskell background? I used to love clojure, but after 2 years of haskell, I find prefix notation and ()'s very hard to get used to

0:58 TEttinger: ttt_fff, interesting. personally I find haskell hard to read when it uses $

0:58 otherwise it's rather clean

0:58 ttt_fff: i find the pattern matching notation / type sigs very concise

0:58 more so than any macros I can rig up with ()

0:58 jeaye: ttt_fff: I'm just the opposite.

0:58 Can't stand the haskell syntax, really love s-exprs

1:00 TEttinger: I kinda stopped caring about syntax a while ago

1:00 ttt_fff: i'm writing a new config langauge

1:00 and need to decie between haskell like vs scheme like

1:00 TEttinger: haskell's going to be harder to parse I imagine

1:00 arrdem: why are you writing your own parser...

1:00 TEttinger: have you looked at Io?

1:00 arrdem: just use datastructures

1:01 I'm sure there are several fine Haskell config file readers

1:01 no need to run off and invent a new language

1:01 TEttinger: you could even use something that "looks" like haskell but really just pattern matches/regex replaces to clojure/scheme data structures

4:09 gilliard: Given a fn, 'f', which takes a single number and returns a single number, I would like to find the value in (range 1 n) which produces the largest output when fed into f. What's a neat way to do that?

4:12 TEttinger: ,(max-key (mapv #(.nextInt (java.util.Random. %)) (range 1 100)))

4:12 clojurebot: #error {\n :cause "Wrong number of args (1) passed to: core/max-key"\n :via\n [{:type clojure.lang.ArityException\n :message "Wrong number of args (1) passed to: core/max-key"\n :at [clojure.lang.AFn throwArity "AFn.java" 429]}]\n :trace\n [[clojure.lang.AFn throwArity "AFn.java" 429]\n [clojure.lang.RestFn invoke "RestFn.java" 412]\n [sandbox$eval26 invokeStatic "NO_SOURCE_FILE" 0]\n [sand...

4:13 jeaye: gilliard: Maybe naive, but map f over the range, then sort, then take the first.

4:13 TEttinger: ,(doc max-key)

4:13 clojurebot: "([k x] [k x y] [k x y & more]); Returns the x for which (k x), a number, is greatest."

4:13 kungi: I am currently watching magnars Parens of the Dead videos. In there he uses "clj-autotest" in emacs which I can't find on ELPA. Any idea where this elisp file comes from?

4:14 TEttinger: ,(into (sorted-map) (map (fn [n] [n (.nextInt (java.util.Random. n))]) (range 1 100)))

4:14 clojurebot: {1 -1155869325, 2 -1154715079, 3 -1155099828, 4 -1157023572, 5 -1157408321, ...}

4:15 TEttinger: ah

4:15 ,(into (sorted-map-by val) (map (fn [n] [n (.nextInt (java.util.Random. n))]) (range 1 100)))

4:15 clojurebot: #error {\n :cause "Wrong number of args (2) passed to: core/val"\n :via\n [{:type clojure.lang.ArityException\n :message "Wrong number of args (2) passed to: core/val"\n :at [clojure.lang.AFn throwArity "AFn.java" 429]}]\n :trace\n [[clojure.lang.AFn throwArity "AFn.java" 429]\n [clojure.lang.AFn invoke "AFn.java" 36]\n [clojure.lang.AFunction compare "AFunction.java" 47]\n [clojure.lang.Pe...

4:15 TEttinger: ,(into (sorted-map-by second) (map (fn [n] [[n (.nextInt (java.util.Random. n))]]) (range 1 100)))

4:15 clojurebot: #error {\n :cause nil\n :via\n [{:type java.lang.UnsupportedOperationException\n :message nil\n :at [clojure.lang.APersistentVector key "APersistentVector.java" 452]}]\n :trace\n [[clojure.lang.APersistentVector key "APersistentVector.java" 452]\n [clojure.lang.APersistentVector getKey "APersistentVector.java" 131]\n [clojure.lang.APersistentMap cons "APersistentMap.java" 29]\n [clojure.lan...

4:15 TEttinger: agh

4:16 gilliard: jeaye: Yeah that was my idea but I'm hoping for something simpler...

4:17 magnars: kungi: It's a work in process. You can find all my Emacs settings in https://github.com/magnars/.emacs.d :)

4:17 jeaye: (first (sort > (map f (range 1 n)))) is simpler than everything shown above, I thinkg

4:17 oddcully: ,(apply max-key (fn [x] (* x x)) (range 5))

4:17 clojurebot: 4

4:18 magnars: kungi: so if you want to give it a shot, the code is here https://github.com/magnars/.emacs.d/blob/master/site-lisp/clj-autotest.el

4:19 gilliard: jeaye: That gives me the maximum value for (f n) but I want to know which n produces that.

4:19 jeaye: gilliard: My mistake

4:19 kungi: magnars: Thank you!

4:20 * gilliard looks at max-key

4:22 gilliard: Thanks oddcully

4:22 ,(doc max-key) ; basically restates my question :)

4:22 clojurebot: "([k x] [k x y] [k x y & more]); Returns the x for which (k x), a number, is greatest."

4:23 oddcully: (inc TEttinger)

4:23 lazybot: ⇒ 64

4:23 gilliard: ,(source max-key) ; is nice too

4:24 clojurebot: Source not found\n

4:25 TEttinger: ,(apply max-key #(.nextInt (java.util.Random. %)) (range 5))

4:25 clojurebot: 2

4:26 TEttinger: ,(apply max-key #(.nextInt (java.util.Random. %)) (range 500))

4:26 clojurebot: 402

4:26 TEttinger: nice

4:26 ,(.nextInt (java.util.Random. 402))

4:26 clojurebot: -1000815519

4:26 TEttinger: hm

4:26 gilliard: lol

4:26 TEttinger: that seems not right

4:26 ,(.nextInt (java.util.Random. 2))

4:26 clojurebot: -1154715079

4:26 TEttinger: ,(.nextInt (java.util.Random. 0))

4:26 clojurebot: -1155484576

4:27 hyPiRion: TEttinger: next int is just a random int based on the seed you gave it

4:27 TEttinger: are they all negative???

4:27 lazybot: TEttinger: Yes, 100% for sure.

4:27 hyPiRion: oh

4:27 TEttinger: I know

4:27 hyPiRion: ,(.nextInt (java.util.Random. -1155484576))

4:27 clojurebot: -1764305998

4:27 TEttinger: what on earth...

4:27 hyPiRion: ,(.nextInt (java.util.Random. -1073741824))

4:27 clojurebot: 664794208

4:27 hyPiRion: coincidence I guess.

4:28 TEttinger: ,(map #(.nextInt (java.util.Random. %)) (range 5))

4:28 clojurebot: (-1155484576 -1155869325 -1154715079 -1155099828 -1157023572)

4:28 TEttinger: yeah... that seems like a LCG problem

4:28 oddcully: quick, get the booky! TEttinger is on a run

4:28 hyPiRion: Looks like the first value isn't that non-random

4:29 TEttinger: ,(map #(.nextInt (java.util.Random. %)) (range 5))

4:29 clojurebot: (-1155484576 -1155869325 -1154715079 -1155099828 -1157023572)

4:29 TEttinger: it's seeded hyPiRion

4:30 what's weird is that it seems like for a large consecutive range of seeds, the first number is negative...

4:30 hyPiRion: TEttinger: What I meant was that the highest bits of the first value seems to be very similar

4:31 BorePlusPlus: If I have namespaces in format like this: migrate/step_01.clj, migrate/step_02.clj, migrate/step_03.clj and I would like to get a list of all functions called up from namespaces step-01, step-02 and step-03, is this something that is streaightforward to do?

4:31 hyPiRion: ,(map #(let [r (java.util.Random. %)] (.nextInt r) (.nextInt r)) (range 5)) ;; looks fine here

4:31 clojurebot: (-723955400 431529176 1260042744 -1879439976 -396984392)

4:31 TEttinger: ,(map #(.nextInt (java.util.Random. %)) (range 36rRANDOMNESS 36rRANDOMNESX))

4:31 clojurebot: (-559045358 -559430107 -558275860 -558660609 -548272389)

4:31 TEttinger: interesting

4:31 gilliard: yes, it looks like any two consecutive seeds produce pretty close nextInts

4:32 TEttinger: ,(map #(.nextInt (java.util.SplittableRandom. %)) (range 36rRANDOMNESS 36rRANDOMNESX))

4:32 clojurebot: #error {\n :cause "java.util.SplittableRandom"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.ClassNotFoundException: java.util.SplittableRandom, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6891]}\n {:type java.lang.ClassNotFoundException\n :message "java.util.SplittableRandom"\n :at [java.net.URLClassLoader$1 run...

4:33 gilliard: ,(map #(.nextInt (java.security.SecureRandom. (byte-array %))) (range 50))

4:33 clojurebot: (-956323137 -1820334814 -1691674753 533104038 1374720712 ...)

4:33 luxbock: magnars: is the command you use to insert () and slurp a built-in, your own custom fn or do you just press ( and slurp really quickly one after another?

4:33 TEttinger: &(map #(.nextInt (java.util.SplittableRandom. %)) (range 36rRANDOMNESS 36rRANDOMNESX))

4:33 lazybot: java.lang.ClassNotFoundException: java.util.SplittableRandom

4:34 magnars: luxbock: it's paredit-wrap-round, bound to M-( by default I think

4:35 luxbock: magnars: ah cool

4:35 TEttinger: woah what, neither bot uses java 8 now? https://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html

4:36 kungi: magnars: when are you releasing the next video for PotD? It inspired me to rewrite large parts of my Emacs config yesterday and really learn clj-refactor. :-)

4:36 TEttinger: huh, must not be used by lazybot at least. my lazybot gives (-522495519 1499783386 -58986586 574128689 1912616253)

4:37 oddcully: (frequencies (map #(compare (.nextInt (java.util.Random. %)) 0) (range (Integer/MAX_VALUE)))) ; {-1 1073739864, 1 1073743783}

4:37 magnars: kungi: hah, glad to hear that :) the next episode will be out on friday

4:37 kungi: magnars: \o/

4:39 TEttinger: (frequencies (map #(compare (.nextInt (java.util.Random. %)) 0) (range 0xffff)))

4:39 ,(frequencies (map #(compare (.nextInt (java.util.Random. %)) 0) (range 0xffff)))

4:39 clojurebot: {-1 33492, 1 32043}

4:40 TEttinger: a ha!

4:40 ,(frequencies (map #(compare (.nextInt (java.util.Random. %)) 0) (range 0xfff)))

4:40 clojurebot: {-1 4095}

4:40 TEttinger: up to 0xfff it only produces negative first numbers!

4:41 luxbock: magnars: what kind of keyboard are you using?

4:41 magnars: luxbock: Norwegian MBP

4:45 luxbock: magnars: I was coding exclusively on the MBP keyboard for a long time but I recently purchased the Atreus keyboard from technomancy and it's really nice

4:45 works great for Emacs

4:45 because it puts your thumbs to work

4:46 magnars: yeah, that looks pretty nice - and I'm not surprised that technomancy's keyboard is Emacs friendly :) but I'm spending 2+ hours commuting on a train every day, so portability trumps all

4:48 kungi: luxbock: I use a kinesis advantage keyboard which is also just great for emacs and typing in general.

5:02 crocket: Is it possible to use robert hooke on multimethods?

6:33 dxlr8r: hello, any recommendations on a socket server library for clojure? I just need basic functionality

6:44 notarobot_: dxlr8r: http://www.luminusweb.net/docs/websockets.md

6:46 dxlr8r: notarobot_: not websocket, regular socket server :)

6:58 notarobot_: dxlr8r: oops sorry

6:58 H4ns: dxlr8r: what are you looking for in a socket library, really?

7:03 dxlr8r: H4ns: implementing a socket in my application?

7:03 Olajyd: HI, oddcully

7:04 dxlr8r: found this in the end, https://github.com/bguthrie/async-sockets , looks ok :)

7:10 Olajyd: Hi, any advice on how to think about / model what seems inherently "stateful" in the clojure context? Is there a better way to manage "state" than passing around mutating refs? I feel like Im about to understand something bigger but am a little stuck, I have a sample code on pastebin https://www.refheap.com/108707, Can I find a way of keeping track of previous-col-val without mutating it? any suggestions? :)

7:11 updated link: https://www.refheap.com/108708

7:14 dstockton: Olajyd: no expert, but I think you want to look at something like loop/recur

7:14 Olajyd: :|

7:14 dxlr8r: was just going to suggest that :)

7:14 dstockton: and pass the previous-col-val to the next iteration

7:14 Olajyd: uhmm, I want to avoid using the loop/recur form

7:15 oddcully: Olajyd: isn't this just another view on the problem from earlier?

7:17 it it is: ,(reductions (fn [old new] (if (empty? new) old new)) ["a" "" "b" "" "" "c"])

7:18 Olajyd: yeaa, oddcully, I just want to understand it more

7:19 oddcully, maybe you could shed more lights on data immuatability :)

7:20 oddcully: my guess is, that this has nothing to do with mutable data

7:20 but your brain wants to write imperative code

7:22 like having a "def last" outside of the loop where you want to keep track of the last good value

7:22 with loop/recur or a reduce you just send the last good value just back into the loop

7:26 negaduck: hi! Are chans disposable? Is it ok to create massive number of chans and goes as a reaction to events or in a loop? Should I close chans? In this article: http://dimagog.github.io/blog/clojure/clojurescript/2013/07/12/making-http-requests-from-clojurescript-with-core.async/ -- in the GET function the author closes a chan. Is this necessary? Or this is just to make sure nobody puts anything on this chan?

7:32 pseudonymous: I'm feeling as if I miss something incredibly simple. But HoneySQL outputs something like ["<query>" "<arg1>" "<arg2"> "<arg3">] and I can't for the life of me figure out how to execute the damned thing. (sql/db-do-commands seems to expect a query where all the parameters are already inserted..?)

7:33 schmir: pseudonymous: (jdbc/query db ["<query"> ...])

7:33 pseudonymous: where jdbc is clojure.java.jdbc

7:33 pseudonymous: I tried that, though INSERT statements aren't allowed there.

7:34 schmir: jdbc/execute!

7:35 pseudonymous: schmir: O_O It works - praised be the machine god! Thank you.. Really :P I was doc'ing random functions in both honeysql's and clojure.java.jdbc's namespaces trying to find what it is I was supposed to use

7:36 schmir: Olajyd: IMHO you should forget about refs and atoms when starting with clojure development

7:36 pseudonymous: how about praised be schmir :)

7:36 oddcully: karma *nudgenudge*

7:37 Olajyd: schmir, hmmm

7:37 pseudonymous: schmir: You could quite possibly be one of the machine gods - if not, I'll at least petition them for your inclusion :)

7:37 schmir: pseudonymous: thanks :)

7:38 Olajyd: really. I'm developing a commercial clojure program and never used a ref

7:39 git grep atom |wc -l says 16, where I have above 10k lines of code

7:40 Olajyd: schmir, wow, so the problem is that although the use of `reductions` work for that problmem, I’m wondering what if the `rows` is a lazy-sequence?

7:40 *problem

7:41 schmir, does `reductions` work with a lazy-sequence?

7:43 schmir: Olajyd: yes, why shouldn't it work

7:44 oddcully: ,(take 10 (reductions (fn [old new] (if (empty? new) old new)) (cycle ["a" "" "b" "" "c"])))

7:45 clojurebot: ("a" "a" "b" "b" "c" ...)

7:46 Olajyd: so the thing is I’m using clojure with Apache-spark, and the apache-spark, data-structures are usually in lazy-sequences :|

7:46 justin_smith: reductions can take a lazy-sequence, and it returns one

7:59 gfredericks: ,(reductions (comp second list) 5 '(0 1 2 3 4))

7:59 clojurebot: (5 0 1 2 3 ...)

7:59 gfredericks: ,(reductions (comp second list) 0 ())

7:59 clojurebot: (0)

8:00 gfredericks: ,(reductions (comp second list) 1 *1)

8:00 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Var$Unbound>

8:06 Olajyd: can somebody explain (.toJavaRDD)?

8:07 justin_smith: it's a method being called on no object - guaranteed to be an error unless it's inside a doto or -> or ->> chain or similar

8:09 if it is inside a doto, ->, ->> etc. then it is a method being called on whatever object is inserted into the form at compile time by that macro

8:11 Olajyd: ok

8:12 Thanks justin_smith

8:21 justin_smith, I got another question

8:22 Is it possible to convert clojure.lang.LazySeq to toJavaRDD?

8:25 justin_smith: Olajyd: toJavaRDD is a method, not a class - what class does toJavaRDD belong to?

8:26 Olajyd: I just google it though, :)

8:27 but ultimately I want to convert the clojure.lang.LazySeq to type JavaRDD

8:28 tried this though (r (-> result (.toJavaRDD)))

8:28 justin_smith: that's equivalent to (r (.toJavaRDD result))

8:29 what is result?

8:29 a lazy-seq?

8:29 Olajyd: yes

8:30 justin_smith: that's not going to work, because in the world of the jvm methods belong to classes, and nobody defined a .toJavaRDD method on the clojure.lang.LazySeq class

8:30 Olajyd: Dont knw whether i’m making a mistake though :|

8:30 justin_smith: I don't know spark well enough to know how one constructs RDD objects

8:30 Olajyd: are you using spark directly? are you using a lib like flambo?

8:31 Olajyd: oh great that explains why I’m getting this `No matching field found: toJavaRDD for class clojure.lang.LazySeq` right?

8:31 justin_smith, exactly :)

8:31 justin_smith: yeah, it's trying to tell you exactly what I just tried to explain

8:31 Olajyd: I mentioned two options...

8:31 Olajyd: you farmiliar with flambo, justin_smith?

8:33 justin_smith: Olajyd: I saw sorenmacbeth give a couple talks about it, and I know it's a spark wrapper

8:33 I haven't used it though

8:34 Olajyd: great

8:36 justin_smith: Olajyd: if your project is to use spark, you might find it helpful to review the docs on interop with clojure http://clojure.org/java_interop

8:38 Olajyd: ok say u want to advice, I did some of the evaluation in clojure but i need to convert it back to type RDD for further stuff, what will u suggest?

8:40 justin_smith: I'd look for a method in the spark lib somewhere that makes an RDD instance out of a collection or array - it's easy to turn a lazy-seq into either of those

9:02 gilliard: (frequencies (map #(compare (.nextInt (java.util.Random. %)) 0) (range (Integer/MIN_VALUE) (Integer/MAX_VALUE)))) ; => {1 2147483647, -1 2147483648}

9:03 As I read that, it seems impossible to get "0" as a response to nextInt...

9:03 justin_smith: ,(frequencies (map #(compare (.nextInt (java.util.Random. %)) 0) (range (Integer/MIN_VALUE) (Integer/MAX_VALUE))))

9:03 clojurebot: eval service is offline

9:03 gilliard: How long have you got ;)

9:03 justin_smith: haha

9:03 gfredericks: gilliard: that might be true

9:03 oddcully: gilliard: thought the same with half of the numbers

9:03 gfredericks: ,(.nextInt (java.util.Random. Integer/MAX_VALUE))

9:03 clojurebot: -1631654733

9:04 gilliard: oddcully, gfredericks: yes it might be true, mightn't it?

9:04 * gfredericks finds his slide about how java.util.Random works

9:05 gfredericks: gilliard: that's not the full seed range though

9:05 oddcully: gilliard: at at least as first number

9:05 gfredericks: I think zero should be possible, set me see if I can reverse engineer it

9:05 gilliard: oddcully: looking at the source of j.u.Random, I don't see how it is, but gfredericks is about to show me!

9:06 oh yes, the seed is a long, and even I don't have that kind of patience...

9:06 oddcully: ah right it's a long. now i need pmap

9:07 gfredericks: gilliard: the seed is a long but it's truncated to 48 bits I think

9:07 have to check the constructor to be sure

9:07 gilliard: Yes: http://developer.classpath.org/doc/java/util/Random-source.html

9:08 justin_smith: ~gfredericks |is| about to show you.

9:08 clojurebot: Ok.

9:08 gfredericks: the whole algorithm is 48 bits

9:09 justin_smith: hey did you guys hear that there is a new fridge that leaks your gmail credentials? the world is stupid

9:10 gfredericks: I don't know enough arithmetic to reverse engineer this any better than just searching higher

9:10 gilliard: I got interested after reading this: http://franklinta.com/2014/08/31/predicting-the-next-math-random-in-java/

9:12 gfredericks: ,(defn java-random [seed] (-> seed (unchecked-add 0x5deece66d) (unchecked-multiply 0x5deece66d) (bit-shift-right 16) (unchecked-int)))

9:12 clojurebot: #'sandbox/java-random

9:12 ebzzry: How/where is let* defined?

9:12 gfredericks: ,(java-random 42)

9:12 clojurebot: #error {\n :cause "integer overflow"\n :via\n [{:type java.lang.ArithmeticException\n :message "integer overflow"\n :at [clojure.lang.Numbers throwIntOverflow "Numbers.java" 1501]}]\n :trace\n [[clojure.lang.Numbers throwIntOverflow "Numbers.java" 1501]\n [clojure.lang.Numbers multiply "Numbers.java" 1867]\n [clojure.lang.Numbers$LongOps multiply "Numbers.java" 467]\n [clojure.lang.Numbers ...

9:12 gfredericks: ,(defn java-random [^long seed] (-> seed (unchecked-add 0x5deece66d) (unchecked-multiply 0x5deece66d) (bit-shift-right 16) (unchecked-int)))

9:12 clojurebot: #'sandbox/java-random

9:12 gfredericks: ,(java-random 42)

9:12 clojurebot: -1139325123

9:12 gfredericks: ,(.nextInt (java.util.Random. 42))

9:12 clojurebot: -1170105035

9:12 gfredericks: aw poop

9:13 akabander: When I do (doc let) it says clojure.core/let

9:13 gfredericks: ,(doc let)

9:14 clojurebot: "([bindings & body]); binding => binding-form init-expr Evaluates the exprs in a lexical context in which the symbols in the binding-forms are bound to their respective init-exprs or parts therein."

9:14 gfredericks: ,(.nextInt (java.util.Random 2464063869))

9:14 clojurebot: #error {\n :cause "java.lang.Class cannot be cast to clojure.lang.IFn"\n :via\n [{:type java.lang.ClassCastException\n :message "java.lang.Class cannot be cast to clojure.lang.IFn"\n :at [sandbox$eval47 invokeStatic "NO_SOURCE_FILE" 0]}]\n :trace\n [[sandbox$eval47 invokeStatic "NO_SOURCE_FILE" 0]\n [sandbox$eval47 invoke "NO_SOURCE_FILE" -1]\n [clojure.lang.Compiler eval "Compiler.java" 694...

9:14 akabander: ,(clojure-version)

9:14 clojurebot: "1.8.0-alpha3"

9:14 oddcully: gfredericks: 0-4096 as seed gives a negative

9:14 gfredericks: ,(.nextInt (java.util.Random. 2464063869))

9:14 clojurebot: 0

9:14 oddcully: ah there ya go

9:15 (inc gfredericks)

9:15 lazybot: ⇒ 145

9:15 gfredericks: gilliard: ^ I found that after 17 seconds of searching

9:15 akabander: Hmm, I get more data from doc, maybe the lein repl is doing something?

9:15 oddcully: ,(Long/toBinaryString 2464063869)

9:15 clojurebot: "10010010110111101010000101111101"

9:16 justin_smith: akabander: I think it's more that clojurebot's version is truncated

9:16 gfredericks: gilliard: this result is actually expected for *any* decent RNG

9:16 justin_smith: akabander: did you have a question about clojure.core/let ? that is the namespace it comes from

9:16 akabander: in clojure.core namespaces don't map 1-1 with files though

9:17 gfredericks: your output is 32 bits and you tried 2^32 seeds, so there's a decent chance you won't see any particular value but that you will see it sometime later

9:17 s/expected/unsurprising/

9:17 gilliard: gfredericks: That's why I was surprised. I had thought the seed was an Integer.

9:17 akabander: I was trying to answer ebzzry, but I think I answered wrong with (doc let) and not let*

9:18 gfredericks: gilliard: even if it were, it should only be surprising if the RNG guarantees it will generate every value exactly once

9:18 akabander: I don't have a let* in my repl, so it's not core.

9:18 ebzzry: akabander: the same in my case

9:19 justin_smith: akabander: let* is a special form, it is defined in java

9:19 let is a macro calling let*, it is in clojure.core

9:19 akabander: justin_smith: It was ebzzry who was asking.

9:19 gilliard: gfredericks: I would expect any value to be equally likely (give or take).

9:19 justin_smith: ahh, I missed that, sorry

9:19 ebzzry: justin_smith: ok. thanks.

9:20 akabander: It's cool, I got your attention, which got the correct answer for ebzzry :^)

9:20 justin_smith: ebzzry: there's a function that tells you if something is a special-form

9:20 akabander: Conveniently for me, I'm reading the macro section of "Joy", so the source for let almost makes sense to me!

9:20 ebzzry: do you know where in tha java source can I see the definition of let* and fn*?

9:20 justin_smith: ,(special-symbol? 'let*)

9:20 clojurebot: true

9:21 justin_smith: ebzzry: one moment, it's not too hard to find...

9:21 ebzzry: justin_smith: thanks

9:23 gfredericks: gilliard: for a deterministic generator with 32 bit seed and 32 bit output, that implies generating every value exactly once

9:23 justin_smith: ebzzry: well, it's weird, but here's part of it :) https://github.com/clojure/clojure/blob/1d5237f9d7db0bc5f6e929330108d016ac7bf76c/src/jvm/clojure/lang/Compiler.java#L44

9:23 gfredericks: i.e., the generator is a permutation of the seed

9:24 justin_smith: ebzzry: so in Compiler.java it sets up "Opcodes" for parsing / binding, and let* is one of those

9:25 ebzzry: next step in the chain is a map of specials https://github.com/clojure/clojure/blob/1d5237f9d7db0bc5f6e929330108d016ac7bf76c/src/jvm/clojure/lang/Compiler.java#L110

9:25 jeaye: 9K line file -_-

9:25 ebzzry: justin_smith: thanks

9:25 justin_smith: jeaye: clojure's java is far from the prettiest :P

9:25 gilliard: gfredericks: Ack, thanks. And because it's a 48bit seed, nextLong actually does have some gaps.

9:26 justin_smith: ebzzry: this appears to be the meat of it https://github.com/clojure/clojure/blob/1d5237f9d7db0bc5f6e929330108d016ac7bf76c/src/jvm/clojure/lang/Compiler.java#L6218

9:27 ebzzry: which makes sense now that I think about it - let is a thing that takes a body of code and binds things, so of course it would be part of the compiler, and it would mainly do parsing and binding...

9:31 gfredericks: gilliard: yep

10:02 snowell: Say I have a map {:one 1 :two 2} and I want to do a (let {:keys [one two]} myMap) on it

10:03 But instead of having to specify the symbols, I just want to destructure all the keys of the map

10:03 Is there an idiomatic (or any) way to accomplish this?

10:03 I tried (into [] (map (comp symbol name) (keys myMap))), but no dice

10:03 akabander: snowell: I was wondering this earlier, I think there'd be issues with symbols in the body of the expression?

10:04 snowell: It's not a huge deal. Just wanted to preserve a little readability

10:04 gfredericks: snowell: nope, no way to do that, and that would be discouraged too

10:04 akabander: Reader/compiler/runtime confusion?

10:04 gfredericks: since it means you can't tell by looking at the code what it does

10:04 gilliard: programmer confusion

10:04 snowell: gfredericks: that's fair

10:05 gfredericks: e.g., say I have (fn [{destructure-all-keys}] (+ a b))

10:05 ^ what does + mean there?

10:05 sometimes it's clojure.core/+ but other times it's the :+ key of the map you pass in

10:06 snowell: Yeah, that would be no bueno

10:06 gfredericks: clojure & associated macros are typically designed so that when a name becomes part of the lexical scope, you can see it explicitly

10:06 even at the expense of a little verbosity

10:07 noncom|2: i think a macros can be written to enable that

10:07 but that is a very bad practice...

10:07 gfredericks: you can't do it with a macro in a straightforward way

10:07 because macros operate at compile-time and you don't know what keys there are until runtime

10:08 noncom|2: the macro could take all keys and symbolize them and intern them with their values

10:08 gfredericks: "all keys"?

10:08 noncom|2: yes..

10:08 R0B_ROD: Hi

10:08 akabander: It would conceptually expand to a big messy let statement.

10:09 gfredericks: noncom|2: where do you get the list of keys from at compile-time?

10:09 akabander: Aha, that's the technical problem that was bugging me

10:09 gfredericks: the only way to do something like that is to call eval at runtime

10:09 which basically means you're calling the compiler every time the function gets run

10:10 noncom|2: gfredericks: no, not on compile time. the macros just inserts the facility that interns the symbols. not at compile time. i say macros because it will easily allow to pass a custom body of code like with the 'let statement

10:10 gfredericks: noncom|2: I think whatever you're imagining will boil down to calling eval

10:11 the only other option is walking the code to figure out what symbols it references, which is tricky because clojure doesn't have a facility to macroexpand/analyze the code

10:12 noncom|2: yeah, maybe eval..

10:13 no need to walk, just intern them all. anyway you're already screwed if you're doing this kind of thing imho..

10:16 crocket: gfredericks, What do you make with clojure nowadays? any meaningful project?

10:20 snowell: cfleming: I take back anything bad I thought about Cursive. I'm enjoying my time with it immensely. Thanks!

10:21 gfredericks: noncom|2: does "intern" mean "create some vars"?

10:21 crocket: I use it at work and I'm maintaining test.check

10:22 noncom|2: gfredericks: yes, sorry, i meant that. well, first to make the symbols, intern them within the curent environment and assign vars to them

10:23 gfredericks: noncom|2: so they'd have to be dynamic vars and you'd have to use binding? I think there are a lot of ways that would break

10:24 noncom|2: gfredericks: sure there are lot of ways this can break - the whole idea is very risky and dirty.. as for dynamic - idk.. is there no way in clojure to access the current environment and modify it?

10:25 gfredericks: noncom|2: you can't dynamically access the lexical environment, no

10:25 it's not reified, it's compiled into bytecode

10:25 noncom|2: for example, let has simpler rules on variable reassign

10:25 gfredericks: in the code (let [a (inc x)] (f x)), "a" does not exist in any meaningful way

10:25 noncom|2: hmmm

10:26 gfredericks: contrasted with (def b 12) where b is a var you can poke and do things with

10:26 * gfredericks got to go

10:26 noncom|2: well, we cold just build a (eval (let [.. ] body)) from the map - i mean the let assignemnt block can be taken directly from the map

10:29 crocket: gfredericks, doesn't sound very interesting.

10:41 justin_smith: crocket: on the contrary, test.check is fascinating, you should take a look at what it does

10:52 akabander: noncom|2: It seems like a lot of effort to do something that's counter to the Zen of Clojure. I mean, it's an interesting idea, but surely we could harness your power for good?

10:53 noncom|2: akabander: sure we could! :) i just came about when someone asked about all this, so I just told my thoughts, I am not advocating for anything here :)

10:53 snowell: Sorry I started all that! :D

10:54 akabander: Haha, it's just that I find myself trying to figure out how to make it work... then "omg wtf am I doing?!" kicks in.

10:55 It's an interesting puzzle, in the same way "how would I weaponize grey goo" is interesting.

10:59 justin_smith: I know, instead of implicit local bindings, we could implement content tracking in clojure.string, sending all data to google between every string transform

11:01 akabander: Yeah, a local redis would not be cloudy enough.

11:01 justin_smith: nor would it be as careless with client data

11:01 akabander: But I like the google idea because every query could be "i'm feeling lucky"

11:01 justin_smith: haha

11:03 chance123: ||||| >>>>> WHAT IS YOUR DOMAIN NAME WORTH? Vist >>> www.VALBOT.com <<< FREE DOMAIN VALUATION! or GOOGLE >>> VALBOT.com <<< |||||

11:04 sdegutis: Is it possible define a defmethod in a namespace that has no access to the defmulti?

11:05 justin_smith: no, defmethod actually alters the defmulti created var itself

11:05 sdegutis: Dang.

11:05 I'm trying to do my configs up using these.

11:05 H4ns: erm, you can define methods for multimethods created in other namespaces

11:06 I'm not sure if I'm misunderstanding the question or justin_smith's answer, though.

11:06 justin_smith: H4ns: yes, but he wants to do it without accessing the namespace with the defmethod in it

11:06 err, without the defmulti

11:06 H4ns: he said with no access, if you can load the namespace that is access

11:06 perhaps I misunderstood the question

11:06 sdegutis: by "no access" do you mean "cannot require the ns at runtime" ?

11:14 sdegutis: justin_smith: ah no I meant inside the (ns).

11:14 Inside the ns that defines the defmulti, I want to :require the namespaces that define the defmethods.

11:14 This is the thing not possible, accurate?

11:15 justin_smith: yeah, that shit's cray

11:15 H4ns: sdegutis: you could create an extra namespace for the defmulti

11:15 justin_smith: there's probably a hack using resolve and require at runtime, but it aint worth it bro

11:15 sdegutis: trudat

11:16 Perhaps using defmulti for configs is dumb.

11:16 justin_smith: you can use defmulti - just put the defmulti in a namespace with no implementation logic in it

11:16 sdegutis: Oh right.

11:16 justin_smith: and put the implementation logic in another namespace, higher in the tree

11:16 sdegutis: So A requires B,C,D which each require Z, and A requires Z to call it's defmulti.

11:17 where B,C,D each have a defmethod for Z's defmulti

11:17 amirite?

11:17 justin_smith: sdegutis: I think I've said this before, but defmulti and defprotocol belong in vapid namespaces that only define abstractions and no implementation details

11:17 sdegutis: yes, something like that

11:17 sdegutis: justin_smith: weird.

11:18 I like circular dependencies. Sad Haskell/Clojure don't support them.

11:18 justin_smith: sdegutis: this is platonic epistimology, where the abstract essence of things is prior to their concrete manifestation

11:18 sdegutis: Does "accidents" fit in there somewhere?

11:18 akabander: I knew that Philosophy degree would come in handy!

11:18 justin_smith: sdegutis: but if you use your abstractions properly, every circular dependency becomes a non-circular one

11:20 sdegutis: This is not magic enough for me.

11:20 I need more magic.

11:20 justin_smith: ruby is over there ->

11:20 sdegutis: I think I'll derive a namespace via string.

11:20 Then I'll load the var in that namespace.

11:21 So for :production I'll load #'config.production/config

11:21 Deal?

11:21 justin_smith: sdegutis: symbols and resolve are more direct, but this is the path to evil

11:21 and by "evil" I mean your own pain and suffering in the future

11:22 sdegutis: This is top-level config-setting stuff.

11:22 This is the absolutely most correct place to use magic.

11:22 Heck I'm even using lein-environ!

11:22 Now, web handler routing and such, that's a much more questionable place to use black magic.

11:23 justin_smith: I already described the clean way to do this, and I know you understood it because you basically repeated it back to me.

11:23 sdegutis: Using defmulti?

11:24 I started implementing it, then I didn't like how much repetition there was in (ns config.dev) (defmulti configs :dev ...)

11:24 See "dev" in that file twice. Bad.

11:24 justin_smith: right, by having the defmulti in a file that has no impl logic, and then having impl logic in a separate namespace, and code invoking the method in a third

11:25 sdegutis: I don't think this is a constrcutive conversation any more.

11:25 sdegutis: Pragmatism always trumps correctness. The only time this seems to not be true is when correctness serves pragmatism.

11:25 In this case, the benefits of defmulti are not really needed, since I'm the only implementor of all the defmulti's, and they're all known at compile time.

11:37 Got it: (defn get-config-for [env] (-> (str/join "." [(ns-name *ns*) env]) (symbol) (ns-resolve 'config) (var-get)))

11:38 Ahh, found a bug in lein-environ :'(

11:39 Fatal one too. You can't have two Lein processes running at the same time in two different envs, because it touches .lein-env to know what configs to use.

11:39 That sucks.

11:39 I vaguely remember there was some way you could inject code using Leiningen...

11:44 justin_smith: sdegutis: injecting code via leiningen and constructing namespaces at runtim from strings are not the jedi way, young padawan, these are the ways of the sith

11:45 Sorella: "justin_smith> sdegutis: but if you use your abstractions properly, every circular dependency becomes a non-circular one" I find this to be bending the definition of "properly" quite a bit. Circular dependencies should be supported in languages, since they arise naturally, it's just hard to do so (specially when you have types). Would be possible in Clojure

11:45 if things were late bound.

11:46 justin_smith: Sorella: clojure does not support circular dependencies without indirection.

11:46 Sorella: (You can work around that limitation, of course. But it's still a limitation :/)

11:46 snowell: Anybody aware of a keybinding or such in Cursive Clojure to indent a block of code correctly (as opposed to just moving the whole block left/right a tab)?

11:46 justin_smith: it's an intentional choice not to support them, not laziness or lack of creativity

11:46 Sorella: Oh, I didn't mean to imply Clojure supports recursive deps.

11:46 justin_smith: I'm saying it doesn't support them due to a choice not to support them.

11:47 and it's a choice I personally agree with

11:47 Sorella: justin_smith: that's fine. I was just questioning the choice of word "properly" here :)

11:47 As it implies "circular dependencies" are bad (at least to me)

11:47 justin_smith: Sorella: yes, and we disagree on that particular value judgment

11:48 hante_monsta: Does clojure has queue?

11:48 justin_smith: hante_monsta: yeah, there's a few choices in fact

11:49 the main one being clojure.lang.persistentqueue/EMPTY

11:49 hante_monsta: justin_smith: such as?

11:49 R0B_ROD: Hello all, new to everything...

11:49 * R0B_ROD continues to read

11:49 justin_smith: ,(-> clojure.lang.persistentqueue/EMPTY (conj 1))

11:49 clojurebot: #error {\n :cause "clojure.lang.persistentqueue"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.ClassNotFoundException: clojure.lang.persistentqueue, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6704]}\n {:type java.lang.ClassNotFoundException\n :message "clojure.lang.persistentqueue"\n :at [java.net.URLClassLoader$1 ...

11:49 justin_smith: err...

11:49 sdegutis: justin_smith: I have three different ways of running code: from `lein run` which is always "development", from `lein test` which is always "test", and from `java -jar mywebsite.jar` which can be either "staging" or "production". I need to come up with a unified way of getting about 30 configuration variables depending on which environment I'm running in.

11:50 justin_smith: ,(-> clojure.lang.PersistentQueue/EMPTY (conj 1))

11:50 clojurebot: #object[clojure.lang.PersistentQueue 0x477c7fed "clojure.lang.PersistentQueue@20"]

11:50 hante_monsta: snowell: Cursive, does not indent well some macros definition

11:50 justin_smith: ,(-> clojure.lang.PersistentQueue/EMPTY (conj 1) (->> (into []))

11:50 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

11:50 justin_smith: ,(-> clojure.lang.PersistentQueue/EMPTY (conj 1) (->> (into [])))

11:50 clojurebot: [1]

11:50 justin_smith: hante_monsta: sorry for the many mistakes getting to it, but see above

11:50 sdegutis: I'm thinking :injections is probably the simplest, safest and most reliable way to set an environment variable when inside `lein run` or `lein test`.

11:51 justin_smith: ,(-> clojure.lang.PersistentQueue/EMPTY (conj 1) (conj 2) (pop) (->> (into [])))

11:51 clojurebot: [2]

11:51 hante_monsta: Is there any O complexity table about Clojure's fns?

11:52 justin_smith: hante_monsta: there's one in the book "Clojure High Performance Programming" - I seem to recall there might be one in a Chas Emerick blog post somewhere too?

11:52 hante_monsta: justin_smith: thanks, very appriciaty, I wonder why I ca't find that in the docs (google) for some reason

11:52 rhg135: What is the advantage of a persistent queue over a vector?

11:52 Sorella: hante_monsta: they're usually the same as the mutable counterparts (in amortised time).

11:52 rhg135: queues support O(1) insertion at the end, and O(1) removal at the beginning.

11:52 philth: hante_monsta: https://www.innoq.com/blog/st/2010/04/clojure-performance-guarantees/ ?

11:52 frogbyte: Hello there

11:52 rhg135: Ah

11:53 Thanks

11:53 hante_monsta: Thanks++

11:53 Sorella: In clojure it has to touch more than one element, though, but we still consider it constant time.

11:53 justin_smith: rhg135: that's why I used conj / pop in my example

11:53 philth: hante_monsta: (inc :thanks)

11:53 justin_smith: rhg135: to do the fast ops

11:53 philth: ;)

11:53 sdegutis: Data composition trumps function composition when available.

11:54 rhg135: The ways of failure are strong with this one

11:55 sdegutis: I'm just thinking about Compojure.

11:55 frogbyte: I need to use the function clojure.java.shell/sh which accepts variable argument. how can I transform a vector so that it can be accepted by this function?

11:55 sdegutis: It builds an opaque data structure that can then be acted on (by asking it to handle a request) but can't be inspected at all.

11:55 justin_smith: frogbyte: apply

11:55 Sorella: sdegutis: configuration is one of the things I find particularly hard in Clojure :/ I've used a atom for my last project, which allows rebinding the configuration at runtime (pretty useful in some cases), but I miss parametric modules.

11:55 justin_smith: frogbyte: (apply clojure.java.shell/sh coll)

11:55 frogbyte: thanks

11:55 sdegutis: Whereas building up a data of route handlers is much more inspectable and flexible, and can still be acted on with a given request.

11:56 hante_monsta: I am reading about game programming with js that expose some imperative algorithms and data structures, and I am trying to find the functional counte parts, for example, people say that I can replace doublylinkedlist with zippers

11:56 sdegutis: Sorella: parametric modules? sir you sound like an OCamler not a Haskeller

11:56 justin_smith: Sorella: have you looked at stuartsierra's component lib?

11:56 hante_monsta: But my head unzip thinking about it

11:56 Sorella: Not a sir, but I'm more of a Newspeaker :P

11:56 justin_smith: I haven't. What's that?

11:56 justin_smith: Sorella: components can be parameterized, and can be re-initialized at runtime with new parameters

11:57 Sorella: component is a library for building systems in terms of data dependencies, solves a lot of typical clojure problems with initialization and sanely building state

11:57 sdegutis: Sorella: never heard of that term

11:57 From 1984?

11:58 Sorella: sdegutis: a Smalltalk dialect: http://www.newspeaklanguage.org/. It has first-class parametric modules, and no global namespace.

11:58 justin_smith: Sorella: https://github.com/stuartsierra/component I recommend trying it in a fairly new project first - it's easier to figure out how to use it from a clean slate, and after you know the ins and outs you can adapt an existing project to use it pretty easily

11:58 sdegutis: Sounds horrifying.

11:59 justin_smith: Sorella: anyway, complete game-changer in terms of managing stateful resources in clojure, I recommend it very highly

11:59 Sorella: It has optional typing too, which is one of the things I don't particularly agree with in the design of the language (I'd have gradual ones, but types are hard for first-class modules).

11:59 justin_smith: sounds interesting :D

12:01 justin_smith: Sorella: a pattern i find very useful is to make a helper that prints out the name of each component as it starts up, which just last night saved me lots of grief when figuring out how to set up a staging environment

12:01 rhg135: You can do runtime redefinition? With component

12:01 justin_smith: because it made it clear exactly which part of the system was misconfigured or missing a required resource from the OS

12:01 hante_monsta: justin_smith: I am using that for one of my web projects, is really easy to use. Just passing the components map as a request context.

12:01 justin_smith: hante_monsta: yup, it's very nice

12:02 hante_monsta: in my case, my server has multiple ways to talk to the outside world, so the http-server is one component, but the kafka connection to our compute cluster is another, and the websocket connections to clients are in a third, and there's a higher level set of components that allow each to invoke messages sent on the others

12:03 hante_monsta: justin_smith: Schema is really good as well, and compojure api is a game changer too (atleast for me)

12:03 justin_smith: hante_monsta: which took a bit of wrangling (because at first glance that looks like it needs to be circular...)

12:03 GivenToCode: im trying to learn a bit of clojure and looking at some code, can anyone tell me what the "(first)" in this line means? https://github.com/TechEmpower/FrameworkBenchmarks/blob/master/frameworks/Clojure/compojure/hello/src/hello/handler.clj#L177

12:04 hante_monsta: justin_smith: I used too to make a notification system along with core.async

12:04 justin_smith: nice

12:04 hante_monsta: justin_smith: Why haskell doesn't have this, or does?

12:05 justin_smith: GivenToCode: the trick is on line 175 - the call to ->

12:06 GivenToCode: -> is a macro that takes the result of each form, and makes it the new first arg to the next form

12:07 GivenToCode: you can find docs and examples for -> on http://conj.io, and feel free to follow up with more questions

12:07 snowell: justin_smith: Is it good/better form to wrap function names in parens like that in -> where there are no other args?

12:07 GivenToCode: justin_smith, so 1 is the first arg to run-queries, and the result of run-queries is the first arg to first?

12:07 justin_smith: snowell: that's a style argument - I don't usually do it, other people think you should always do it

12:07 GivenToCode: exactly!

12:08 GivenToCode: whoever wrote that code really loves the -> macro...

12:08 GivenToCode: justin_smith, if you were to rewrite it, what idioms would you prefer?

12:09 justin_smith: GivenToCode: I would make some of those simple nested calls

12:09 like (response (first (run-queries 1)))

12:09 which compiles to be the same thing as the -> version

12:09 clojurebot: No entiendo

12:12 rhg135: What is wrong with ->

12:13 justin_smith: rhg135: it's not wrong, I find it a little silly when you are only nesting 3 calls though

12:13 especially three calls where there is only 1 arg to each step

12:13 rhg135: but it's a style choice I guess

12:13 rhg135: Some people are allergic to parens though

12:14 akabander: Allergies can be overcome with enough exposure

12:14 rhg135: Yeah

12:15 akabander: I get annoyed when people use "->" as a reason why Clojure "isn't so bad"

12:15 They're operating from false assumptions (that parens are bad).

12:15 rhg135: That is a dumb reason

12:15 justin_smith: (inc ((())))

12:15 lazybot: hello

12:16 (inc parens)

12:16 lazybot: ⇒ 1

12:16 akabander: But you see it in intro to clojure pieces all the time. "Don't like parens? Look you can use -> instead!"

12:16 Bronsa: (inc (((()

12:16 lazybot: ⇒ 1

12:16 justin_smith: Bronsa: so weird

12:17 Bronsa: I might be to blame for that :E

12:17 rhg135: Semantics over syntax forever

12:18 justin_smith: ,(compare "semantics" "syntax")

12:18 clojurebot: -20

12:18 justin_smith: it seems the jvm disagrees, sorry

12:18 hante_monsta: "you don't know nothing jvm"

12:19 Bronsa: ,(compare "a" "c")

12:19 clojurebot: -2

12:19 Bronsa: ,(compare "a" "d")

12:19 rhg135: As do all the jvm coders who like java

12:19 clojurebot: -3

12:19 Bronsa: uh

12:19 hante_monsta: rhg135: was just a joke, just a joke.

12:21 ainz: clojure or haskel better?

12:22 about performance.

12:22 snowell: ainz: I assume you will only get a biased opinion in a clojure chat :)

12:22 And it probably depends on what you value more

12:22 rhg135: hante_monsta: I just refered to the people who claim syntax makes a language unusable, not a reply

12:22 ainz: :)

12:22 thank sir

12:22 Sorella: ainz: performance in what context?

12:22 justin_smith: haskell will calculate answers faster, with clojure you'll get correct code sooner (and most of us will claim it is more fun too)

12:23 ainz: thanks

12:23 hante_monsta: rhg135: I doesn't make it unsable, but it make me not want to use it

12:23 Sorella: They're... uh, very different, and it's hard to really compare them. Clojure's JVM implementation isn't *that* interested in raw performance, but a solution in Clojure may be or may not be faster than a solution in Haskell, for particular subsets of problems

12:23 rhg135: That I can agree with

12:25 Sorella: akabander: I'm particularly not a fan of the prefix syntax used by Clojure, although paredit makes a very good use of it.

12:25 hante_monsta: Sorella: On the counterpart some people in Java are interested in raw performance without the use of RAII

12:26 Sorella: I'm not sure I'd call this particular prefix syntax "bad" per se. But it has a few places where I'd prefer expressing things with another notation. Most other things (e.g.: Agda) that rely on text but are expressive are too complicated though, and tooling/syntax errors become trickier.

12:27 hante_monsta: which is... weird, given that Java isn't particularly that great at raw performance either.

12:29 justin_smith: Sorella: it's in a special niche when you combine performance and portability as criteria though

12:32 Sorella: That's likely true. Makes me wonder if Rust might replace it in that area though, eventually.

12:32 justin_smith: it has massive inertia, and gets used in the sorts of settings where deciding to use a new language is a 5 year exploritory process

12:32 hante_monsta: Sorella: People still love their C++, and don't want to change.

12:34 ralph___: Can anyone offer how to take a collection and dump it's contents in place? Examples @ https://www.refheap.com/108717 or: [a b c] -> a b c

12:36 Sorella: ralph___: (flatten [a [b [c] d]]) => [a b c d]

12:36 ralph___: Sorella: But I want them out of the collection, not flattened.

12:36 Sorella: However, thanks.

12:36 Sorella: ralph___: out of the collection...?

12:36 rhg135: Apply?

12:37 ralph___: rhg135: But what function to apply?

12:37 Bronsa: ralph___: you can't do that, functions can only return one value

12:37 ralph___: do you need this while writing a macro?

12:37 ralph___: Bronsa: OK and yes.

12:37 Bronsa: ,`(foo ~'(bar baz ))

12:37 Sorella: ralph___: ,@the-collection will expand the collection

12:37 rhg135: Ah, nvm then

12:37 clojurebot: (sandbox/foo (bar baz))

12:37 Bronsa: ,`(foo ~'@(bar baz ))

12:37 clojurebot: (sandbox/foo (clojure.core/deref (bar baz)))

12:38 Bronsa: ,`(foo ~@'(bar baz )) ;;err

12:38 clojurebot: (sandbox/foo bar baz)

12:38 Sorella: Oh, I'm mixing Lisps, apparently

12:38 Bronsa: Sorella: yeah ,@ is CL, ~@ is clj

12:39 ralph___: Bronsa, Sorella: Aha, yes, that seems like the ticket. Thanks!

12:39 Bronsa: ralph___: note that ~@ works only inside a ` context and only inside a collection. You still can't splice things into the top-level

12:40 ralph___: Bronsa: I think that should be OK. It doesn't have to be top-level, just within the current scope.

12:42 justin_smith: Sorella: about flatten

12:42 ~flatten

12:42 clojurebot: flatten is rarely the right answer. Suppose you need to use a list as your "base type", for example. Usually you only want to flatten a single level, and in that case you're better off with concat. Or, better still, use mapcat to produce a sequence that's shaped right to begin with.

12:42 justin_smith: also ##(flatten "hello")

12:42 lazybot: ⇒ ()

12:42 justin_smith: ,(flatten {:a 0})

12:42 clojurebot: ()

12:43 Bronsa: ,(flatten 1)

12:43 clojurebot: ()

12:44 justin_smith: ,(flatten #{1 2 3 :set :go})

12:44 clojurebot: ()

12:44 phillord: I've used flatten some of the time

12:45 justin_smith: phillord: well it does say "rarely" and not "never" the right answer

12:45 * phillord nods

12:45 justin_smith: phillord: but it's good to remember its many pitfalls

12:45 phillord: I needed it for "user interface" reasons.

12:46 justin_smith: phillord: oh man that reminds me I am supposed to be helping with some frontend stuff today and I already feel dirty

12:47 phillord: consider a function like "and" but which works either on lists or arguments

12:48 so (and a b c) or (and [a b c]) should return true iff a, b and c

12:48 but also (and a [b c]) or (and a [b [c]])

12:49 well, that's what I used it for, good or bad

12:49 justin_smith: phillord: it's a truisim in systems science that weird messy shit happens on system boundaries

12:49 * phillord nods

12:49 justin_smith: one of those boundaries of course is app / user

12:49 phillord: that's a good aphorism

12:49 justin_smith: see also biodiversity where two ecosystems meet - this isn't always a bad thing

12:50 phillord: given that my library is entirely a system boundary I think that gives me a good excuse!

12:50 justin_smith: haha

12:50 sure

12:51 phillord: actually, several system boundaries at once -- user interface to programmatic library, mutable to immutable, and Clojure to Java. I hope I satisfied everybody, of course. But in the real world....

13:15 doritostains: lein.bat trampoline is giving me the error "input line too long" on a Windows 2003 server. Is there a way to fix this or should I just do with out trampoline?

13:17 justin_smith: lein definitely generates huge command lines...

13:20 amalloy: $google windows xargs

13:20 lazybot: [linux - Windows equivalent to xargs? - Super User] http://superuser.com/questions/652492/windows-equivalent-to-xargs

13:21 jorr: If I want to be able to read a config file consistenly in a jar built with lein uberjar, where do I put the config file?

13:21 I expected resource-paths in project.clj to work, but I'm not able to find anything in those paths at the repl with (java.clojure.io/resource "bla")

13:22 mindbender1: Does anyone have a working systemd script for datomic?

13:22 justin_smith: jorr: I load files via the resource-paths all the time - are you looking for the resource in a path relative to the resource-path entry?

13:24 eg. if ./resources/ is in :resource-paths then I can access ./resources/public/app.js via (io/resource "public/app.js")

13:24 jorr: justin_smith: I think so... can I just reference the directory in resource-path, then that directory will be searched? I think I listed the path to the file itself and not just directory.

13:24 justin_smith: yes, that is how it should work

13:24 jorr: justin_smith: Hmm, okay thanks, I'm sure it'll work with some more fiddling then.

13:25 justin_smith: of course io/resource either returns nil or a input source which you would then hand to slurp or with-open or whatever

13:26 amalloy: i am amazed, searching for "windows xargs" to see if there is a simple solution to doritostains's issue. everyone on the entire internet thinks that xargs is just a way to invoke a program N times (which it is), rather than a way to pass a large command-line to a single program invocation (which it also it)

13:27 justin_smith: amalloy: maybe it's a classic flandersization problem

13:27 amalloy: $google flandersization

13:27 lazybot: [Flanderization - TV Tropes] http://tvtropes.org/pmwiki/pmwiki.php/Main/Flanderization

13:27 wvxvw: hi there. Newbie question. Why is my REPL not finding any dependencies / is unable to require anything but the Java / Clojure own libraries?

13:27 hiredman: well, vars are just a way to have you routes update when you recompile ring routes

13:28 justin_smith: "The act of taking a single (often minor) action or trait of a character within a work and exaggerating it more and more over time until it completely consumes the character."

13:28 jorr: justin_smith: aah that was it, thanks so much.

13:28 justin_smith: jorr: np

13:28 wvxvw: I have a ~/.lein/profiles.clj with pomegranate, and I'm sure it's on my HD, but REPL cannot load it.

13:29 justin_smith: wvxvw: how do you go about requiring it?

13:29 amalloy: there are a million "xargs.bat" files that are like "FOR file in %*; %1 %file"

13:29 wvxvw: (require '[cemerick.pomegranate :as p])

13:29 => FileNotFoundException Could not locate cemerick/pomegranate...

13:29 justin_smith: wvxvw: it could be your profiles.clj is malformed, can you share a paste of it?

13:30 wvxvw: justin_smith: it's really simple, here it is:

13:30 justin_smith: no multi line pastes please

13:30 wvxvw: {:user {:plugins [[cider/cider-nrepl "0.8.2"] [lein-exec "0.3.1"] [com.cemerick/pomegranate "0.3.0"]]}}

13:30

13:30 justin_smith: pomegranate is not a plugin

13:30 wvxvw: well... that's almost one :)

13:30 justin_smith: you need it under :dependencies

13:30 wvxvw: ah...

13:30 let me try that

13:31 are other plugins and why the difference?

13:31 justin_smith: wvxvw: plugins are things added to lein's classpath while loading up your project and preparing to run it

13:31 they can do special things, up to and including adding things to your app's classpath

13:32 wvxvw: yes, that's what I'd like to happen

13:32 justin_smith: wvxvw: dependencies are meant to be required directly by your app. A dependency that is not meant to be a plugin will not end up adding anything to your runtime classpath.

13:32 wvxvw: I mean, why would other things not be able to do that?

13:32 justin_smith: wvxvw: the plugin route for adding an app dep is the weird roundabout way, dependencies are the direct simple way

13:33 wvxvw: justin_smith, I really fail to see the difference.

13:33 justin_smith: wvxvw: lein is a tool that builds your classpath

13:33 wvxvw: a plugin can manipulate the way lein does that through arbitrary code, if it chooses to

13:33 wvxvw: I think that classpath is a... not very smart concept... why would it even use that?

13:34 justin_smith: wvxvw: a dependency is much simpler - it is directly added to your app's class path, with no other special gimmicks or tricks

13:34 wvxvw: the classpath is why you can use 8 different versions of clojure in 8 different projects and not worry about this breaking anything

13:35 wvxvw: Not really no... :) Sorry, Python can do away pretty well without such things. CL too, just to name some other language.

13:35 justin_smith: wvxvw: and they internally have something much like the classpath for setting your visible packages

13:36 wvxvw: But you don't need a ton of setup in random places to do that. You can do it all from the interactive session.

13:36 justin_smith: or else you can break app b by changing a dep in app a (which is the common case)

13:37 wvxvw: anyway, regardless of our personal judgment of the jvm's resource and dependency management strategies, the reason that plugins and dependencies are different is because plugins do weird magic stuff which might include influencing your runtime available packages, while dependencies alter your runtime available packages and do nothing else

13:39 wvxvw: well, it's not something I can influence, so for now, I'll probably have to suck it up. But it's really not something I'd like to put up with in the long run :)

13:39 justin_smith: wvxvw: I never had any luck having multiple versions of a single CL lib available at once

13:39 wvxvw: I run it in exactly this very moment :)

13:40 Maxima can't load together with quicklisp, so I run Maxima separately from the SLIME I work with

13:40 Sorry, back to where we started

13:40 phillord: wvxvw: actually python does have nearly the same thing, for exactly the same reason, which is virtual envs. Diff is these run in different VMs

13:40 wvxvw: (require '[cemerick.pomegranate :as p]) still errors

13:41 justin_smith: wvxvw: can you paste your new profiles.clj?

13:41 wvxvw: But I _don't have to_ use a virtual environment.

13:41 {:user {:plugins [[cider/cider-nrepl "0.8.2"] [lein-exec "0.3.1"]] :dependencies [[com.cemerick/pomegranate "0.3.0"]]}}

13:41 here

13:42 justin_smith: that should be working...

13:42 wvxvw: nope, the same exact error

13:43 FileNotFoundException Could not locate cemerick/pomegranate__init.class or cemerick/pomegranate.clj on classpath. clojure.lang.RT.load (RT.java:449)

13:43 here's the full text

13:45 justin_smith: wvxvw: hey I just replaced my profiles.clj with the one you pasted, and started a fresh repl with no project, and was able to require cemerick.pomegranage using the exact require you pasted

13:45 wvxvw: have you restarted the repl since changing profiles.clj?

13:45 wvxvw: justin_smith this only means there are some hidden variables, like environment variables, configuration files elsehwere etc, stuff that neither of us is aware of, but you have them and I don't.

13:46 justin_smith: wvxvw: no, I have no other visible config for lein other than what lein self-installs and the profiles.clj which I replaced with yours

13:46 amalloy: wvxvw: no, there aren't. the only hidden variable is what you are typing that's causing that error

13:46 justin_smith: lein is installed locally by and for my user, and has no system level config

13:46 s/no other visible/no other available

13:47 wvxvw: you never know... what about $JAVA_... stuff? Can this influence it? Maybe $CLASSPATH, $MAVEN_... stuff?

13:47 justin_smith: if you changed the $MAVEN stuff that could provoke a not-found type error, or force re-download of artifacts

13:48 it would not simply make a dep unavailable from the repl

13:48 it would fail

13:48 wvxvw: can you locate the jar with pomegranate? So that I could check I have it too?

13:48 No, I never changed it by hand, but, again, you never know, different system, different package manager etc.

13:49 justin_smith: wvxvw: it is in ~/.m2/repository/com/cemerick/pomegranate/0.3.0/

13:49 wvxvw: Because, apparently, it does make a dependency unavailable from repl.

13:49 amalloy: wvxvw: the thing i would like to know is, starting from a terminal $ prompt, what are you typing that causes you to get this error message

13:49 justin_smith: wvxvw: lein is the package manager

13:49 wvxvw: it's not really a package manager, since it cannot install or search for packages... it's 0.33% package manager :D

13:50 justin_smith: wvxvw: it does both, and those are its primary jobs

13:50 wvxvw: well, it kinda fails at that big time :)

13:50 yes, I do have that jar at exactly the same location

13:50 justin_smith: wvxvw: and if it is failing to do those things you should ensure your version is up to date and that you are using it correctly

13:51 wvxvw: it is installed today, about an hour ago

13:51 oddcully: there is the plz plugin for lein to make it search and add deps

13:51 wvxvw: what I'm doing with it:

13:51 amalloy: i find it frustrating to try and help you, wvxvw, because you would prefer to argue about how lein should act, and guess at possible solutions to your problem that, if you had the experience justin_smith and i have, are clearly not possible issues, rather than follow suggested debugging steps like "what are you doing that causes this error"

13:51 wvxvw: $ lein repl

13:51 justin_smith: OK after changing your ~/.lein/profiles.clj a fresh lein repl should be able to load pomegranate

13:51 wvxvw: then:

13:51 (require '[cemerick.pomegranate :as p])

13:51 nothing more

13:52 amalloy: and you have done this anew since changing your profiles

13:52 wvxvw: also, is there probably some way to make it start faster? Just in case...

13:53 justin_smith: ~faster

13:53 clojurebot: faster is https://github.com/technomancy/leiningen/wiki/Faster

13:53 justin_smith: wvxvw: ^ see link

13:53 wvxvw: thanks, will do

13:55 ok, for no reason this time it worked. I honestly didn't do anything. in fact, I had it all recorded as a macro, so I just re-ran exactly the same stuff I did before, and it worked.

13:55 go figure

13:56 Thank you justin_smith, I guess :)

13:57 amalloy: (inc justin_smith)

13:57 lazybot: ⇒ 291

14:04 justin_smith: wvxvw: I'm legitimately curious, how one uses different versions of the same CL lib within two projects on the same machine using the same install, because in my various usage of defpackage I never saw a version parameter

14:06 wvxvw: justin_smith: you can symlink the asd fily into your project directory, it's the place where quicklisp will look up first, before the global registry / local-projects

14:06 s/asd fily/asd file/

14:07 justin_smith: wvxvw: so if my dep tree contains 100 deps going recursively, I make 100 symlinks if I want to ensure reproducable behavior?

14:08 wvxvw: in that case I'd have modified the global registry (the asdf configuration file) and have copies of it loaded on per project basis

14:08 justin_smith: also, how does one keep this in sync with a team, forcing everyone to have all the same things manually installed so the symlinks work?

14:09 wvxvw: but that doesn't sound like a realistic scenario at this point... in all my years of working with CL, I didn't accumulate enough libraries to run into the kind of problems

14:09 justin_smith: wvxvw: using clojure I use large numbers of very small libs

14:10 my app has many project files right now, in one of these projects "lein deps :tree | wc -l" tells me I have aproximately 200 libs in my tree of deps

14:10 wvxvw: then again, you'd need something like virtual environment, but, again, in my experience, the problem people have which encourage them to have a virtual enviroment is usually bad planning (which is not so unusual)

14:10 justin_smith: we don't have or need virtual environments with clojure

14:11 wvxvw: instead you have an extremely convoluted and uncomfortable way of importing libraries?

14:11 justin_smith: usually - I guess some people use them to bundle non-clojure services along with the jar in one place I guess

14:11 wvxvw: once you accept some simple premises it's neither, but I do understand there's no accounting for taste

14:12 wvxvw: this isn't taste really... let me explain. With things like pip / gem / cabal etc you learn to expect that there is a program to install stuff, find stuff etc.

14:12 justin_smith: wvxvw: I find it very helpful to know with 100% certainty that my team mates get exactly the lib versions I get, without any extra effort needed beyond what is required to make things work locally

14:13 wvxvw: I know what those programs are, and have found them less reliable than lein

14:13 wvxvw: lein is called a project manager, but it doesn't really know how to do any of that. It cannot search, it cannot install (because, technically, there isn't even a place to install to)

14:13 justin_smith: wvxvw: it does both!

14:13 it installs to a local cache

14:13 wvxvw: but no, it doesn't!

14:13 justin_smith: it searches with "lein search"

14:13 wvxvw: there's no such command line option

14:13 justin_smith: ?

14:13 wvxvw: install Install the current project to the local repository.

14:14 justin_smith: I just ran "lein search pomegranate"

14:14 wvxvw: this isn't installing a library, this is finding the dependency for the project

14:14 justin_smith: wvxvw: that is what "lein deps" does

14:14 rhg135: It does install

14:14 To your local repo

14:14 wvxvw: but the help says otherwise, whome should I trust?

14:15 rhg135: It says that too

14:15 wvxvw: I want to install globally... local is a bonus, but most of the time this isn't what I want...

14:16 justin_smith: wvxvw: sadly wanting to install globally isn't normal, or easy with lein. Which is why I said that if you can accept some simple premises (one of these is "no such thing as global installs"), it can be quite nice. If you can't accept it's premises, I encourage finding a build tool you like better.

14:16 rhg135: You could use plain jvm if you dislike lein

14:16 justin_smith: I think ant does global installs

14:16 right

14:17 wvxvw: well, I don't really care about what is considered normal :) practical for me outweights what others consider normal

14:18 and if the answer is "it is what it is", then yes, I can understand it. Many languages and environments are built on this very principle :)

14:18 justin_smith: I think you'll find not using lein in the clojure ecosystem is a lot more work than using lein is

14:18 rhg135: What would a global install do for you?

14:19 Using python was painful here

14:19 wvxvw: I'm just a random bystander, Clojure isn't my primary language. But, if we were to compare it to Java, then it's simply not improving on how bad Java is in this regard...

14:19 Well, it wasn't painful for me.

14:20 rhg135: Lucky

14:20 wvxvw: Global install in details

14:20 well, you see, java, for instance, has a way to make a global install on Linux.

14:20 there's a whole packaging system in place etc.

14:21 Too bad most Java programmers don't know about it...

14:21 rhg135: Maven...

14:21 wvxvw: so you end up having multiple copies of the same jars over and over in many places

14:21 justin_smith: wvxvw: no, it uses one cache, you might have multiple versions, but only one copy of each version

14:22 wvxvw: Maven doesn't always have what you need. I've had a (mis)fortune to work on various sized Java projects and therenever was a case when all dependencies were managed by Maven.

14:22 justin_smith: wvxvw: the key is reproducibility - that is, given the same project.clj two different developers on different machines are guaranteed to have exactly the same versions of everything

14:22 wvxvw: Also, Linux way of installing java is independent of Maven, so...

14:22 justin_smith: wvxvw: and, given the same project.clj, I can come back 10 years later and use the same versions of everything

14:23 I wish Linux package managers were as reliable about versions and isolation as lein is, I guess nix comes close

14:23 wvxvw: That's more of a wishful thinking. It will never work exactly like that. But you may have higher degree of confidence, that's true.

14:23 justin_smith: wvxvw: I come back to projects years later, it works like that

14:24 wvxvw: because package version deploys are effectively immutable

14:24 wvxvw: you are trying to convince me by means of a single person making experiment in a non-controled enviroment? :P Seriously, that's not going to cut it

14:24 justin_smith: wvxvw: this is why we accept the weird parts of lein (including no global installs, needing a project.clj for everything...) - the increased repeatability

14:25 wvxvw: What if I don't care about it?

14:25 justin_smith: then don't use lein

14:25 wvxvw: but there's no alternative... except for lots of manual labor...

14:25 rhg135: Boot is nice

14:26 Not as nice as lein, but yeah

14:26 wvxvw: will it locate and install libraries available in some centralized repository into a global repository?

14:26 (on the machine I'm working on that is)

14:26 rhg135: Yes

14:26 justin_smith: rhg135: that's not true, it uses a classpath to manage versions via the maven schema

14:26 it's not what he wants

14:27 he wants unversioned global installs

14:27 rhg135: Set you're maven repo to be global

14:27 Like /m2

14:27 Oh

14:27 justin_smith: rhg135: by global he means no version qualification

14:27 wvxvw: that's not true

14:27 justin_smith: bbl, lunch

14:27 rhg135: Unversioned, blasphemy

14:28 wvxvw: by global I mean the same thing as Java packages are installed on Linux

14:28 no Maven

14:28 just rpm / deb

14:28 it's much faster, easier to manage and more secure

14:28 rhg135: No such global repo exists

14:29 wvxvw: well... that's one of the problems :)

14:29 rhg135: I know only of maven

14:29 wvxvw: (to make it fair, for example, there isn't one such repo for CL either)

14:29 rhg135: It works great though

14:29 wvxvw: which is unfortunate and sad, but that's how it is.

14:29 well, that probably depends on what you want it to do :)

14:31 rhg135: You specify your deps, if they're in your local repo, uses that, else, downloads it

14:32 wvxvw: well, this is bad, and I'll tell you why

14:32 It seems ok as long as you are the user of your program

14:32 but when you try to distribute it for others to use, you want the shared libraries to be available not only to you, but to others too

14:33 rhg135: They are

14:33 wvxvw: I mean, you don't want the Windows-style installs, where all DLLs come with the program

14:33 no, they aren't, and that's the problem

14:33 rhg135: They aren't

14:33 wvxvw: you don't want your users to install lein

14:33 neither maven etc.

14:33 rhg135: They don't

14:33 wvxvw: then how will they get their libraries?

14:34 rhg135: You can use plain java

14:34 wvxvw: hahaha

14:34 lol

14:34 seriously, and how that solves the problem?

14:34 rhg135: Download them manually

14:34 Or via rpm etc

14:34 wvxvw: seriously? come on. You will distribute your program with a readme which says users need to download stuff from the internet?

14:35 In what universe? :)

14:35 tatut: in reality, I think most will just ship a uberjar with everything, wvxvw seems to want something different

14:35 rhg135: Try running a python app with deps without setuptools

14:35 That's fun

14:36 wvxvw: you see, I'm so bitter not because of Clojure. CL lacks this infrastructure too. Some time ago I wanted to package my small and unimportant library in a way that others could use it too, and I realized that I can't.

14:36 danlentz_: why not?

14:36 lots of people seem to be distributing CL libraries

14:37 wvxvw: rhg135, setuptools is a built-in package. You can, if you wanted to, make a distribution which installs all it needs. Not a usual thing to do, but also not so uncommon.

14:37 but, most importantly, you don't do it in python.

14:37 you do it using rpm / dep and such

14:37 and this is where the real problem is. You need global install

14:38 rhg135: Isn't there a non standard setup lib some use

14:38 I meant that

14:38 wvxvw: there's pip, but what I'm getting at is distributing the program, not the library for other programmers

14:39 this is the three staged process: programmer writes the program, package maintainer packages it and the user installs it and uses.

14:39 danlentz_: wvxvw: cl offers quicklisp (quicklisp.org) with a facility called a "dist"

14:39 wvxvw: In case of CL, it's broken at package maintainer - you simply cannot package your program so that a user could just install it...

14:40 rhg135: I need pygame vY. My distro only has vX. Oh dear

14:40 danlentz_: wvxvw: huh?

14:40 nonsense

14:40 wvxvw: yes, there are limitations on what is packaged / available, but at least in pricniple it's possible

14:40 with Clojure / CL doesn't seem to be possible

14:41 danlentz_: ok, sorry i joined in

14:41 wvxvw: danlentz_ well. The only CL program distributed on Fedora is Maxima

14:41 danlentz_: well, fedora is not a cl distribution mechanism, is it?

14:42 wvxvw: I looked through the sources of the package, and I've also read the guidelines for packaging Lisp programs for RHEL distros (from previous century - nothing newer)

14:42 danlentz_: Waaa. I cant download Ubuntu from the Mac app store

14:42 yeah

14:42 well, look at ASDF

14:42 and quicklisp

14:42 wvxvw: Fedora is a distribution of programs, and that's what I'm talking about

14:43 Look, I probably know about quicklisp and ASDF than you do... and that's why I'm saying this in the first place...

14:43 they are not tools for installing programs.

14:43 they are for programmers, not the users

14:44 To give you more specifics: I wrote a library in CL, bindings for link-grammar C++ library.

14:45 Now, I wanted to package it for Fedora so that someone who wants to use the library could install it with dnf / yum

14:45 There is no way at the moment to do that.

14:45 The infrastructure that existed once is long gone

14:45 New isn't there yet.

14:45 danlentz_: ok, apologies for basking in the ignorance that makes me think im using it effectively

14:46 wvxvw: this is not it. I'm talking about different process / different purpose

14:46 distributing programs =/= resolving dependencies

14:47 * rhg135 resets the counter

14:47 danlentz_: a quicklisp dist can package and distribute software

14:47 wvxvw: :0

14:47 danlentz_: and ASDF system can build and install libraries

14:47 wvxvw: no...

14:48 danlentz_: and both are arbitrarily extensible platforms

14:48 wvxvw: We are talking about integration with package managers, does it explain it better?

14:48 danlentz_: i see

14:48 wvxvw: Can quicklisp produce a package installabe on Android?

14:49 it can produce a program, something you can drop on your computer and run - that's true

14:49 danlentz_: i'm using clojure to install an app that can package and run on iOS

14:49 clojurescript rather

14:49 wvxvw: but packaging for a package manager is an entirely different process

14:50 danlentz_: i see, though. But you are limiting "package manager" to mean yum or apt

14:50 wvxvw: alright, sorry, I must go, duty calls.

14:50 I just mentioned Android (that'd be GooglePlay, or w/e it's called)

14:50 anyhow, sorry, I must be bowing out. Nice talking to you guys :)

15:25 hanate_monsta: Would people (this community) bash on me if solve problems in imperative way in Clojure? :)

15:26 snowell: Bashing doesn't help anyone!

15:26 {blake}: We're not really bashers here.

15:26 snowell: But I will say the first time I took something imperative I wrote in Clojure and changed it to a pure function it felt AMAZING

15:27 hanate_monsta: I wanna do the opposite.

15:27 {blake}: We might say we're disappointed in you. =P

15:27 snowell: lolwut

15:27 hanate_monsta: YES!

15:27 {blake}: But I'd be open to hearing why you wanted to do so.

15:27 hanate_monsta: Games!

15:29 Could I translate your silence as bashing? I knew it.

15:29 {blake}: heh

15:29 But the world is moving toward pure functional games!!

15:29 hanate_monsta: LIARS!

15:31 {blake}: Entity Component Systems?

15:31 hanate_monsta: Garbage!

15:32 {blake}: Socrates, Plato, Aristotle? Morons!

15:32 hanate_monsta: I meant, Clojure produce so much garbage (you know GC)

15:32 {blake}: Oh, well, yeah. That's a good argument against using Clojure for games generally.

15:40 Is there a way for Clojure to query the JVM? See what the heap size is?

15:41 ,(.maxMemory (Runtime/getRuntime))

15:41 clojurebot: #error {\n :cause "Reference To Runtime is not allowed"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.SecurityException: Reference To Runtime is not allowed, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6891]}\n {:type java.lang.SecurityException\n :message "Reference To Runtime is not allowed"\n :at [clojurebot.s...

15:42 justin_smith: {blake}: check out the javadoc for System and Runtime, yeah

15:42 {blake}: I looked at System first and didn't see anything...I'll look harder. =P

16:55 OK, I have a function defined as (defn promote[req][req]...(stuff)...) and I just now noticed I have the arg list in there twice. It works but why? Is it reading that as a multiple-arity situation with only one arity?

16:56 justin_smith: {blake}: it's just a vector doing nothing

16:57 ,((fn [] [1 2 3] :OK))

16:57 clojurebot: :OK

16:57 {blake}: Oh. Right. I guess if there were nothing else it would return the arguments.

17:10 Sounds like a Jimmy Buffet song: "Just A Vector Doin' Nothin'"

17:11 OK, here's a style question. It has seemed to me that the preference for using require is pass vector.

17:11 (:require [clojure.set :as set...)

17:12 To the point where I was surprised to see "(require '(clojure.java io))" in the docs.

17:13 I guess the vector is preferred because you don't have to do the ' mark?

17:13 justin_smith: {blake}: no, with require you do

17:13 oddcully: note the difference between (:require) in ns and (require)

17:14 {blake}: When used directly, yeah, but in the :require clause you don't.

17:14 justin_smith: {blake}: the difference is that () is being used for the prefix form of require there

17:14 {blake}: neither requires (or even allows) a quote in the :require form

17:14 {blake}: Oh.

17:14 justin_smith: {blake}: those are two different things - prefix require, which is universally despised, and nobody uses

17:14 {blake}: So why prefer the vector?

17:14 justin_smith: and a require with a qualifying vector

17:15 {blake}: justin_smith: Oh! I didn't know it was universally despised. Why is it universally despised?

17:15 Awkward to actually use?

17:16 justin_smith: {blake}: if you do (:require (clojure.java [io :as io] [shell :as shell])) it is hard to grep for usage of clojure.java.io or clojure.java.shell

17:16 that's the prefix thing that the () example is using above

17:16 and note that when using :as etc. you should still be using [] inside it

17:17 {blake}: Ahhh. OK. And, yeah, I prefer :as more and more with any require.

17:18 justin_smith: {blake}: but I hope it's clear I am not talking about using :as or not - I am talking about the prefix form of require

17:18 which is what your require with () actually was

17:18 {blake}: Yeah, I get it.

17:19 I meant "in addition to that, I'm tending to use :as which requires the vector, right?"

17:19 justin_smith: OK

17:20 {blake}: does't require it, but that's the idiom

17:20 {blake}: Right. Fair enough.

18:17 oneness: anyone out there tinkered with adding pre and post to defmulti?

18:22 justin_smith: oneness: you mean like a pre-condition on the dispatch function? because there is nothing else on the defmulti level itself

18:22 or do you mean on one of your defmethods - either should work

18:25 oneness: I mean to add pre and post contract to the defmulti so all defined methods automatically abide by it.

18:26 looked at a bit to defmulti and looks like it does not support :pre and :post.

18:35 amalloy: oneness: just define an ordinary function that delegates to your multimethod

18:35 (and put the conditions on that, of course)

18:38 hiredman: or put them on the dispatch function, or each defmethod, or...

19:16 justin_smith: $mail oneness I just created a multimethod dispatch function with :pre conditions and it absolutely works

19:16 lazybot: Message saved.

19:16 justin_smith: ,(defmulti foo (fn [& args] {:pre [(even? (count args))]} (first args)))

19:16 clojurebot: #'sandbox/foo

19:17 justin_smith: ,(defmethod foo :default [& _] :OK)

19:17 clojurebot: #object[clojure.lang.MultiFn 0x6f992b1 "clojure.lang.MultiFn@6f992b1"]

19:17 justin_smith: ,(foo :a :b)

19:17 clojurebot: :OK

19:17 justin_smith: ,(foo :a :b :c)

19:17 clojurebot: #error {\n :cause "Assert failed: (even? (count args))"\n :via\n [{:type java.lang.AssertionError\n :message "Assert failed: (even? (count args))"\n :at [sandbox$eval25$fn__26 doInvoke "NO_SOURCE_FILE" 0]}]\n :trace\n [[sandbox$eval25$fn__26 doInvoke "NO_SOURCE_FILE" 0]\n [clojure.lang.RestFn invoke "RestFn.java" 436]\n [clojure.lang.MultiFn invoke "MultiFn.java" 238]\n [sandbox$eval103 inv...

19:17 justin_smith: ,(foo :a :b :c :d)

19:17 clojurebot: :OK

21:08 AWizzArd: There is this Java method which takes a java.util.function.Function. How can I pass it some Clojure function? (.method my-fn) doesn’t work.

21:09 Java 8.

21:09 justin_smith: AWizzArd: you can make a java.util.function.Function that delegates to your fn

21:09 fn does not implement java.util.function.Function, and from what I hear never will

21:10 function.Function has a constructor that take a callable right?

21:10 AWizzArd: Oho, why not implement it?

21:10 Function is an interface.

21:10 justin_smith: oh right

21:10 so you could use reify

21:10 AWizzArd: I see it has some apply method that I can implement.

21:11 But seriously, there should be something in Clojure that makes this easy. Clojure is deeply integrated into the JVM, and I don’t think it should stop this here.

21:11 justin_smith: reify isn't so hard to use

21:12 amalloy: AWizzArd: reify is what makes it easy

21:12 there can't be any tighter integration, because clojure isn't going to require java 8 anytime soon

21:12 so it can't have a Function implementation built in

21:14 AWizzArd: amalloy: yes okay, depending on J8 is maybe too early, but I was thinking of the “never will” that justin_smith mentioned.

21:15 amalloy: with the conditional compilation reader macros, couldn’t there be two compilation targets, of which J8 is one?

21:16 amalloy: do you have a conditional compilation reader macro that works for java, in which IFn and AFn and all that are defined?

21:22 AWizzArd: amalloy: two branches then. All patches are done on the current/classical brand and simply get merged into the J8 one.

21:24 amalloy: feel free to propose this on clojure-dev. i predict it will not go far

21:24 AWizzArd: amalloy: you think the current interest in Java 8 is too small when weighted with the required effort that would have to be put into such a development?

21:24 amalloy: i don't know justin_smith's "never" is based on some specific statement from someone with authority or just a rough estimate, but with my limited information i expect it will be a very long time

21:28 AWizzArd: Perhaps future versions of Java will add interesting features that would increase the motivation to use them

21:51 camm_v222: Hi, I'm new at Clojure. Perhaps you know a web site, book, or video tutorials where I can learn about it?

21:52 namra: camm_v222: http://www.braveclojure.com/

21:52 camm_v222: another one -> https://aphyr.com/posts/301-clojure-from-the-ground-up-welcome

21:53 http://shop.oreilly.com/product/0636920034292.do

21:54 camm_v222: Thanks namra, I really appreaciate it.

21:55 namra: there are other well know clojure books, but unfortunately forgot their names :/

21:56 camm_v222: http://clojure.org/books?responseToken=a59c3eac653721eb2b49c7b99f5aa5d6 --- there you go

21:56 many people recommend "the joy of clojure" but iirc it's not an introduction more like a book for people who already have experience with clojure

22:19 talios: if there an (if-let) variant that accepts multiple binding forms at all? Can't seem to spot one..

22:19 s/if/is/

22:19 gfredericks: talios: not in clojure or contribs I don't think

22:20 justin_smith: nope

22:20 gfredericks: there's been a bunch of discussions about that

22:20 justin_smith: there have been various proposals but no unanimity of how it would work

22:20 gfredericks: I am pretty happy with prismatic/fnhouse

22:21 talios: doh, I wonder if I can use core.match for what I want, and match on a pair of things. basically I have a map and I want to conditional run something if 2 specific keys are present.

22:56 nxqd: hi guys, what is the safe way to get a value in a map based on a key where that key is not available : (def a {:a 2}) (:b a)

22:57 gfredericks: nxqd: what do you want that to evaluate to?

22:58 nxqd: I just found contain? I think it's what I need.

22:58 thanks for helping :)

22:58 gfredericks: np

23:28 sdegutis: How can I profile all the time `lein run` is taking before -main is actually called?

23:39 gfredericks: time lein run -m clojure.main -e '(println (quote hello))'

23:40 though that probably won't require your code

23:40 so you'll want to add a require in there too

23:40 doing both will tell you how much time is lein & clojure and how much time is compiling your code

23:41 sdegutis: gfredericks: it's definitely a good start though for a baseline

23:42 ddellacosta: nxqd: a little late but you should also take a look at the behavior of get, that may be a simpler way to do what you want without doing some kind of check first

23:42 &(get {:foo "foo"} :bar "bar")

23:42 lazybot: ⇒ "bar"

23:43 neoncontrails: What's the most idiomatic way in Clojure to keep iterating a lazy-seq until the values are no longer changing?

23:43 sdegutis: WHOA

23:44 (require 'my.main.namespace) takes 6673.242276 msecs

23:44 gfredericks: sdegutis: if you find the clojure jar in your ~/.m2 you can also run that with `time java -jar clojure.jar -e '(println :hello)'`

23:44 neoncontrails: ,(take 10 (iterate (fn [x] (Math/cos x)) 1))

23:44 clojurebot: (1 0.5403023058681398 0.8575532158463934 0.6542897904977791 0.7934803587425656 ...)

23:44 sdegutis: Is it normal that it should take 6 seconds to require all my project's namespaces?

23:45 gfredericks: sdegutis: not too surprising

23:46 sdegutis: it probably includes loading all your libraries too

23:46 sdegutis: :(

23:46 Right.

23:46 neoncontrails: Take <acceptably large fixnum> obviously gets the right answer eventually, but I'm curious how to short-circuit the evaluation when the values stop oscillating

23:47 gfredericks: neoncontrails: you want to detect when you get the same value twice in a row?

23:48 amalloy: neoncontrails: you want to wait until cos(x)~=x? for what values of x is that true

23:48 sdegutis: gfredericks: but is it reasonable for just loading a bunch of libs to take that long?

23:48 I mean all they should be doing is a bunch of (def) and (defn) right?

23:48 gfredericks: amalloy: something between 0 and pi I think

23:48 sdegutis: well it's compiling all of that code to classes

23:48 amalloy: between 0 and pi/4 even, i would think

23:49 gfredericks: sdegutis: I think ztellman had one weird trick to speed it up that might not be incorporated yet

23:49 neoncontrails: amalloy: How did I not see that before. Thank you!

23:49 sdegutis: gfredericks: oooo

23:49 amalloy: how did what i said helped?

23:51 neoncontrails: I think I was hitting a wall trying to access the (last (butlast sequence)) and compare it to the (last sequence), but yours is a much better solution

23:51 amalloy: i didn't offer a solution

23:52 not one i recognized, anyway

23:53 gfredericks: ,(->> (iterate #(Math/cos %) 1) (partition 2 1) (remove (fn [[a b]] (not= a b))) (ffirst))

23:53 clojurebot: 0.7390851332151607

23:53 gfredericks: ,(Math/cos 0.7390851332151607)

23:53 clojurebot: 0.7390851332151607

23:53 neoncontrails: You asked the question in just the right way I suppose :)

23:53 ,(take-while (fn [x] (not (= x (Math/cos x)))) (iterate (fn [x] (Math/cos x)) 1))

23:53 clojurebot: (1 0.5403023058681398 0.8575532158463934 0.6542897904977791 0.7934803587425656 ...)

23:54 neoncontrails: gfredericks: Interesting, can you briefly explain the logic?

23:54 gfredericks: neoncontrails: (partition 2 1 coll) gives you adjacent pairs

23:55 e.g., ##(partition 2 1 '[a b c d])

23:55 lazybot: ⇒ ((a b) (b c) (c d))

23:55 gfredericks: so then just run through the list until you find two that are equal

23:55 neoncontrails: Aha, very good

23:57 (inc gfredericks)

23:57 lazybot: ⇒ 146

23:57 neoncontrails: (inc amalloy)

23:57 lazybot: ⇒ 295

23:57 amalloy: you can also just write that function once, call it fix

23:58 neoncontrails: That's a good point. I'll do that now as an exercise

23:58 amalloy: good thing you said, because i was about to paste a correct definition

23:59 (which IMO turns out to be a lot clearer than a partition/iterate solution)

23:59 gfredericks: ~amalloy |was about to paste| a correct definition

23:59 clojurebot: In Ordnung

Logging service provided by n01se.net