#clojure logs

2015-02-21

01:56juxhi
01:58juxI 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])
01:59juxall strings are returned surrounded by \"
01:59juxso I get ({:id 1 :name "\"John Doe\"})
02:00juxwhat can be the reason?
02:03hiredmanyou are double printing, either on the way out or the way in
02:20juxhiredman: these things show in my unit tests, so it's not a thing of printing
02:20juxand I inserted data directly using Navicat
02:32juxhell, you were right
02:47ewemoaalexyakushev: having trouble building foreclojure-android -- is it supposed to build atm?
02:48alexyakushevewemoa: What error do you get?
02:52ewemoaalexyakushev: https://pastee.org/68hs4
02:53alexyakushevewemoa: Let's take it to #clojure-android, shall we?
03:51EremoxIs there some thing like scala's Akka in clojure?
03:52irctc__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)))
03:59amalloyirctc__: you can make the first arity call the second one
04:03irctc__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?
04:32amalloyyou 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
04:47the-kennyOr you can use core.match if you want the 'matching' style.
04:48irctc__i will look into core.match and multimethods - thanks for the advice
05:49nw2probably 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?
05:51Bronsanw2: you want & body not body in the argvec
05:52hyPiRion(macroexpand-1 '(foo (File. "/tmp"))) => (do File. "/tmp")
05:53nw2Bronsa: ah, of course! thank you very much
06:19Guthur`Hi, I'm just starting with Clojure usign Emacs and CIDER
06:19Guthur`I was wondering if there is an eldoc style hint system with CIDER
06:20Guthur`so that I can get information about the interface for a function etc
06:20EremoxWhy is sicp recommended?
06:21AimHerePartly 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.
06:22darrenhI 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.
06:22EremoxWhich would be better to read first sicp or ctmcp
06:42tomjackGuthur`: yes? it doesn't work for you?
06:42tomjackoh, it looks like I had to do (require 'cider-eldoc) (add-hook 'cider-mode-hook (lambda () (cider-turn-on-eldoc-mode)))
06:48Guthur`tomjack: ah, ok I will give that ago
06:53Guthur`tomjack: excellent,thanks
06:54tomjackif you use paredit, I'm not sure it works right
06:54tomjackhttp://emacswiki.org/emacs/ParEdit#toc2
06:55tomjackbut it seems kind of nuts that only those two commands are on the list!
07:01Guthur`Yeah i normally use paredit, but have not added it to a clojure mode hook yet
08:17jaenIs 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)?
08:44the-kennyjaen: with lein pprint, yes.
08:44the-kennyjaen: https://github.com/technomancy/leiningen/tree/master/lein-pprint
08:51jaenthe-kenny: thanks. It shows no middleware however. That's weird o_0
09:13dorightClojure 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?
09:13pandeirowhat 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))
09:15the-kennypandeiro: check clojure.walk
09:16the-kennydoright: My guess is recruiters write scala on their job offers because it's sooooo enterprise.
09:16doright10 of these jobs include other languages in the title so 7 are exclusively Clojure, cf. Scala:297 and Groovy:42
09:16pandeirothe-kenny: yeah i don't see how to accumulate the result w/ walk
09:16pandeirothe-kenny: aside from using them for side effects w/ an atom
09:18the-kennypandeiro: hm. clojure.core/tree-seq then maybe?
09:19the-kenny,(rest (tree-seq sequential? seq '((foo (bar baz)))))
09:19clojurebot((foo (bar baz)) foo (bar baz) bar baz)
09:21the-kennynow throw away non-lists and bingo
09:21pandeirothe-kenny: nice, thank you
09:22irctc__Hi everybody. How can i union a seq/list of sets? (union '(#{1}) #{1})
09:22irctc__sorry... like this one (union '(#{1} #{1})
09:22the-kenny,(apply union [#{42 23} {1 2 3 42}])
09:22clojurebot#<CompilerException java.lang.RuntimeException: Unable to resolve symbol: union in this context, compiling:(NO_SOURCE_PATH:0:0)>
09:22the-kenny,(apply clojure.set/union [#{42 23} {1 2 3 42}])
09:22clojurebot#<CompilerException java.lang.ClassNotFoundException: clojure.set, compiling:(NO_SOURCE_PATH:0:0)>
09:23the-kennydamn you clojurebot
09:23AimHere,(apply clojure.set/union [#{42 23} #{1 2 3 42}])
09:23clojurebot#<CompilerException java.lang.ClassNotFoundException: clojure.set, compiling:(NO_SOURCE_PATH:0:0)>
09:23irctc__great! thanks!
09:23the-kennyirctc__: either apply or reduce, a matter of taste. I prefer reduce when the size of the input list is unknown.
09:25the-kennyAimHere: whoops, just noticed the missing # in my code.
09:26AimHereDidn't do much good, as far as clojurebot was concerned
09:27the-kennyyeah, no difference here.
09:29vas,(apply hash-map [:a 5 :b 6])
09:29clojurebot{:b 6, :a 5}
09:29vas,(reduce hash-map [:a 5 :b 6])
09:29clojurebot{{{:a 5} :b} 6}
09:29the-kennyit doesn't work for all functions, that's obvious
09:52hyPiRionIf 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?
09:52hyPiRionAssuming that people are unlikely to use the two-ary version on a daily basis
09:56seancorfieldhyPiRion: 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?).
09:59hyPiRionseancorfield: yeah, the sort-functions in core is probably doing that to keep the coll at the end like map and friend does
09:59hyPiRionIt won't be used in that setting though, so I guess it makes more sense to just put it at the end
10:02seancorfieldYeah, the "coll arg last" idiom is a good reason for ((f x) y) to be (f y x) :)
10:16ambrosebshow do I tell lein which project.clj to use without cd'ing into it?
10:16ambrosebsI want to run the tests of some subfolder in a Makefile
10:18Glenjaminsh -c "cd subfolder && lein test" ?
10:18Glenjaminnot really what you asked, but should work
10:20ambrosebsGlenjamin: thanks :)
11:02zlingearnestly
11:14justin_smithdoright: maybe not be a lisp?
11:15justin_smithambrosebs: you can use cd in make commands
11:15justin_smithI typically use a pushd / popd combo though
12:14Guest40845Hey 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:33justin_smithGuest40845: 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:41Guest40845justin_smith: mind if i pm?
12:43justin_smithgo ahead, sure
13:02dnolenClojureScript 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:19underplankHi all im trying to instansiate a java ProcessBuilder class like so
14:19underplankorochi.core.api=> (ProcessBuilder. 'python')
14:19underplankIllegalArgumentException No matching ctor found for class java.lang.ProcessBuilder clojure.lang.Reflector.invokeConstructor (Reflector.java:183)
14:19underplankAny idea why?
14:21underplankapparently it doesnt have a constructor? or something?
14:25i-blisunderplank: try (ProcessBuilder. (list "python"))
14:25kriyative@underplank -- did you mean "python" with double-quotes?
14:25underplankI meant a string of “python”
14:25i-blisunderplank: the constructor takes a list
14:26underplanki-blis: huh. it also looks like it take a string. but, thats cool. I could be looking at an old api
14:26underplankyup. using a list works. thanks!
14:27i-blis:)
14:27underplankyeah 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:27underplank:)
14:28underplankthanks i-blis !
14:31csd_Are any of you running CIDER 0.9.0-snapshot?
14:32i-blisyou're welcome underplank
14:34i-bliscsd_: went back to 0.8.2 a week or so ago : did jack in but did not eval code
14:34csd_i-blis: i can't jack in.. gives me a class path error
14:35i-bliscsd_: use stable :)
14:35csd_yeah :-/
14:35justin_smithunderplank: 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:36i-bliscsd_: or do you absolutely need boot support?
14:36underplankahhh, right. that makes sense. So when they say “String” in the constructor, thats not actually what that means :)
14:36csd_i had been using the snapshot for a while because of a bug i'd run into a while back
14:37csd_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:37i-blis0.8.2 seems pretty stable
14:38i-bliscsd_: you can pin the package
14:38vasso 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:38csd_i-blis: awesome
14:38vas( ideal result is just sequential [{nodes}, {nodes}] )
14:39kriyativei-blis: how do you pin packages from MELPA? I switched to el-get just for that ability.
14:39i-bliscsd_: (add-to-list 'package-pinned-packages '(cider . "melpa-stable") t)
14:40kriyativei-blis: good to know, thanks.
14:41i-bliscsd_: provided you added melpa-stable to packages-archives, igws
14:44vashuzzah for concat.
14:46csd_i-blis: looks like MELPA-stable has 0.7.0 latest
14:48i-bliscsd_: are you sure you're using stable.melpa.org?
14:48csd_positive
14:48i-blishttp://stable.melpa.org/#/cider has 0.8.2
14:48csd_weird, thats not what Packages shows
14:49i-bliscsd_: emacs 24?
14:49csd_no, 25
14:49i-bliswell, shouldn't be the issue
14:50csd_oh wait i think i have a syntax in my emacs config
14:50csd_err a syntax error
14:51i-blisdo you have : (add-to-list 'package-archives
14:51i-blis '("melpa-stable" . "http://stable.melpa.org/packages/&quot;) t)
14:52csd_i-blis: there we go :)
14:52csd_thank you
14:53i-bliscsd_: you're welcome
14:54csd_one of those times where you go to do some work and unexpectedly waste a half hour tooling :-/
14:56gfredericksdoes anybody know how to throw this exception via normal clojure usage (i.e., without interopping in the Var class)?
14:56gfrederickshttps://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Var.java#L218
15:05i-blisgfredericks, why not: (throw (java.lang.IllegalStateException.))
15:12gfredericksi-blis: I'm more asking about how to get to that line of code
15:12gfredericksI want to know if it's even possible
15:15amalloygfredericks: (binding [x 1] (.start (Thread. #(set! x 2)))) maybe?
15:17i-blisgfredericks: I am not sure I understand, you want to throw an exception as if a var was set outside its thread?
15:18gfredericksamalloy: 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:18gfredericksi-blis: yep; based on my understanding that line should be unreachable, trying to figure out if there's anything I'm missing
15:27justin_smithgfredericks: is it that you got that exception and want to know how it could have happened?
15:27kryftWhat 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:28justin_smithkryft: wrap the function body in a call to locking?
15:29justin_smith,(defn locked [x] (locking locked (inc x)))
15:29clojurebot#'sandbox/locked
15:29justin_smithit locks on itself
15:29justin_smith,(locked 1)
15:29clojurebot2
15:29kryftjustin_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:29kryftjustin_smith: So I thought I'd check that there isn't a more idiomatic way
15:29justin_smithkryft: well, why is it that the function needs to be locked?
15:29justin_smiththe more idiomatic way is not to need locking at all :)
15:29amalloykryft: well indeed you should rarely need to do this
15:30justin_smithkryft: usually we use immutable data structures so that locking is irrelevant
15:30gfredericksjustin_smith: nope have never got it as far as I know
15:30gfredericksjust wondering if it's dead code or not
15:30justin_smithgfredericks: ahh, I misunderstood then
15:30justin_smithOK
15:31justin_smithkryft: 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:32justin_smithkryft: 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:32kryftjustin_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:32justin_smithand the locking is because you don't want emails sent more than once?
15:32kryftjustin_smith: Right.
15:32amalloykryft: well you have a whole database to work with! databases are great at lokcing
15:33justin_smithkryft: 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:33amalloyadd a column "trying_to_send_right_now", and set that to true when you take it out, for example
15:33amalloylocking 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:34justin_smiththat'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:36kryftjustin_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:37justin_smithkryft: 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:38justin_smithkryft: though perhaps there is some other factor that makes emailing from arbitrary contexts advantageous?
15:39kryftjustin_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:39justin_smithin general I find if something needs to be done exactly once, having exactly one thread in charge of it is helpful
15:39kryftjustin_smith: So I'm sure a single thread would work.
15:40justin_smithyou could also use core.async instead of a thread and a queue, if you find other places where core.async would be useful
15:40justin_smithanyway, 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:41justin_smithsince it is syncronous in its own context
15:42kryftjustin_smith: Right, sounds good. It didn't occur to me to have an explicit thread for that.
15:43kryftamalloy: 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:43justin_smithanother (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:44justin_smiths/agents/agent
15:44kryftamalloy: (I'm fairly new to postgresql too, so I may well be mistaken :)
15:44kryftIt's my first backend, my first DB application, and my first clojure app! :P
15:44justin_smithbest of luck!
15:49kryftjustin_smith: Thanks!
16:05kryftjustin_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:05justin_smithkryft: no need to poll even, just blocking read on the queue in a loop
16:07kryftjustin_smith: Ah, right
16:07justin_smithkryft: so, if you use java.util.concurrent.BlockingQueue it would be a .take operation
16:07justin_smith(rather than .poll, which has a timeout)
16:09justin_smithand then .put for synchronous adding to the queue (but not synchronous waiting for it to be consumed)
16:14kryftjustin_smith: Ah, nice (I was trying to find a structure like that in clojure)
16:14justin_smithkryft: there is clojure.lang.PersistentQueue
16:15justin_smith,(let [q clojure.lang.PersietentQueue/EMPTY q' (conj q :a)] (into [] q'))
16:15clojurebot#<CompilerException java.lang.ClassNotFoundException: clojure.lang.PersietentQueue, compiling:(NO_SOURCE_PATH:0:0)>
16:15justin_smithoops
16:15justin_smith,(let [q clojure.lang.PersistentQueue/EMPTY q' (conj q :a)] (into [] q'))
16:15clojurebot[:a]
16:15justin_smithbut in that case you would want to put it inside an atom, ref, or agent
16:16kryftRight
16:18kryftjustin_smith: Thanks again; I guess I'll just use a BlockingQueue here, but good to know that PersistentQueue exists
16:19justin_smithalso, as I mentioned before, core.async is a mini language around channels, that are effectively queues
16:19justin_smithbut it may be a bit much if you only need that kind of flow in one place
16:24kryftjustin_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:37justin_smithkryft: alpha, but widely used
16:38kryftjustin_smith: A bit like prismatic/schema then :P
16:42justin_smithI think it's wider deployed than schema though, I've had it in production a couple of instances myself
16:42Graawrhey ! 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:43justin_smithGraawr: in general, clojure core doesn't abstract very far from the host for IO stuff. That lib may exist out there somewhere though.
16:44csd_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:48Graawrjustin_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:50justin_smithand jar-file is a java.util.jar.JarFile?
16:50Graawryup
16:50Graawrand jar-entry is a java.util.jar.JarEntry
16:50justin_smithoh, the code there calls getInputStream on jar-file
16:51justin_smithnot on the entry
16:51justin_smitherr wait
16:52Graawrwhoops, typo: (.getInputStream jar-file jar-entry) returns nil (there's no nesting)
16:52justin_smithso, I would expect this to work: (.getInputStream (java.util.jar.JarFile. "some/path/to.jar"))
16:52justin_smithwhy the extra arg?
16:52justin_smiththe stream is the jar, not some entry in the jar
16:52justin_smithwait...
16:53justin_smithok, so file is a java.io.File
16:53justin_smithyou get an inputstream from the file
16:54justin_smithsorry, I'm all mixed up on this, I'm backing out for a moment
16:54Graawroh okay, thank you !
17:00justin_smithGraawr: 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:01justin_smithbecause if the first thing you got was a directory, I could see getInputStream returning nil if you did not replicate the continue logic
17:01maaclHelp 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:02justin_smithmaacl: delete your elc files and restart emacs
17:02justin_smithcider tends to not upgrade cleanly
17:03Graawrjustin_smith: yes, the continue will skip the current loop interation
17:03maacljustin_smith: Ok, will give that a try.
17:04Graawrjustin_smith: but I get a nil from getInputStream whatever the input (file or directory jarEntry)
17:08maacljustin_smith: Thanks, that did the trick.
17:08clojurebotHuh?
17:08justin_smithmaacl: np, it should really be in the cider docs
17:11justin_smithGraawr: so I made my own attempt to translate it, mostly just to help me read it
17:12justin_smithGraawr: 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:12justin_smith(so of course it can't write to it, the directory has not been made yet)
17:13justin_smithGraawr: d'oh, and now I read the comments!
17:14justin_smithGraawr: would it be instructive to show you my translation that works, or would you rather sort it out yourself?
17:14Graawrjustin_smith: I'd like to see your version if that's okay, I'm still a bit struggling halway through mine
17:15justin_smithof course I had to pick a jar that had more than 2800 files in it to test with...
17:15justin_smithOK
17:16justin_smithGraawr: this is a direct translation (taking into account the comments about .getParentFile) and it works https://www.refheap.com/97626
17:16Graawrjustin_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:16justin_smithno need for any libs for this
17:16justin_smithgetParentFiles is trivial
17:16justin_smith*getParentFile
17:16Graawroh right
17:17justin_smithalso, I changed the system separator to "/" because that works even on Windows
17:17Graawrah, didn't know that
17:17Graawrhum
17:17GraawrI see you don't use enumeration-seq on the entries ? I thought it was needed
17:17justin_smithand 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:18justin_smithGraawr: that's not a call, that's just a type
17:18justin_smitherr... wait
17:18justin_smithwhy would I need enumeration-seq?
17:19Graawrnevermind, that was an artefact from a previous try where I got confused by the Enumeration class used
17:19justin_smithGraawr: oh, I get it. Since I am not using clojure sequence functions, I don't need to use enumeration-seq.
17:20Graawryup
17:20justin_smithI 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:20Graawrthough if I wanted to use seq (like using a loop/recur with (first ...) and (rest ...)) it would be needed right ?
17:20justin_smithGraawr: I wouldn't use loop/recur - enumeration-seq + doseq
17:21Graawroh
17:21justin_smithloop / recur with first / rest can almost always be translated into something higher level
17:24Graawrhum, yes, i've still not really wrapped my mind around higher-level looping structure besides map/reduce kinds
17:24justin_smithGraawr: 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:26Graawrthat's exactly what i'm experiencing ^^
17:28Graawrby 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:28justin_smithalso, 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:28justin_smithGraawr: what you have there is how I would do it
17:28justin_smithGraawr: what's the end goal? do you need the files to be on disk to use some OS utility on them?
17:28Graawrhum, I have to say my java IO was fairly brief, I might need to look further into bytes array for writing
17:29justin_smithGraawr: it's an alternate read method, takes a byte array for filling
17:29justin_smithand 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:30justin_smithand write, of course, has an alternate method that takes a byte-array to write from
17:31Graawrjustin_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:32RaynesPeople keep telling me to rewrite refheap in node.
17:32justin_smithGraawr: 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:32RaynesI'm incredibly entertained by this, given that the one single lone reason for folks using refheap is because it's written in Clojure
17:32RaynesBecause everyone has it in their head that "Hey, I can contribute to this in my favorite language!"
17:33RaynesBut then they never contribute to it.
17:33justin_smithRaynes: nah, I use it because it isn't spammy and it syntax highlights with a dark background
17:33RaynesI need to rewrite it
17:33rhg135nah, same here
17:33RaynesNot in node, but in Clojure.
17:33Graawrjustin_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:33Raynesjustin_smith: So I should revert this commit to add interstitials?
17:33justin_smithGraawr: aha, so you aren't serving the stuff from a clojure web server
17:33justin_smithRaynes: DON"T YOU FUCKING JOKE
17:33justin_smithhaha
17:34Raynesgit branch -D piss-off-justin-smith
17:34Raynesgf3: We should rewrite refheap from the ground up with you designing.
17:34Graawrjustin_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:34RaynesWe'll use Graawr's static site generator.
17:34RaynesWe'll just regenerate it every time someone makes a paste.
17:35justin_smithGraawr: ahh, got it
17:35RaynesIn all seriousness, it might be fun to rewrite the whole thing with cljs
17:35RaynesClient side 4evr
17:35justin_smithhttp://i.imgur.com/aJwbNM4.jpg
17:36Raynesyes
17:36rhg135Raynes, how would the api work if it ran client-side?
17:36RaynesHow would anything work fi it ran client side?
17:36RaynesThere'd still be a server component.
17:37justin_smithrhg135: the one benefit I can think of is it could push edits when people update the paste
17:37RaynesBut the server would probably just become an API service.
17:37justin_smithperhaps even a UI to see revisions
17:37rhg135ah ok, and that'd stay the same i assume?
17:37RaynesThe API is shitty, so I'd probably change it too
17:37rhg135i find it pretty simple
17:37RaynesI can add a compatibility layer :P
17:38rhg135GET to /posts/:id get response
17:38RaynesOh, that'd still work
17:39rhg135i'm curious what you mean by a new api.
17:40rhg135justin_smith, push is always win imo in web design
17:40Raynesrhg135: I mean, the problem with the current API is not really the API itself, but how it's written
17:40RaynesSee, I didn't know a damn thing about web development.
17:40RaynesThe API is entirely distinct from the interface.
17:40RaynesThey hardly even use the same code
17:40RaynesIt's so ridiculous.
17:40RaynesThe web interface should be using the same API
17:41rhg135oh I see, Raynes. So maybe some feature expressions if you go cljs?
17:41Raynes'feature expressions'?
17:41RaynesMaybe I still don't know shit about web development.
17:41RaynesDamn it.
17:41RaynesI need to stop writing websites
17:41Raynes;)
17:42rhg135being able to share code server-side with client-side
17:42RaynesI see
17:42RaynesI don't know what state of the art in cljs client-server communication is
17:42RaynesBut I hope there is some good shit available
17:42RaynesI'm spoiled by Meteor
17:42RaynesWhere it's all so seamless
17:42justin_smithRaynes: 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:42rhg135websockets i hear are useful for this
17:43RaynesYeah, 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:43RaynesIf not, I'll come back in a few months when there is :P
17:43rhg135or even ajax
17:43Rayneshttp://hoplon.io/
17:43RaynesLike this
17:44rhg135the goal is to minimize the synchronization from client to server
17:45RaynesIt should all be pretty simple
17:46rhg135i don't do any web dev either
17:46RaynesI do web dev, but usually single page apps.
17:46rhg135but i've read being able to share code--like nodejs--is a boon
17:47rhg135so clj(s) is nice
17:47RaynesI've been doing a lot of ES6/Coffee lately.
17:47RaynesI don't share the same furious hatred for JS that others do.
17:48rhg135i've done Coffee just because i cba to remember js's quirks
17:48justin_smithshall we burn the heretic, stone him, or simply force him to live with his corrupted and sad decisions?
17:48RaynesI mean, coffee shares those quirks.
17:48rhg135it's a fine language if you know it, and I don't
17:49RaynesCoffee is just a js preprocessor, really.
17:49rhg135Raynes, but less
17:49RaynesES6 is pretty cool too
17:49rhg135it is which is great
17:49justin_smithrhg135: it was written in like a week, you can learn the important aspects in less time than that
17:49RaynesI'm furious they didn't add a thin arrow with their fat arrow.
17:49rhg135ive been out of the js loop since before es6 existed
17:49rhg135well it did just not practically
17:50rhg135justin_smith, i could, it's the context switches in my mind I'd have to make going back to another lang
17:51RaynesES6 offers: a module system, => fat arrow functions that pass the this context in, potentially comprehensions...
17:52rhg135i didn't feel like running a development nodejs build
17:52Raynesbabeljs.io
17:52rhg135or using that lol
17:52Rayneshttps://github.com/Raynes/barrelroll
17:53RaynesCurrently writing a thing with it
17:55Raynesoshi
17:55RaynesThere's a new Clojure build tool?
17:55rhg135why be afraid?
17:56justin_smithI don't know how mature boot is
17:56rhg135not like they can't speak to each other
17:56rhg135they both produce jars
17:59RaynesI wrote small very small portions of leiningen
17:59RaynesI'm emotionally attached
17:59rhg135i like leiningen; it makes it easy for clj
17:59rhg135cljs otoh is a pita
18:12thsigHey 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:13thsigI.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:16justin_smiththsig: unless you have a really compelling reason, ring is the best bet
18:16justin_smithalmost everything else (with rare exceptions like pedastal) uses ring
18:18thsigjustin_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:18thsigsince in ruby, one ends up adding a lot of the stuff from rails back on to sinatra as the requirements get more complex
18:19justin_smiththsig: I wouldn't compare ring to sinatra, no
18:19thsigbut of course clojure is different, just trying to get a feel for the web library landscape
18:20justin_smiththsig: if anything I would compare compojure to sinatra, but in the clojure world we tend to do things very modular
18:20justin_smithyou can easily use ring without compojure
18:21thsigjustin_smith: Ok, I see. I guess ring is more like rack.
18:21thsigthere's a lot of stuff that comes along with rails that I've never used or liked
18:21justin_smithyeah, that's a much closer comparison
18:21thsigand now that I'm experienced I like the idea of picking just what I need
18:21justin_smithyeah, that's the norm in clojure
18:23thsigjustin_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:24justin_smithin 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:25justin_smithheh
18:28gfredericks,(def a-million (bit-shift-left 20 1))
18:28clojurebot#'sandbox/a-million
18:29justin_smith,a-million
18:29clojurebot40
18:34underplankSo 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:34underplankexample code https://www.refheap.com/97630
18:37justin_smithso every time a client hits create-proxy you would rebuild your whole system? that seems a bit silly
18:38justin_smithwhy not update an atom containing proxies?
18:39justin_smithotherwise you have a topological problem, as you've noticed, where the handler that creates your response also wants to return a new component
18:39underplankSorry. 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:40underplankI 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:40underplankand the Api component doesnt need to be replaced.
18:40justin_smithright. 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:41justin_smithbut that seems like it would get a little messy without much benefit
18:43underplankyeah. 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:11maacl`Does anyone know if it is possible to get popup documentation with CIDER and company completion?
20:13justin_smithyes, it is possible
20:14arrdemsupposedly it'll "just work" if you have company turned on
20:14arrdemhasn't worked for me in a while
20:14justin_smiththat was my experience a while back, but I wouldn't be surprised if something broke at aome point
20:14maacl`justin_smith: Ok, is there anything I have to do to enable it? Completion works, but I am not getting any documentation
20:15justin_smithI'm not really sure, I just know I have had it working in the past
20:15maacl`justin_smith: ok
20:16arrdem#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:22maacl`arrdem: Thanks, I have raised a ticket.
20:23arrdemclojurebot: rejoice
20:23arrdemmaacl`: thanks.
20:23arrdemmaacl`: FWIW cider-grimoire still totally works, not that I'm biased or anything :P
20:55dorightHow do I convert, for example, "String" to a parameter of the (class ....) function?
20:55arrdemdoright: what are you trying to achieve? resolve the class named by a string?
20:56dorightarrdem: (defn get-meths [class-name] (for [meth (.getDeclaredMethods (class class-name))] (println (.getName meth))))
20:56doright(defn get-meths [class-name] (for [meth (.getDeclaredMethods (class class-name))] (println (.getName meth))))
20:57dorightarrdem: With (import 'java.lang.reflect.Method)
20:58Bronsadoright: given that you call (class ) on class-name you're going to need an instance object of that class
21:02dorightBronsa: Not really. This works: (let [mths (.getDeclaredMethods (class String))] (for [m mths] (println (.getName m))))
21:02Bronsa,(class String)
21:02clojurebotjava.lang.Class
21:02Bronsadoright: that's likely not what you want
21:03dorightBronsa: Why? It lists all the methods, like I asked.
21:03Bronsadoright: it lists all the methods of Class not String
21:04dorightBronsa: Ah, will have another look :)
21:04arrdemI'll leave you in Bronsa's more classloader-informed hands
21:04Bronsadoright: what is exactly that you want get-methods to do?
21:05Bronsaget-meths, rather
21:06dorightBronsa: Should have been: (let [mths (.getDeclaredMethods (class (String.)))] (for [m mths] (println (.getName m))))
21:07Bronsadoright: what's the input to your function and what's the desired output?
21:07dorightBronsa: I don't think it's do-able but pass in a class name such as String or URL.
21:08Bronsadoright: as a string?
21:08dorightBronsa: (class (classname.)) [pseudo-code] looks even less likely
21:08dorightBronsa: Yes, as a string.
21:09dorightBronsa: S'pose core.typed might come in handy here.
21:10dorightBronsa: I'm just playing with Java interop, that's all, as a learning exercise.
21:11Bronsadoright: this is how it should be written then: http://sprunge.us/BUGY?clj
21:11dorightBronsa: 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:12dorightBronsa: Marvelous. I'll go study that one. Thanks.
21:12Bronsadoright: 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:12Bronsadoright: also note that for is lazy, when you need to perform side-effects you should use doseq
21:15dorightBronsa: (symbol "class-name-string") was what I needed.
21:16Bronsadoright: not really, (symbol "String") returns 'String as a symbol, not the String class
21:16Bronsa,(class (symbol "String"))
21:16clojurebotclojure.lang.Symbol
21:16dorightBronsa: Maybe I could have passed it directly after all.
21:16Bronsa,(class String)
21:16clojurebotjava.lang.Class
21:16Bronsadoright: in that case http://sprunge.us/cOTN?clj and you can invoke it as (get-meths String)
21:19dorightBronsa: ^Class is a type hint?
21:19Bronsayes
21:19dorightBronsa: Then that's what I was missing. Learned a lot, thanks.
21:20Bronsadoright: note that type hints only affect performances, they don't change the semantics of the code
22:40justin_smith,(Class/forName "String")
22:40clojurebot#<ClassNotFoundException java.lang.ClassNotFoundException: String>
22:40justin_smith,(Class/forName "java.lang.String")
22:40clojurebotjava.lang.String
23:31julianlevistonWhich is more idiomatic, do you think? (into {} (filter pred m)) or (select-keys m (filter pred (keys m))) ?
23:32justin_smithjulianleviston: the latter only gets to filter based on the keys...
23:32justin_smithbut regardless, the former is nicer
23:32julianlevistonyeah, that’s what I’m trying to do - filter on keys with a predicate...
23:32julianlevistonjustin_smith: why is it nicer, in your opinion?
23:32justin_smithless noise
23:33julianlevistonjustin_smith: this is the predicate: #(keyword? (key %))
23:33julianlevistonwell, for the first one
23:33justin_smith(comp keyword? key)
23:34julianlevistonjustin_smith: actually I think you’ve answered my question… the second is better because it explains the intent more.
23:34justin_smithanyway, the into/filter is a more straightforward combo to my eyes, compared to select keys / filter / keys
23:34justin_smithOK
23:34julianlevistonwhat I *really* want is a function select-keys-filter, so maybe I’ll go write that.
23:34julianlevistonor something with a less ugly name
23:35julianlevistonjustin_smith: I guess that’s probably because the into/filter is more lazy.
23:35julianlevistonjustin_smith: damn clojure and its messy laziness :)
23:35julianlevistonjustin_smith: so, because it’s more lazy, it’s doing less work… :) right? that’s why you intuitively reach for it?
23:36justin_smithinto isn't lazy
23:36julianlevistonjustin_smith: and I guess wrapping it in a function will name my intent, so convey the sematics better?
23:36julianlevistonjustin_smith: isn’t reduce lazy?
23:36justin_smithno
23:37julianlevistonjustin_smith: but it uses a transducer, doesn’t it?
23:37julianlevistonjustin_smith: I thought transducers were
23:37julianlevistonjustin_smith: I guess that’s only if you compose them, then their effect is lazy… hm...
23:37justin_smithnope, they are agnostic to laziness for the most part
23:38justin_smiththe thing using them gets to decide if it is lazy or not
23:38julianlevistonjustin_smith: but if you compose two or more transducers, then the net effect is laziness of function application, isn’t it?
23:38justin_smithso a reduce on a transducer is eager, a sequence on a transducer can be lazy
23:38justin_smithabsolutely not
23:38julianlevistonguh.
23:38julianlevistonthat’s a bit sucky
23:38justin_smithwhat does lazy function composition even mean?
23:39julianlevistonjustin_smith: no, lazy application
23:39justin_smithOK, sequence on a transducer is lazy
23:39julianlevistonjustin_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:39justin_smithreduce isn't
23:39justin_smiththe transducer is neither lazy nor not lazy
23:39julianlevistonjustin_smith: yes, I know… but the fact that it can be means it is when it can be.
23:39justin_smithaborting early is not the same as laziness
23:39justin_smithreduce can return early, and is not lazy
23:40julianlevistonjustin_smith: hm… I guess we have different definitions then
23:40justin_smithreduce can have a filtered mapping as it's input, it's still going to be eager
23:40julianlevistonjustin_smith: eager meaning it gets all of its arguments before starting?
23:40julianlevistonjustin_smith: right?
23:40justin_smithearly return isn't lazy, because it is never going to do the hypothetical work that followed - no work is delayed
23:41julianlevistonjustin_smith: yep. cool.
23:41justin_smitheager meaning it fully calculates its result when called
23:41julianlevistonyep tho if the work IS INSIDE the transducer, not outside it, it *is* lazy… as in… lazy application… not lazy evaluation.
23:41julianlevistonjustin_smith: know what I mean?
23:41justin_smithabsoluttely not, no, that makes no sense to me
23:41justin_smiththe transducer is neither lazy nor not-lazy
23:42justin_smithit's a transduce
23:42justin_smithsomething lazy or eager can use it
23:42julianlevistonjustin_smith: lazy function application means you don’t apply the function across the whole thing if you don’t have to…
23:42julianlevistonjustin_smith: lazy usually just means the arguments are evaluated before the function begins.
23:42justin_smithare you talking about eagerly consuming args? that's not the same as laziness.
23:42justin_smithor lack thereof
23:42julianlevistonjustin_smith: hehe :) as I said, we have different definitions of lazy application here.
23:42justin_smith(first x) does not fully realize its input. It also is in no way lazy.
23:43julianlevistonjustin_smith: and yes… call it eager consumption, if you like.
23:43justin_smithjulianleviston: your definition of lazy is not used anywhere in clojure
23:43ddellacostajulianleviston: it seems like you are redefining terms idiosyncratically, which does no one any good
23:43julianlevistonno not at all.
23:43julianlevistonI explicitly said lazy function application, not lazy evaluation.
23:43justin_smiththere is no such thing as "lazy function application" in clojure
23:43ddellacostawhat is the difference between application and evaluation?
23:44julianlevistonddellacosta: (apply + [1 2 3]) versus (+ 1 2 3)
23:44justin_smithwhat he means by his invented term "lazy function application" is that the args are not greedily consumed
23:44ddellacostaand, if it exists, please point us to some literature where this terminology is used
23:45julianlevistonddellacosta: it’s the difference between eval and apply, isn’t it?
23:45ddellacostajulianleviston: those two are exactly the same in terms of how they are evaluated. There's nothing "lazy" going on here
23:45julianlevistonjustin_smith: yeah! :)
23:45ddellacostaso we are talking about code vs. data? Okay, well, I've never heard lazy used in this context
23:45julianlevistonddellacosta: ddellacosta in that case, sure, but if you quote it, then they can be different… right? :)
23:46julianlevistonddellacosta: but of course you and justin are completely correct…
23:47julianlevistonddellacosta: in clojure, this makes no difference.
23:47julianlevistonit’s important if you want to do less work, though...
23:47justin_smithI 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:47julianlevistonjustin_smith: ok I won’t use it then.
23:47ddellacostajulianleviston: 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:47tomjackisn't it "call by name"?
23:47julianlevistonddellacosta: sure.
23:47ddellacostatomjack: is what "call by name?"
23:48justin_smithjulianleviston: 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:48julianlevistonSo… back to the actual discussion, though…
23:48tomjack"call by name" is, I think, a maybe less idiosyncratic way to say "lazy function application"
23:49tomjackas opposed to clojure's "call by value"
23:49justin_smithtomjack: ahh, the way Haskell compiles / evaluates with term rewriting, I can see that
23:49justin_smithyeah, Clojure does not share those semantics at all
23:50julianlevistonjustin_smith: because it’s not super lazy… just sometimes lazy… when you specify.
23:50justin_smithI mean you can fake it by using delay all over the place but it will be ugly as fuck
23:50justin_smithjulianleviston: it has lazy sequences
23:50justin_smiththat's the beginning and end of laziness in clojure
23:50julianlevistonwhat 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:50justin_smithno lazy evaluation
23:50julianlevistonjustin_smith: yep.
23:51tomjackhuh, some with map is just Clojure's normal laziness, no?
23:51julianlevistonso 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:52justin_smithyou 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:52julianlevistonwhich 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:52julianleviston(sorry sub collections in there where I said lists…)
23:53justin_smithjulianleviston: 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:53julianlevistonjustin_smith: that was exactly what I thought… brilliant :)
23:53julianlevistonjustin_smith: but of course, into and silect-keys … both of them aren’t composable in that way, so it makes no difference, correct?
23:54julianlevistonselect*
23:54justin_smithsure, and both are fully eager
23:54julianlevistonI guess select-keys is probably more “efficient”, but it’s only a guess.
23:55justin_smithit's easy to test that with criterium
23:55julianlevistontrue!
23:55julianlevistonwill do
23:55justin_smithprobably looks different with different input sizes
23:55julianleviston,(time (let [m {:a "hey" :b "yes" "string-key" "should not include"} pred #(keyword? (key %))] (into {} (filter pred m))))
23:55julianleviston, (time (let [m {:a "hey" :b "yes" "string-key" "should not include"} pred #(keyword? %)] (select-keys m (filter pred (keys m)))))
23:55clojurebot"Elapsed time: 7.390301 msecs"\n{:b "yes", :a "hey"}
23:55clojurebot"Elapsed time: 0.19605 msecs"\n{:a "hey", :b "yes"}
23:55julianlevistonhm...
23:55julianlevistoninteresting
23:56julianlevistonjustin_smith: yeah, should test with a variety of coll sizes.
23:57julianleviston(inc justin_smith)
23:57lazybot⇒ 191
23:57julianleviston(inc ddellacosta)
23:57lazybot⇒ 8
23:57julianleviston(inc tomjack)
23:57lazybot⇒ 5
23:58ddellacostahmm, I'm kind of surprised those two would differ at all efficiency-wise
23:58ddellacostaalthough actually the second one may have benefitted from caching from the first run
23:58justin_smithddellacosta: the cost of consing up (count m)-n keys vs the cost of removing n keys
23:59julianlevistonyep.
23:59julianlevistonmakes sense to me…
23:59julianlevistonbecause of how into works
23:59julianleviston(source into)
23:59julianleviston,(source into)
23:59clojurebotSource not found\n
23:59ddellacostaI guess into is O(n)
23:59ddellacostayeah, into is a reduce
23:59julianleviston(reduce conj to from)
23:59ddellacostaselect-keys is O(n log n)?