#clojure log - Feb 21 2015

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

1:56 jux: hi

1:58 I got strange behavior from clojure.java.jdbc. when I do query (sql/query dsn ["select id, name from ns.users where id > ? order by id" 1])

1:59 all strings are returned surrounded by \"

1:59 so I get ({:id 1 :name "\"John Doe\"})

2:00 what can be the reason?

2:03 hiredman: you are double printing, either on the way out or the way in

2:20 jux: hiredman: these things show in my unit tests, so it's not a thing of printing

2:20 and I inserted data directly using Navicat

2:32 hell, you were right

2:47 ewemoa: alexyakushev: having trouble building foreclojure-android -- is it supposed to build atm?

2:48 alexyakushev: ewemoa: What error do you get?

2:52 ewemoa: alexyakushev: https://pastee.org/68hs4

2:53 alexyakushev: ewemoa: Let's take it to #clojure-android, shall we?

3:51 Eremox: Is there some thing like scala's Akka in clojure?

3:52 irctc__: Hi everybody. Is there a shorter version to do this multi arity-function? because for both type of arguments, the same function is called: (defn get-15min-range ([{start :start-time end :end-time}] (range start (+ end 900) 900)) ([start end] (range start (+ end 900) 900)))

3:59 amalloy: irctc__: you can make the first arity call the second one

4:03 irctc__: great, i will to this! I have a second question. when i have two destructuring arguments in a multi-arity function [{a :a b :b}] and [[a b]] - i get a warning that both arguments are the same length, even if one is a map and the other one is a vector. How can i express this destructuring in an multiple-arity function?

4:32 amalloy: you can't. clojure's functions are only overloaded on argument count, not on anything else. if you want different bodies based on something else, oyu need to do more than write a multi-arity function. for example, write a multimethod instead

4:47 the-kenny: Or you can use core.match if you want the 'matching' style.

4:48 irctc__: i will look into core.match and multimethods - thanks for the advice

5:49 nw2: probably a stupid question, but in this example https://www.refheap.com/97610, the call to the "foo" macro throws a ClassNotFoundException, but the "bar" macro works fine. is there any way to make the "foo" macro work?

5:51 Bronsa: nw2: you want & body not body in the argvec

5:52 hyPiRion: (macroexpand-1 '(foo (File. "/tmp"))) => (do File. "/tmp")

5:53 nw2: Bronsa: ah, of course! thank you very much

6:19 Guthur`: Hi, I'm just starting with Clojure usign Emacs and CIDER

6:19 I was wondering if there is an eldoc style hint system with CIDER

6:20 so that I can get information about the interface for a function etc

6:20 Eremox: Why is sicp recommended?

6:21 AimHere: Partly because it introduces a lot of important programming concepts. Also it uses a lisp as it's introductory programming language, which turns some nerds on.

6:22 darrenh: I have a question about the component framework. If I want to vary a protocol implementation based on configuration, is there a good way to go about it? My use case is where I want to wrap one of my components with one that intercepts the calls based on a configuration flag.

6:22 Eremox: Which would be better to read first sicp or ctmcp

6:42 tomjack: Guthur`: yes? it doesn't work for you?

6:42 oh, it looks like I had to do (require 'cider-eldoc) (add-hook 'cider-mode-hook (lambda () (cider-turn-on-eldoc-mode)))

6:48 Guthur`: tomjack: ah, ok I will give that ago

6:53 tomjack: excellent,thanks

6:54 tomjack: if you use paredit, I'm not sure it works right

6:54 http://emacswiki.org/emacs/ParEdit#toc2

6:55 but it seems kind of nuts that only those two commands are on the list!

7:01 Guthur`: Yeah i normally use paredit, but have not added it to a clojure mode hook yet

8:17 jaen: Is there any way to dump leiningen middleware stack and/or hooks so I know where certain behaviour comes from (or a verbose execution mode that says so)?

8:44 the-kenny: jaen: with lein pprint, yes.

8:44 jaen: https://github.com/technomancy/leiningen/tree/master/lein-pprint

8:51 jaen: the-kenny: thanks. It shows no middleware however. That's weird o_0

9:13 doright: Clojure appears in only 17 London job titles on www.indeed.co.uk compared with Scala:386 and Groovy:70. What is required to increase Clojure's adoption?

9:13 pandeiro: what would be the way to walk a sequence of nested sexps and produce a sequence of all of them, eg: (f '((foo (bar baz)))) => ((foo (bar baz)) (bar baz))

9:15 the-kenny: pandeiro: check clojure.walk

9:16 doright: My guess is recruiters write scala on their job offers because it's sooooo enterprise.

9:16 doright: 10 of these jobs include other languages in the title so 7 are exclusively Clojure, cf. Scala:297 and Groovy:42

9:16 pandeiro: the-kenny: yeah i don't see how to accumulate the result w/ walk

9:16 the-kenny: aside from using them for side effects w/ an atom

9:18 the-kenny: pandeiro: hm. clojure.core/tree-seq then maybe?

9:19 ,(rest (tree-seq sequential? seq '((foo (bar baz)))))

9:19 clojurebot: ((foo (bar baz)) foo (bar baz) bar baz)

9:21 the-kenny: now throw away non-lists and bingo

9:21 pandeiro: the-kenny: nice, thank you

9:22 irctc__: Hi everybody. How can i union a seq/list of sets? (union '(#{1}) #{1})

9:22 sorry... like this one (union '(#{1} #{1})

9:22 the-kenny: ,(apply union [#{42 23} {1 2 3 42}])

9:22 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: union in this context, compiling:(NO_SOURCE_PATH:0:0)>

9:22 the-kenny: ,(apply clojure.set/union [#{42 23} {1 2 3 42}])

9:22 clojurebot: #<CompilerException java.lang.ClassNotFoundException: clojure.set, compiling:(NO_SOURCE_PATH:0:0)>

9:23 the-kenny: damn you clojurebot

9:23 AimHere: ,(apply clojure.set/union [#{42 23} #{1 2 3 42}])

9:23 clojurebot: #<CompilerException java.lang.ClassNotFoundException: clojure.set, compiling:(NO_SOURCE_PATH:0:0)>

9:23 irctc__: great! thanks!

9:23 the-kenny: irctc__: either apply or reduce, a matter of taste. I prefer reduce when the size of the input list is unknown.

9:25 AimHere: whoops, just noticed the missing # in my code.

9:26 AimHere: Didn't do much good, as far as clojurebot was concerned

9:27 the-kenny: yeah, no difference here.

9:29 vas: ,(apply hash-map [:a 5 :b 6])

9:29 clojurebot: {:b 6, :a 5}

9:29 vas: ,(reduce hash-map [:a 5 :b 6])

9:29 clojurebot: {{{:a 5} :b} 6}

9:29 the-kenny: it doesn't work for all functions, that's obvious

9:52 hyPiRion: If you have a function on the form (fn f ([a] (f a init-val)) ([a b] ...)), is it more idiomatic to put the `b` arg at the end or in the front?

9:52 Assuming that people are unlikely to use the two-ary version on a daily basis

9:56 seancorfield: hyPiRion: I think I would expect ((f x) y) == (f x y) so b should be at the end... But I know there are sometimes good reasons for not doing that (I think there are core fns like that?).

9:59 hyPiRion: seancorfield: yeah, the sort-functions in core is probably doing that to keep the coll at the end like map and friend does

9:59 It won't be used in that setting though, so I guess it makes more sense to just put it at the end

9:59 * hyPiRion stops bikeshedding and gets to work

10:02 seancorfield: Yeah, the "coll arg last" idiom is a good reason for ((f x) y) to be (f y x) :)

10:16 ambrosebs: how do I tell lein which project.clj to use without cd'ing into it?

10:16 I want to run the tests of some subfolder in a Makefile

10:18 Glenjamin: sh -c "cd subfolder && lein test" ?

10:18 not really what you asked, but should work

10:20 ambrosebs: Glenjamin: thanks :)

11:02 zling: earnestly

11:14 justin_smith: doright: maybe not be a lisp?

11:15 ambrosebs: you can use cd in make commands

11:15 I typically use a pushd / popd combo though

12:14 Guest40845: Hey there, off topic question but can I PM someone who has experience leaving a software project written by a very small team or you're the only guy on the team? Trying to make a career move and I don't want to hurt the company I'm with…

12:33 justin_smith: Guest40845: I've done a handoff before. Leave detailed comments describing what each file is for, and add an overview tying all of them together in the README. Also, be sure that the README has a description of how to build, run, deploy that can be followed by the letter without any implicit steps

12:41 Guest40845: justin_smith: mind if i pm?

12:43 justin_smith: go ahead, sure

13:02 dnolen: ClojureScript 0.0-2913 released, Google Closure Modules, and better underlying architecture for supporting nREPL https://groups.google.com/d/msg/clojurescript/n_8WHnlcOGI/1kmATGABVi0J

14:19 underplank: Hi all im trying to instansiate a java ProcessBuilder class like so

14:19 orochi.core.api=> (ProcessBuilder. 'python')

14:19 IllegalArgumentException No matching ctor found for class java.lang.ProcessBuilder clojure.lang.Reflector.invokeConstructor (Reflector.java:183)

14:19 Any idea why?

14:21 apparently it doesnt have a constructor? or something?

14:25 i-blis: underplank: try (ProcessBuilder. (list "python"))

14:25 kriyative: @underplank -- did you mean "python" with double-quotes?

14:25 underplank: I meant a string of “python”

14:25 i-blis: underplank: the constructor takes a list

14:26 underplank: i-blis: huh. it also looks like it take a string. but, thats cool. I could be looking at an old api

14:26 yup. using a list works. thanks!

14:27 i-blis: :)

14:27 underplank: yeah I should look at the version of the docs I am looking at. Apparently back in Java 1.5 you could ue a string.

14:27 :)

14:28 thanks i-blis !

14:31 csd_: Are any of you running CIDER 0.9.0-snapshot?

14:32 i-blis: you're welcome underplank

14:34 csd_: went back to 0.8.2 a week or so ago : did jack in but did not eval code

14:34 csd_: i-blis: i can't jack in.. gives me a class path error

14:35 i-blis: csd_: use stable :)

14:35 csd_: yeah :-/

14:35 justin_smith: underplank: ProcessBuilder takes either varargs string, or list of string. It turns out that via clojure you need to provide either a list, or a String-array because varargs are a java compiler thing and don't exist on a vm level

14:36 i-blis: csd_: or do you absolutely need boot support?

14:36 underplank: ahhh, right. that makes sense. So when they say “String” in the constructor, thats not actually what that means :)

14:36 csd_: i had been using the snapshot for a while because of a bug i'd run into a while back

14:37 its just sort of annoying because i get packages from the "non-stable" branch of MELPA but this is the one thing ill have to have to get from the stable branch

14:37 i-blis: 0.8.2 seems pretty stable

14:38 csd_: you can pin the package

14:38 vas: so I end up with some enlive vectors that look like: [{nodes}] and [{nodes}] .... how do you combine two vectors? (am i right in calling them vectors because they're in square brackets?)

14:38 csd_: i-blis: awesome

14:38 vas: ( ideal result is just sequential [{nodes}, {nodes}] )

14:39 kriyative: i-blis: how do you pin packages from MELPA? I switched to el-get just for that ability.

14:39 i-blis: csd_: (add-to-list 'package-pinned-packages '(cider . "melpa-stable") t)

14:40 kriyative: i-blis: good to know, thanks.

14:41 i-blis: csd_: provided you added melpa-stable to packages-archives, igws

14:44 vas: huzzah for concat.

14:44 * kriyative

14:46 csd_: i-blis: looks like MELPA-stable has 0.7.0 latest

14:48 i-blis: csd_: are you sure you're using stable.melpa.org?

14:48 csd_: positive

14:48 i-blis: http://stable.melpa.org/#/cider has 0.8.2

14:48 csd_: weird, thats not what Packages shows

14:49 i-blis: csd_: emacs 24?

14:49 csd_: no, 25

14:49 i-blis: well, shouldn't be the issue

14:50 csd_: oh wait i think i have a syntax in my emacs config

14:50 err a syntax error

14:51 i-blis: do you have : (add-to-list 'package-archives

14:51 '("melpa-stable" . "http://stable.melpa.org/packages/&quot;) t)

14:52 csd_: i-blis: there we go :)

14:52 thank you

14:53 i-blis: csd_: you're welcome

14:54 csd_: one of those times where you go to do some work and unexpectedly waste a half hour tooling :-/

14:56 gfredericks: does anybody know how to throw this exception via normal clojure usage (i.e., without interopping in the Var class)?

14:56 https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Var.java#L218

15:05 i-blis: gfredericks, why not: (throw (java.lang.IllegalStateException.))

15:12 gfredericks: i-blis: I'm more asking about how to get to that line of code

15:12 I want to know if it's even possible

15:15 amalloy: gfredericks: (binding [x 1] (.start (Thread. #(set! x 2)))) maybe?

15:17 i-blis: gfredericks: I am not sure I understand, you want to throw an exception as if a var was set outside its thread?

15:18 gfredericks: amalloy: if it's not bound on the new thread then you'll just get a normal can't-set!-a-var-without-a-thread-local-binding

15:18 i-blis: yep; based on my understanding that line should be unreachable, trying to figure out if there's anything I'm missing

15:27 justin_smith: gfredericks: is it that you got that exception and want to know how it could have happened?

15:27 kryft: What would be the best way to ensure that a function can't be called if a call to that function is currently in progress? So basically a simple lock

15:28 justin_smith: kryft: wrap the function body in a call to locking?

15:29 ,(defn locked [x] (locking locked (inc x)))

15:29 clojurebot: #'sandbox/locked

15:29 justin_smith: it locks on itself

15:29 ,(locked 1)

15:29 clojurebot: 2

15:29 kryft: justin_smith: Ok, that seemed to be the solution based on some quick googling, but it was usually accompanied by "you should rarely need to use locking" :)

15:29 justin_smith: So I thought I'd check that there isn't a more idiomatic way

15:29 justin_smith: kryft: well, why is it that the function needs to be locked?

15:29 the more idiomatic way is not to need locking at all :)

15:29 amalloy: kryft: well indeed you should rarely need to do this

15:30 justin_smith: kryft: usually we use immutable data structures so that locking is irrelevant

15:30 gfredericks: justin_smith: nope have never got it as far as I know

15:30 just wondering if it's dead code or not

15:30 justin_smith: gfredericks: ahh, I misunderstood then

15:30 OK

15:31 kryft: amalloy: of course when interacting with an external system we sometimes lose some of the tidiness that immutability offers, and locking is sometimes needed

15:32 kryft: but for example if your algorithm assumes locking and is 100% clojure, there is probably a nice immutable lock-free way to do it

15:32 kryft: justin_smith: Well, my app sends emails every now and then, and it keeps emails in a postgresql DB (with a lot of other data). The function in question fetches unsent emails and tries to send them.

15:32 justin_smith: and the locking is because you don't want emails sent more than once?

15:32 kryft: justin_smith: Right.

15:32 amalloy: kryft: well you have a whole database to work with! databases are great at lokcing

15:33 justin_smith: kryft: clojure doesn't have implicit paralellism - if you don't do the task from multiple threads or instances, you won't need to worry about that

15:33 amalloy: add a column "trying_to_send_right_now", and set that to true when you take it out, for example

15:33 locking will only work inside one jvm, but if you put the lock in the database it will scale to any number of servers later on

15:34 justin_smith: that's a good point too, but I still think it's easier to just ensure that only one thread in one instance is email sending. It's not as if email sending is a bottleneck that you need to parallelize for performance in most cases.

15:36 kryft: justin_smith: Currently the sending could be triggered from multiple threads - basically I try to send as soon as I add a new email to the table. The table is there mostly to keep track of what's been sent and because it's naturally possible that sending could fail.

15:37 justin_smith: kryft: OK. My approach would be to have a single thread responsible for sending emails, perhaps offering a queue that other threads could put emailing tasks onto.

15:38 kryft: though perhaps there is some other factor that makes emailing from arbitrary contexts advantageous?

15:39 kryft: justin_smith: Not really - I just want to make sure they get sent relatively quickly (for example, a user registers and gets a confirmation immediately)

15:39 justin_smith: in general I find if something needs to be done exactly once, having exactly one thread in charge of it is helpful

15:39 kryft: justin_smith: So I'm sure a single thread would work.

15:40 justin_smith: you could also use core.async instead of a thread and a queue, if you find other places where core.async would be useful

15:40 anyway, this eliminates the need for locking logic, because that single thread of execution (or logical thread of execution in the core.async case) can reliably track what has and hasn't been done

15:41 since it is syncronous in its own context

15:42 kryft: justin_smith: Right, sounds good. It didn't occur to me to have an explicit thread for that.

15:43 amalloy: I considered using the DB for this, but I wasn't sure that it could be done without using DB locks (which clojure's jdbc interface doesn't seem to support)

15:43 justin_smith: another (mostly equivalent) option is to use an agent, and store the emailed addresses in the agents, sending it a function that sends an email if it hasn't been sent yet

15:44 s/agents/agent

15:44 kryft: amalloy: (I'm fairly new to postgresql too, so I may well be mistaken :)

15:44 It's my first backend, my first DB application, and my first clojure app! :P

15:44 justin_smith: best of luck!

15:49 kryft: justin_smith: Thanks!

16:05 justin_smith: For the "single responsible thread" approach, did you mean having a function regularly polling the queue and sending emails whenever there's something in there, or something fancier?

16:05 justin_smith: kryft: no need to poll even, just blocking read on the queue in a loop

16:07 kryft: justin_smith: Ah, right

16:07 justin_smith: kryft: so, if you use java.util.concurrent.BlockingQueue it would be a .take operation

16:07 (rather than .poll, which has a timeout)

16:09 and then .put for synchronous adding to the queue (but not synchronous waiting for it to be consumed)

16:14 kryft: justin_smith: Ah, nice (I was trying to find a structure like that in clojure)

16:14 justin_smith: kryft: there is clojure.lang.PersistentQueue

16:15 ,(let [q clojure.lang.PersietentQueue/EMPTY q' (conj q :a)] (into [] q'))

16:15 clojurebot: #<CompilerException java.lang.ClassNotFoundException: clojure.lang.PersietentQueue, compiling:(NO_SOURCE_PATH:0:0)>

16:15 justin_smith: oops

16:15 ,(let [q clojure.lang.PersistentQueue/EMPTY q' (conj q :a)] (into [] q'))

16:15 clojurebot: [:a]

16:15 justin_smith: but in that case you would want to put it inside an atom, ref, or agent

16:16 kryft: Right

16:18 justin_smith: Thanks again; I guess I'll just use a BlockingQueue here, but good to know that PersistentQueue exists

16:19 justin_smith: also, as I mentioned before, core.async is a mini language around channels, that are effectively queues

16:19 but it may be a bit much if you only need that kind of flow in one place

16:24 kryft: justin_smith: Yeah, that's probably overkill here; all other concurrency issues are basically handled by JDBC transactions. Also core.async seems to be in alpha at the moment?

16:37 justin_smith: kryft: alpha, but widely used

16:38 kryft: justin_smith: A bit like prismatic/schema then :P

16:42 justin_smith: I think it's wider deployed than schema though, I've had it in production a couple of instances myself

16:42 Graawr: hey ! is there a "pure clojure" (i.e. without wobbly java interop) way to extract a directory from the currently running jar ? I'm currently coming up with a direct translation of a java snippet using JarFIle & JarEntry, but it really feels wobbly

16:43 justin_smith: Graawr: in general, clojure core doesn't abstract very far from the host for IO stuff. That lib may exist out there somewhere though.

16:44 csd_: can someone please look at this core.async snippet and tell me what i'm missing? i would expect 42 to be printed https://www.refheap.com/97625

16:48 Graawr: justin_smith: okay, so I better keep going then. I'm translating this answer ( http://stackoverflow.com/questions/1529611/how-to-write-a-java-program-which-can-extract-a-jar-file-and-store-its-data-in-s/1529707#1529707 ) to clojure, although I'm lost at getting an input stream : (.getInputStream (jar-file jar-entry)) always returns nil

16:50 justin_smith: and jar-file is a java.util.jar.JarFile?

16:50 Graawr: yup

16:50 and jar-entry is a java.util.jar.JarEntry

16:50 justin_smith: oh, the code there calls getInputStream on jar-file

16:51 not on the entry

16:51 err wait

16:52 Graawr: whoops, typo: (.getInputStream jar-file jar-entry) returns nil (there's no nesting)

16:52 justin_smith: so, I would expect this to work: (.getInputStream (java.util.jar.JarFile. "some/path/to.jar"))

16:52 why the extra arg?

16:52 the stream is the jar, not some entry in the jar

16:52 wait...

16:53 ok, so file is a java.io.File

16:53 you get an inputstream from the file

16:54 sorry, I'm all mixed up on this, I'm backing out for a moment

16:54 Graawr: oh okay, thank you !

17:00 justin_smith: Graawr: my java is rusty - would the continue in that first if statement skip the rest of the body and start the next step of the while loop?

17:01 because if the first thing you got was a directory, I could see getInputStream returning nil if you did not replicate the continue logic

17:01 maacl: Help oh help, just upgraded my emacs packages and now I don't get a repl buffer when I do cider-jack-in or cider-connect

17:02 justin_smith: maacl: delete your elc files and restart emacs

17:02 cider tends to not upgrade cleanly

17:03 Graawr: justin_smith: yes, the continue will skip the current loop interation

17:03 maacl: justin_smith: Ok, will give that a try.

17:04 Graawr: justin_smith: but I get a nil from getInputStream whatever the input (file or directory jarEntry)

17:08 maacl: justin_smith: Thanks, that did the trick.

17:08 clojurebot: Huh?

17:08 justin_smith: maacl: np, it should really be in the cider docs

17:11 Graawr: so I made my own attempt to translate it, mostly just to help me read it

17:12 Graawr: the error I run into is that I get entries that belong in a specific directory, but not an entry representing the directory itself

17:12 (so of course it can't write to it, the directory has not been made yet)

17:13 Graawr: d'oh, and now I read the comments!

17:14 Graawr: would it be instructive to show you my translation that works, or would you rather sort it out yourself?

17:14 Graawr: justin_smith: I'd like to see your version if that's okay, I'm still a bit struggling halway through mine

17:15 justin_smith: of course I had to pick a jar that had more than 2800 files in it to test with...

17:15 OK

17:16 Graawr: this is a direct translation (taking into account the comments about .getParentFile) and it works https://www.refheap.com/97626

17:16 Graawr: justin_smith: although I believe that fixing the fault reported in the comments shouln't be hard with raynes fs utilities, IIRC there's a function to make parents dirs if they don't exist

17:16 justin_smith: no need for any libs for this

17:16 getParentFiles is trivial

17:16 *getParentFile

17:16 Graawr: oh right

17:17 justin_smith: also, I changed the system separator to "/" because that works even on Windows

17:17 Graawr: ah, didn't know that

17:17 hum

17:17 I see you don't use enumeration-seq on the entries ? I thought it was needed

17:17 justin_smith: and I am quite reluctant to use system separator (perhaps superstitiously) after dealing with network code that tried to put system separator in a URL

17:18 Graawr: that's not a call, that's just a type

17:18 err... wait

17:18 why would I need enumeration-seq?

17:19 Graawr: nevermind, that was an artefact from a previous try where I got confused by the Enumeration class used

17:19 justin_smith: Graawr: oh, I get it. Since I am not using clojure sequence functions, I don't need to use enumeration-seq.

17:20 Graawr: yup

17:20 justin_smith: I directly converted the while into a while, instead of making it a doseq over a seq - which could have been cleaner, but I was in "zero brain translation" rote mode

17:20 Graawr: though if I wanted to use seq (like using a loop/recur with (first ...) and (rest ...)) it would be needed right ?

17:20 justin_smith: Graawr: I wouldn't use loop/recur - enumeration-seq + doseq

17:21 Graawr: oh

17:21 justin_smith: loop / recur with first / rest can almost always be translated into something higher level

17:24 Graawr: hum, yes, i've still not really wrapped my mind around higher-level looping structure besides map/reduce kinds

17:24 justin_smith: Graawr: you might find it a nice exercise to translate the while into a doseq / enumeration-seq combo, and/or replacing the innermost let with a with-open call on the two streams

17:26 Graawr: that's exactly what i'm experiencing ^^

17:28 by the way, as I'm extracting from a running jar, I use the (-> (class *ns*) .getProtectionDomain .getCodeSource .getLocation .getPath) to get the path of the running jar, but it, here again, seems a bit wobbly. Isn't there any standard tool to reference the running jar ?

17:28 justin_smith: also, I bet it could be at least 10x as fast if you added a byte-array for read, instead of reading one byte at a time

17:28 Graawr: what you have there is how I would do it

17:28 Graawr: what's the end goal? do you need the files to be on disk to use some OS utility on them?

17:28 Graawr: hum, I have to say my java IO was fairly brief, I might need to look further into bytes array for writing

17:29 justin_smith: Graawr: it's an alternate read method, takes a byte array for filling

17:29 and then of course instead of writing one byte, you would write as many bytes from the array as you read (the return value of read will tell you how many)

17:30 and write, of course, has an alternate method that takes a byte-array to write from

17:31 Graawr: justin_smith: no, i'm building a transcompiler for a school project; I convert a directory structure containing notes took in a given language into a local, static website, so I need to copy the default assets (in jar at runtime) to disk

17:32 Raynes: People keep telling me to rewrite refheap in node.

17:32 justin_smith: Graawr: OK, you may or may not be aware that we can use clojure.java.io/resource to get file contents from a jar without writing anything to disk

17:32 Raynes: I'm incredibly entertained by this, given that the one single lone reason for folks using refheap is because it's written in Clojure

17:32 Because everyone has it in their head that "Hey, I can contribute to this in my favorite language!"

17:33 But then they never contribute to it.

17:33 justin_smith: Raynes: nah, I use it because it isn't spammy and it syntax highlights with a dark background

17:33 Raynes: I need to rewrite it

17:33 rhg135: nah, same here

17:33 Raynes: Not in node, but in Clojure.

17:33 Graawr: justin_smith: yes, but as I generate a static site, some assets (js, fonts, css) need to be on disk for the final "product" to be used by the end user

17:33 Raynes: justin_smith: So I should revert this commit to add interstitials?

17:33 justin_smith: Graawr: aha, so you aren't serving the stuff from a clojure web server


17:33 haha

17:34 Raynes: git branch -D piss-off-justin-smith

17:34 gf3: We should rewrite refheap from the ground up with you designing.

17:34 Graawr: justin_smith: no, that's entirely local. The point is just to pass a lectures notes directory to the software, and it spits back a static site

17:34 Raynes: We'll use Graawr's static site generator.

17:34 We'll just regenerate it every time someone makes a paste.

17:35 justin_smith: Graawr: ahh, got it

17:35 Raynes: In all seriousness, it might be fun to rewrite the whole thing with cljs

17:35 Client side 4evr

17:35 justin_smith: http://i.imgur.com/aJwbNM4.jpg

17:36 Raynes: yes

17:36 rhg135: Raynes, how would the api work if it ran client-side?

17:36 Raynes: How would anything work fi it ran client side?

17:36 There'd still be a server component.

17:37 justin_smith: rhg135: the one benefit I can think of is it could push edits when people update the paste

17:37 Raynes: But the server would probably just become an API service.

17:37 justin_smith: perhaps even a UI to see revisions

17:37 rhg135: ah ok, and that'd stay the same i assume?

17:37 Raynes: The API is shitty, so I'd probably change it too

17:37 rhg135: i find it pretty simple

17:37 Raynes: I can add a compatibility layer :P

17:38 rhg135: GET to /posts/:id get response

17:38 Raynes: Oh, that'd still work

17:39 rhg135: i'm curious what you mean by a new api.

17:40 justin_smith, push is always win imo in web design

17:40 Raynes: rhg135: I mean, the problem with the current API is not really the API itself, but how it's written

17:40 See, I didn't know a damn thing about web development.

17:40 The API is entirely distinct from the interface.

17:40 They hardly even use the same code

17:40 It's so ridiculous.

17:40 The web interface should be using the same API

17:41 rhg135: oh I see, Raynes. So maybe some feature expressions if you go cljs?

17:41 Raynes: 'feature expressions'?

17:41 Maybe I still don't know shit about web development.

17:41 Damn it.

17:41 I need to stop writing websites

17:41 ;)

17:42 rhg135: being able to share code server-side with client-side

17:42 Raynes: I see

17:42 I don't know what state of the art in cljs client-server communication is

17:42 But I hope there is some good shit available

17:42 I'm spoiled by Meteor

17:42 Where it's all so seamless

17:42 justin_smith: Raynes: feature-expressions are all liek "this code only works in js" "this other code only works in the jvm" but it's all still in one file

17:42 rhg135: websockets i hear are useful for this

17:43 Raynes: Yeah, websockets are the answer but I don't want to deal with them directly. I imagine there's a bunch of cljs stuff that already deals with htis.

17:43 If not, I'll come back in a few months when there is :P

17:43 rhg135: or even ajax

17:43 Raynes: http://hoplon.io/

17:43 Like this

17:44 rhg135: the goal is to minimize the synchronization from client to server

17:45 Raynes: It should all be pretty simple

17:46 rhg135: i don't do any web dev either

17:46 Raynes: I do web dev, but usually single page apps.

17:46 rhg135: but i've read being able to share code--like nodejs--is a boon

17:47 so clj(s) is nice

17:47 Raynes: I've been doing a lot of ES6/Coffee lately.

17:47 I don't share the same furious hatred for JS that others do.

17:48 rhg135: i've done Coffee just because i cba to remember js's quirks

17:48 justin_smith: shall we burn the heretic, stone him, or simply force him to live with his corrupted and sad decisions?

17:48 Raynes: I mean, coffee shares those quirks.

17:48 rhg135: it's a fine language if you know it, and I don't

17:49 Raynes: Coffee is just a js preprocessor, really.

17:49 rhg135: Raynes, but less

17:49 Raynes: ES6 is pretty cool too

17:49 rhg135: it is which is great

17:49 justin_smith: rhg135: it was written in like a week, you can learn the important aspects in less time than that

17:49 Raynes: I'm furious they didn't add a thin arrow with their fat arrow.

17:49 rhg135: ive been out of the js loop since before es6 existed

17:49 well it did just not practically

17:50 justin_smith, i could, it's the context switches in my mind I'd have to make going back to another lang

17:51 Raynes: ES6 offers: a module system, => fat arrow functions that pass the this context in, potentially comprehensions...

17:52 rhg135: i didn't feel like running a development nodejs build

17:52 Raynes: babeljs.io

17:52 rhg135: or using that lol

17:52 Raynes: https://github.com/Raynes/barrelroll

17:53 Currently writing a thing with it

17:55 oshi

17:55 There's a new Clojure build tool?

17:55 * Raynes shakes with fear

17:55 rhg135: why be afraid?

17:56 justin_smith: I don't know how mature boot is

17:56 rhg135: not like they can't speak to each other

17:56 they both produce jars

17:59 Raynes: I wrote small very small portions of leiningen

17:59 I'm emotionally attached

17:59 rhg135: i like leiningen; it makes it easy for clj

17:59 cljs otoh is a pita

18:12 thsig: Hey guys, I'm about to start a web app project which I expect will eventually be quite full-featured - do people here prefer ring or pedestal or something else for such cases? Is ring mostly preferred for smaller apps, or is it most popular in general?

18:13 I.e. is ring preferred for smaller, simpler apps, and are other methods preferred for bigger/more complex apps? Or is it a good fit for the whole spectrum?

18:16 justin_smith: thsig: unless you have a really compelling reason, ring is the best bet

18:16 almost everything else (with rare exceptions like pedastal) uses ring

18:18 thsig: justin_smith: Thanks for the feedback! I'm coming at this from ruby land, having mostly used clojure for non-web stuff, so I was wondering how apt the analogy "ring ~ sinatra" was.

18:18 since in ruby, one ends up adding a lot of the stuff from rails back on to sinatra as the requirements get more complex

18:19 justin_smith: thsig: I wouldn't compare ring to sinatra, no

18:19 thsig: but of course clojure is different, just trying to get a feel for the web library landscape

18:20 justin_smith: thsig: if anything I would compare compojure to sinatra, but in the clojure world we tend to do things very modular

18:20 you can easily use ring without compojure

18:21 thsig: justin_smith: Ok, I see. I guess ring is more like rack.

18:21 there's a lot of stuff that comes along with rails that I've never used or liked

18:21 justin_smith: yeah, that's a much closer comparison

18:21 thsig: and now that I'm experienced I like the idea of picking just what I need

18:21 justin_smith: yeah, that's the norm in clojure

18:23 thsig: justin_smith: Thanks again for responding, I'll keep working through my checklist of libs that I need - looks like the ecosystem is pretty solid these days.

18:24 justin_smith: in my experience you can start with the libs you need for your basic functionality, and add more as you need them. We don't really do "frameworks" that demand you structure your entire app differently, for the most part

18:25 * gfredericks creates a new framework called justputallyourfilesrighthere

18:25 justin_smith: heh

18:28 gfredericks: ,(def a-million (bit-shift-left 20 1))

18:28 clojurebot: #'sandbox/a-million

18:29 justin_smith: ,a-million

18:29 clojurebot: 40

18:34 underplank: So im using stuart Sierras component for an compojure app. I dont need to store any state durably (ie db or anything). And I need to access the state in each ring handler. So I’ve manged to pass the component defrecord into the handler, but of course when I update it I get a new version and need to somehow return the new value of the component.

18:34 example code https://www.refheap.com/97630

18:37 justin_smith: so every time a client hits create-proxy you would rebuild your whole system? that seems a bit silly

18:38 why not update an atom containing proxies?

18:39 otherwise you have a topological problem, as you've noticed, where the handler that creates your response also wants to return a new component

18:39 underplank: Sorry. the code is slightly wrong. So I have an Api component. And a Controller component. the controller component sits inside the Api component. When I add a proxy its supposed to add to the Controller component

18:40 I was thinking that the reference to the Controller component inside the Api Component needs to be an atom? and then I can update that at will.

18:40 and the Api component doesnt need to be replaced.

18:40 justin_smith: right. Or you can do something more convoluted where you both return the response and the potentially updated component, and then sort out that logic at a higher level of the code

18:41 but that seems like it would get a little messy without much benefit

18:43 underplank: yeah. I think I had already put in place the seperation of the API which is just poking the controller. So atom in the Api it is. thanks justin_smith !

20:11 maacl`: Does anyone know if it is possible to get popup documentation with CIDER and company completion?

20:13 justin_smith: yes, it is possible

20:14 arrdem: supposedly it'll "just work" if you have company turned on

20:14 hasn't worked for me in a while

20:14 justin_smith: that was my experience a while back, but I wouldn't be surprised if something broke at aome point

20:14 maacl`: justin_smith: Ok, is there anything I have to do to enable it? Completion works, but I am not getting any documentation

20:15 justin_smith: I'm not really sure, I just know I have had it working in the past

20:15 maacl`: justin_smith: ok

20:16 arrdem: #clojure-emacs may be able to help, but that's a pretty quiet channel. If it isn't in the CIDER docs, it's presumed to "just work" and you should probably open a ticket.

20:22 maacl`: arrdem: Thanks, I have raised a ticket.

20:23 arrdem: clojurebot: rejoice

20:23 maacl`: thanks.

20:23 maacl`: FWIW cider-grimoire still totally works, not that I'm biased or anything :P

20:55 doright: How do I convert, for example, "String" to a parameter of the (class ....) function?

20:55 arrdem: doright: what are you trying to achieve? resolve the class named by a string?

20:56 doright: arrdem: (defn get-meths [class-name] (for [meth (.getDeclaredMethods (class class-name))] (println (.getName meth))))

20:56 (defn get-meths [class-name] (for [meth (.getDeclaredMethods (class class-name))] (println (.getName meth))))

20:57 arrdem: With (import 'java.lang.reflect.Method)

20:58 Bronsa: doright: given that you call (class ) on class-name you're going to need an instance object of that class

21:02 doright: Bronsa: Not really. This works: (let [mths (.getDeclaredMethods (class String))] (for [m mths] (println (.getName m))))

21:02 Bronsa: ,(class String)

21:02 clojurebot: java.lang.Class

21:02 Bronsa: doright: that's likely not what you want

21:03 doright: Bronsa: Why? It lists all the methods, like I asked.

21:03 Bronsa: doright: it lists all the methods of Class not String

21:04 doright: Bronsa: Ah, will have another look :)

21:04 arrdem: I'll leave you in Bronsa's more classloader-informed hands

21:04 Bronsa: doright: what is exactly that you want get-methods to do?

21:05 get-meths, rather

21:06 doright: Bronsa: Should have been: (let [mths (.getDeclaredMethods (class (String.)))] (for [m mths] (println (.getName m))))

21:07 Bronsa: doright: what's the input to your function and what's the desired output?

21:07 doright: Bronsa: I don't think it's do-able but pass in a class name such as String or URL.

21:08 Bronsa: doright: as a string?

21:08 doright: Bronsa: (class (classname.)) [pseudo-code] looks even less likely

21:08 Bronsa: Yes, as a string.

21:09 Bronsa: S'pose core.typed might come in handy here.

21:10 Bronsa: I'm just playing with Java interop, that's all, as a learning exercise.

21:11 Bronsa: doright: this is how it should be written then: http://sprunge.us/BUGY?clj

21:11 doright: Bronsa: There's a long-winded Java example of getting all the methods of a class so thought I'd have a go in Clojure.

21:12 Bronsa: Marvelous. I'll go study that one. Thanks.

21:12 Bronsa: doright: that assumes your class-name string represents either an imported class or a fully qualified class name. Not sure why you can't just pass the class directly but that's how to do it with a string

21:12 doright: also note that for is lazy, when you need to perform side-effects you should use doseq

21:15 doright: Bronsa: (symbol "class-name-string") was what I needed.

21:16 Bronsa: doright: not really, (symbol "String") returns 'String as a symbol, not the String class

21:16 ,(class (symbol "String"))

21:16 clojurebot: clojure.lang.Symbol

21:16 doright: Bronsa: Maybe I could have passed it directly after all.

21:16 Bronsa: ,(class String)

21:16 clojurebot: java.lang.Class

21:16 Bronsa: doright: in that case http://sprunge.us/cOTN?clj and you can invoke it as (get-meths String)

21:19 doright: Bronsa: ^Class is a type hint?

21:19 Bronsa: yes

21:19 doright: Bronsa: Then that's what I was missing. Learned a lot, thanks.

21:20 Bronsa: doright: note that type hints only affect performances, they don't change the semantics of the code

22:40 justin_smith: ,(Class/forName "String")

22:40 clojurebot: #<ClassNotFoundException java.lang.ClassNotFoundException: String>

22:40 justin_smith: ,(Class/forName "java.lang.String")

22:40 clojurebot: java.lang.String

23:31 julianleviston: Which is more idiomatic, do you think? (into {} (filter pred m)) or (select-keys m (filter pred (keys m))) ?

23:32 justin_smith: julianleviston: the latter only gets to filter based on the keys...

23:32 but regardless, the former is nicer

23:32 julianleviston: yeah, that’s what I’m trying to do - filter on keys with a predicate...

23:32 justin_smith: why is it nicer, in your opinion?

23:32 justin_smith: less noise

23:33 julianleviston: justin_smith: this is the predicate: #(keyword? (key %))

23:33 well, for the first one

23:33 justin_smith: (comp keyword? key)

23:34 julianleviston: justin_smith: actually I think you’ve answered my question… the second is better because it explains the intent more.

23:34 justin_smith: anyway, the into/filter is a more straightforward combo to my eyes, compared to select keys / filter / keys

23:34 OK

23:34 julianleviston: what I *really* want is a function select-keys-filter, so maybe I’ll go write that.

23:34 or something with a less ugly name

23:35 justin_smith: I guess that’s probably because the into/filter is more lazy.

23:35 justin_smith: damn clojure and its messy laziness :)

23:35 justin_smith: so, because it’s more lazy, it’s doing less work… :) right? that’s why you intuitively reach for it?

23:36 justin_smith: into isn't lazy

23:36 julianleviston: justin_smith: and I guess wrapping it in a function will name my intent, so convey the sematics better?

23:36 justin_smith: isn’t reduce lazy?

23:36 justin_smith: no

23:37 julianleviston: justin_smith: but it uses a transducer, doesn’t it?

23:37 justin_smith: I thought transducers were

23:37 justin_smith: I guess that’s only if you compose them, then their effect is lazy… hm...

23:37 justin_smith: nope, they are agnostic to laziness for the most part

23:38 the thing using them gets to decide if it is lazy or not

23:38 julianleviston: justin_smith: but if you compose two or more transducers, then the net effect is laziness of function application, isn’t it?

23:38 justin_smith: so a reduce on a transducer is eager, a sequence on a transducer can be lazy

23:38 absolutely not

23:38 julianleviston: guh.

23:38 that’s a bit sucky

23:38 justin_smith: what does lazy function composition even mean?

23:39 julianleviston: justin_smith: no, lazy application

23:39 justin_smith: OK, sequence on a transducer is lazy

23:39 julianleviston: justin_smith: if you compose two functions, and one of them is early aborting as in the case of filter, then its effect is laziness

23:39 justin_smith: reduce isn't

23:39 the transducer is neither lazy nor not lazy

23:39 julianleviston: justin_smith: yes, I know… but the fact that it can be means it is when it can be.

23:39 justin_smith: aborting early is not the same as laziness

23:39 reduce can return early, and is not lazy

23:40 julianleviston: justin_smith: hm… I guess we have different definitions then

23:40 justin_smith: reduce can have a filtered mapping as it's input, it's still going to be eager

23:40 julianleviston: justin_smith: eager meaning it gets all of its arguments before starting?

23:40 justin_smith: right?

23:40 justin_smith: early return isn't lazy, because it is never going to do the hypothetical work that followed - no work is delayed

23:41 julianleviston: justin_smith: yep. cool.

23:41 justin_smith: eager meaning it fully calculates its result when called

23:41 julianleviston: yep tho if the work IS INSIDE the transducer, not outside it, it *is* lazy… as in… lazy application… not lazy evaluation.

23:41 justin_smith: know what I mean?

23:41 justin_smith: absoluttely not, no, that makes no sense to me

23:41 the transducer is neither lazy nor not-lazy

23:42 it's a transduce

23:42 something lazy or eager can use it

23:42 julianleviston: justin_smith: lazy function application means you don’t apply the function across the whole thing if you don’t have to…

23:42 justin_smith: lazy usually just means the arguments are evaluated before the function begins.

23:42 justin_smith: are you talking about eagerly consuming args? that's not the same as laziness.

23:42 or lack thereof

23:42 julianleviston: justin_smith: hehe :) as I said, we have different definitions of lazy application here.

23:42 justin_smith: (first x) does not fully realize its input. It also is in no way lazy.

23:43 julianleviston: justin_smith: and yes… call it eager consumption, if you like.

23:43 justin_smith: julianleviston: your definition of lazy is not used anywhere in clojure

23:43 ddellacosta: julianleviston: it seems like you are redefining terms idiosyncratically, which does no one any good

23:43 julianleviston: no not at all.

23:43 I explicitly said lazy function application, not lazy evaluation.

23:43 justin_smith: there is no such thing as "lazy function application" in clojure

23:43 ddellacosta: what is the difference between application and evaluation?

23:44 julianleviston: ddellacosta: (apply + [1 2 3]) versus (+ 1 2 3)

23:44 justin_smith: what he means by his invented term "lazy function application" is that the args are not greedily consumed

23:44 ddellacosta: and, if it exists, please point us to some literature where this terminology is used

23:45 julianleviston: ddellacosta: it’s the difference between eval and apply, isn’t it?

23:45 ddellacosta: julianleviston: those two are exactly the same in terms of how they are evaluated. There's nothing "lazy" going on here

23:45 julianleviston: justin_smith: yeah! :)

23:45 ddellacosta: so we are talking about code vs. data? Okay, well, I've never heard lazy used in this context

23:45 julianleviston: ddellacosta: ddellacosta in that case, sure, but if you quote it, then they can be different… right? :)

23:46 ddellacosta: but of course you and justin are completely correct…

23:47 ddellacosta: in clojure, this makes no difference.

23:47 it’s important if you want to do less work, though...

23:47 justin_smith: I don't think the usage of the term lazy is helpful here really. "lazy evaluation" is a thing that exists - see Haskell. And Clojure uses lazy sequences.

23:47 julianleviston: justin_smith: ok I won’t use it then.

23:47 ddellacosta: julianleviston: the main thing is that using an idiosyncratic definition for something--even if you can make yourself understood, eventually--can make it hard to express your point to others

23:47 tomjack: isn't it "call by name"?

23:47 julianleviston: ddellacosta: sure.

23:47 ddellacosta: tomjack: is what "call by name?"

23:48 justin_smith: julianleviston: maybe what you are pointing out is just a side effect of the fact that the last arg to apply can be lazy. And sure, if the function isn't eager to consume that arg, it can be lazy on its args in that sense (though + is going to consume all its args when invoked)

23:48 julianleviston: So… back to the actual discussion, though…

23:48 tomjack: "call by name" is, I think, a maybe less idiosyncratic way to say "lazy function application"

23:49 as opposed to clojure's "call by value"

23:49 justin_smith: tomjack: ahh, the way Haskell compiles / evaluates with term rewriting, I can see that

23:49 yeah, Clojure does not share those semantics at all

23:50 julianleviston: justin_smith: because it’s not super lazy… just sometimes lazy… when you specify.

23:50 justin_smith: I mean you can fake it by using delay all over the place but it will be ugly as fuck

23:50 julianleviston: it has lazy sequences

23:50 that's the beginning and end of laziness in clojure

23:50 julianleviston: what I was interested in, is minimizing the amount of work to do, generally… I mean, composing map with some, why map the entire list if we’re only going to use half of it later?

23:50 justin_smith: no lazy evaluation

23:50 julianleviston: justin_smith: yep.

23:51 tomjack: huh, some with map is just Clojure's normal laziness, no?

23:51 julianleviston: so if I make a transducer of partial map with partial some, it *should* be lazy… but is it? does it work like a unix pipe, or does it just work like ruby? (Doing the whole map first)

23:52 justin_smith: you could say that reduce / reduced meet some other goal of not fully evaluating inputs that laziness does, but then you should consider that every programming language has some version of this (usually the return or continue statements)

23:52 julianleviston: which brings me back to… which is better for early aborting / saving calculations on large lists… (into {} (filter pred m)) or (select-keys m (filter pred (keys m))) ? I guess it makes no difference because neither are

23:52 (sorry sub collections in there where I said lists…)

23:53 justin_smith: julianleviston: the transducer with composition ensures that all the steps are done together for one input. Whether this is eager or lazy is decided by the thing consuming the transducer in most cases.

23:53 julianleviston: justin_smith: that was exactly what I thought… brilliant :)

23:53 justin_smith: but of course, into and silect-keys … both of them aren’t composable in that way, so it makes no difference, correct?

23:54 select*

23:54 justin_smith: sure, and both are fully eager

23:54 julianleviston: I guess select-keys is probably more “efficient”, but it’s only a guess.

23:55 justin_smith: it's easy to test that with criterium

23:55 julianleviston: true!

23:55 will do

23:55 justin_smith: probably looks different with different input sizes

23:55 julianleviston: ,(time (let [m {:a "hey" :b "yes" "string-key" "should not include"} pred #(keyword? (key %))] (into {} (filter pred m))))

23:55 , (time (let [m {:a "hey" :b "yes" "string-key" "should not include"} pred #(keyword? %)] (select-keys m (filter pred (keys m)))))

23:55 clojurebot: "Elapsed time: 7.390301 msecs"\n{:b "yes", :a "hey"}

23:55 "Elapsed time: 0.19605 msecs"\n{:a "hey", :b "yes"}

23:55 julianleviston: hm...

23:55 interesting

23:56 justin_smith: yeah, should test with a variety of coll sizes.

23:57 (inc justin_smith)

23:57 lazybot: ⇒ 191

23:57 julianleviston: (inc ddellacosta)

23:57 lazybot: ⇒ 8

23:57 julianleviston: (inc tomjack)

23:57 lazybot: ⇒ 5

23:58 ddellacosta: hmm, I'm kind of surprised those two would differ at all efficiency-wise

23:58 although actually the second one may have benefitted from caching from the first run

23:58 justin_smith: ddellacosta: the cost of consing up (count m)-n keys vs the cost of removing n keys

23:59 julianleviston: yep.

23:59 makes sense to me…

23:59 because of how into works

23:59 (source into)

23:59 ,(source into)

23:59 clojurebot: Source not found\n

23:59 ddellacosta: I guess into is O(n)

23:59 yeah, into is a reduce

23:59 julianleviston: (reduce conj to from)

23:59 ddellacosta: select-keys is O(n log n)?

Logging service provided by n01se.net