#clojure logs

2015-04-09

00:00IgorBut when I reset! atom, if I first need calculate new value, depends on this atom, another thread can running between calculating and reset!
00:00justin_smithyes
00:00IgorHmm.. I think I must use swap! in this case =)
00:01justin_smithreset! is for if you unconditionally want to set the value, swap! is if you want to calculate a new value based on an old one, and you want to recalculate if there was any modification in the meantime
00:07Igorthx
01:28grehuoHi everyone. I've got a newbie problem, that I'm stuck at and can't figure out from the docs. I'm creating a todo app, and have my state in an atom like this: http://pastebin.com/ETgz4b5g. I want to make a function to change the state of one of the items in the vector, so that it has {:done true}. I think the function I'm looking for is assoc-in, but I can't get it to work like I want to and can't figure out how to use it. Does anyone
01:28grehuoknow how you would update one specific map in the vector in the atom?
01:30grehuoBasically: how can you swap! a value of a map inside a vector inside an atom, without making changes to the other parts of the atom?
01:31nuwanda__grehuo:
01:32nuwanda__you want assoc-in
01:32nuwanda__with [index :done]
01:33nuwanda__,(def todos [{:id 1 :done false} {:id 2 :done true}])
01:33clojurebot#'sandbox/todos
01:33nuwanda__,(assoc-in todos [0 :done] true)
01:33clojurebot[{:id 1, :done true} {:id 2, :done true}]
01:37grehuoI wrote `(swap! todos (assoc-in @todos [0 :done] true))`, but am getting the error "No item [the vector] in vector of length 2". This is cljs. Also, this will only update the first item, every time right? Not any item I chose?
01:45tomjack(swap! todos assoc-in [0 :done] true)
01:45tomjacktrue
01:46tomjackit seems maybe a bit odd to have a vector of maps with ids -- do you want to update by id, or by position in the vector?
01:46tomjack0 in [0 :done] means "the first element"
01:47tomjackif you want to update by id, it might be easier to have (def todos (atom {1 {:done false} 2 {:done true}})), then (swap! todos assoc-in [1 :done] true) means "the element under key/id 1"
01:50tomjack(swap! todos assoc-in [0 :done] true) probably looks mysterious, it's shorthand for (swap! todos #(assoc-in % [0 :done] true))
01:50tomjackwhen swapping you must take the current value as a function parameter, _not_ dereference like @todos
01:51tomjack(reset! todos (assoc-in @todos [0 :done] true)) would be the non-exception-throwing way to do what you tried, but it would be wrong
01:51grehuoI see.. Yeah having :id in a vector makes no sense, removing it and using position in vector as id instead.
01:51tomjackbecause you may dereference todos, then someone else swaps the atom, then you reset, losing state
01:53tomjack(OTOH having :id in a vector could make sense, if e.g. the todo items can be moved around in the list but you want to remember their identities :) )
01:55tomjacks/losing state/possibly causing any number of weird race condition problems/
01:56grehuonuwanda__ tomjack I'm starting to make it work now, this is so cool! Now I just have to figure out how to select the index of the todo that is being clicked on in my app, but I'll have a go at that myself :). I can not thank you enough for helping me figure out what was wrong in my example, and helping me understand assoc-in! THANK YOU!!!
01:57grehuoThe solution seems to be to not set the :id
01:57grehuoand then do (swap! todos assoc-in [0 :done] true), like you saik
01:57grehuosaid
02:17celwellHello, I find I'm having to use this quite often (when (not *compile-files*) ...) and it's dirtying my code up. Any ideas? Is there a prettier solution? The reason I need that conditional is because those expressions cause uberjar (and uberwar) to hang if they are run at compile time.
02:19mavbozocelwell, interesting, are those expressions have side-effects?
02:21celwellmavbozo: e.g., one starts a thread that modifies a db every 5 seconds
02:22svericelwell: I have never seen something like this before. I would say you have some code which you are evaluating during compilation / macro evaluation maybe which causes your process to hang
02:23mavbozocelwell, those expressions are (defns ...) ?
02:23celwellheres an example:
02:23celwell(when (not *compile-files*)
02:23celwell (def zones (map #(assoc % :zip_codes (util/split-on-comma (:zip_codes %)))
02:23celwell (get-all-zones (db/conn)))))
02:24celwellwhere, get-all-zones grabs from db
02:24celwellif I take off the (when (not *compile-files*) it will hang on ring uber war
02:24celwellor whatever the command is
02:24sveribecause of the (get-all-zones... I assume
02:25celwellyeah
02:25mavbozocelwell, you should't put side-effecty expressions at the top-level of your namespace.
02:25svericelwell: read about component: https://github.com/stuartsierra/component this is valuable for what you want to do
02:26mavbozocelwell, put it inside a function and call those function in your (defn -main [] ...)
02:26celwellI don't have a -main currently.
02:26celwelli guess i should read about it?
02:27celwellI'm lein ring server, and then making uberwars for deployment
02:28sveriDoes an uberwar work at all without a -main method?
02:28celwellyeah
02:29celwellThis is the entrance to the program I guess:
02:29celwell(def app
02:29celwell (-> (handler/site app-routes)
02:29celwell (middleware/wrap-json-body)
02:29celwell (middleware/wrap-json-response)))
02:29sverihm, interesting. still, I find the idea very unusal not to have one entry point
02:29sobel-main is not the entry point for a war
02:29celwellI guess ring handles the -main business, unless I'm mistaken
02:29sobelwell, not your -main
02:29sobel:)
02:32sverisobel: not? How does the container figure out which class and method to start?
02:36sobelsveri: afaik, that's part of the servlet spec
02:39sverisobel: right, I remember, you can define an entry point in some xml file. Been to long since I had to use it
02:45sobelsveri: what entry point do you mean? there is a -main that brings up the server, but it's ring's
02:45sobelall the entry points you define for a web app are request handlers
02:52sverisobel: Yea, It's been some time, but once I worked with GWT and I had to define a class as an entry point in some xml file somewhere
03:25dysfunhrm, have to say i'm rather liking boot so far
03:25dysfuneven if i'm missing about a dozen plugins i quite like
03:34mavbozocelwell, if you use lein-ring plugin you can specify your init function in :ring options in project.clj
03:35mavbozocelwell, the init function called once before your handler starts
04:00mpenetjust wondering: any advantage of using an uberwar vs uberjar?
04:01dysfunmpenet: there is if you deploy via an appserver
04:01mpenetyes, appart from that
04:03mpenetI guess an appserver is mandatory in prod if you use war files
04:06dysfuni think they can still be executable
04:06dysfunit's just that war files mandate all that xml as well
04:07dysfun(well, for stuff that doesn't matter)
04:08dysfunthere's no need to have an appserver for a good production environment either
04:08dysfuni certainly don't have the level of experience required to actually administer an appserver
04:09mpenetI guess if I had to use an app server (as per client request), wars make sense, otherwise not so much
04:09dysfunthat's a good rule of thumb
04:09sverime uses an uberjar too
04:09dysfunthere are some circumstances where appservers win, like if you're using J2EE stuff, but in clojure, there's really no need to use J2EE stuff
04:10dysfunit's mostly handy to have it there as a way of integrating with an aging java codebase
04:11sveriI guess appservers also make sense if you want multiple apps running inside one server to save resources
04:12dysfunthere's some of that, but it starts to get complicated very quickly
04:12dysfunmemory is cheap. i hope your time is not :)
04:13dysfunback in the day, appservers were the only way to make performant web stuff
04:13dysfunthen we got Netty. Then it got good. really good.
04:13dysfunnow i deploy netty in an uberjar (via aleph)
04:15sveridysfun: Well, there are people running vps with only limited memory, so for some this is a concern. That said, I am on your side too, I'd rather pay a bit more before I go ahead and fiddle with theses app servers and all the complexity they bring in
04:15dysfunthere's also something to be said about valuing your sanity :)
07:04blashyrkhello, is it possible to convert a hashmap into an atom?
07:04blashyrkor at least construct an atomic hashmap from a normal, immutable map?
07:05TEttingerblashyrk, I'm not sure atoms mean what you think they do
07:05TEttinger,(atom {})
07:05blashyrkprobably not :)
07:05clojurebot#<Atom@be611cf: {}>
07:05blashyrkI'm using cheshire to parse JSON
07:06TEttinger,(def kinda-variable (atom {}))
07:06clojurebot#'sandbox/kinda-variable
07:06blashyrkbut I want to make modifications to the hashmap I get as a result
07:06TEttinger,(swap! kinda-variable assoc :a 1)
07:06clojurebot{:a 1}
07:06TEttinger,@kinda-variable
07:06clojurebot{:a 1}
07:06TEttingeryou may want transients
07:06blashyrkyes, but is it possible to assoc an entire hashmap to the newly defined atom?
07:07blashyrkand if so wouldn't that be kinda expensive?
07:07TEttingeryeah
07:07TEttingerno
07:08TEttinger,(def kinda-variable (atom (zipmap (range 1000) (map char (range 32 1032)))))
07:08clojurebot#'sandbox/kinda-variable
07:08TEttinger,@kinda-variable
07:08clojurebot{0 \space, 893 \Ν, 920 \θ, 558 \Ɏ, 453 \ǥ, ...}
07:08TEttingerunsorted
07:11blashyrksay I have a map in a var "some-map"
07:11blashyrkbut it's a standard immutable map
07:11TEttingerblashyrk, the neat thing about clojure's data structures is that even though they are immutable, and cannot be modified after being created, if you make another, say, hashmap with most of its keys and values from an existing hashmap, the keys and values that are the same will be shared, not using additional memory and not requiring a copy
07:11blashyrkthat sounds great, but what is the idiomatic way to construct an atomic map completely from an existing map?
07:12TEttingerso it isn't expensive to just return a modified version of that immutable map, and pass it to another fn expecting another map
07:12TEttingerthe fn atom
07:12TEttinger(doc atom)
07:12clojurebot"([x] [x & options]); Creates and returns an Atom with an initial value of x and zero or more options (in any order): :meta metadata-map :validator validate-fn If metadata-map is supplied, it will become the metadata on the atom. validate-fn must be nil or a side-effect-free fn of one argument, which will be passed the intended new state on any state change. If the new state is unacceptable, the validate-fn should return false or thro
07:12TEttingerbasically, you only care about the first part of that
07:13TEttingerthe initial value of the atom will be the argument you pass to (atom)
07:13blashyrkI tried that already but it didn't work for some reason
07:13blashyrklet me check
07:13blashyrk,(def some-map {:somekey 0, :someotherkey 2})
07:13clojurebot#'sandbox/some-map
07:14blashyrk,(def mutable-map (atom some-map))
07:14clojurebot#'sandbox/mutable-map
07:14blashyrk,@mutable-map
07:14clojurebot{:somekey 0, :someotherkey 2}
07:14blashyrkhmmm interesting
07:14TEttingeryou still won't modify some-map
07:14blashyrknot sure why it didn't work for me
07:14TEttingerbut mutable-map can be altered
07:15TEttinger,(swap! mutable-map assoc :yetanotherkey [:whee :vecs])
07:15clojurebot{:somekey 0, :someotherkey 2, :yetanotherkey [:whee :vecs]}
07:16blashyrkah I remember what failed in my case
07:16blashyrkcan I use swap to basically assign?
07:16blashyrklike
07:17blashyrk,(def mutable-map (atom {}))
07:17clojurebot#'sandbox/mutable-map
07:17blashyrk(swap! mutable-map ? some-map)
07:18blashyrkwhat would I use here to directly "assign" the original map to the atom?
07:18blashyrkor should I just redefine mutable map (after parsing the original map) ?
07:18blashyrkwith def
07:21oddcully,(doc reset!)
07:21clojurebot"([atom newval]); Sets the value of atom to newval without regard for the current value. Returns newval."
07:21oddcully,(reset! mutable-map {:a 1})
07:21clojurebot{:a 1}
07:22oddcully,(@mutable-map)
07:22clojurebot#error{:cause "Wrong number of args (0) passed to: PersistentArrayMap", :via [{:type clojure.lang.ArityException, :message "Wrong number of args (0) passed to: PersistentArrayMap", :at [clojure.lang.AFn throwArity "AFn.java" 429]}], :trace [[clojure.lang.AFn throwArity "AFn.java" 429] [clojure.lang.AFn invoke "AFn.java" 28] [sandbox$eval93 invoke "NO_SOURCE_FILE" -1] [clojure.lang.Compiler eval "C...
07:22oddcullyclojurebot: stop confusing me!
07:22clojurebotPardon?
07:22oddcully,@mutable-map
07:22clojurebot{:a 1}
07:24blashyrkthanks!
07:24opqdonut,(deref mutable-map) -- aka
07:24clojurebot{:a 1}
07:28TEttinger(inc oddcully)
07:28lazybot⇒ 1
07:35mavbozoi put core.async/<! inside a try catch block the repl, I get this exception CompilerException java.lang.RuntimeException: Unable to resolve symbol: user in this context, compiling:(/tmp/form-init7054017936426169058.clj:1:1)
07:35mavbozohttps://www.refheap.com/99395
07:36mavbozoweird, why it can not resolve the symbol of the namespace?
07:36mavbozoany suggestions on how to debug this problem?
07:39TEttingerthat is odd, you didn't, say, paste an earlier line that started with user> did you?
07:41mavbozoTEttinger, no, i included the 'user>' prompt in the paste as a information that i was in namespace named 'user'
07:42TEttingeryeah, it's odd that it's not understanding the ns properly
07:42TEttingervery very strange
07:56farzadguys can i ask a dumb question? :D
07:56TEttingerno, there are no dumb questions
07:56TEttingergo right ahead :)
07:56TEttinger~ask
07:56clojurebotThe Ask To Ask protocol wastes more bandwidth than any version of the Ask protocol, so just ask your question.
07:57farzadok how do i subclass a class like Class SimpleChannelInboundHandler<I>
07:57farzadthat <I> thingie is puzzling me
07:58TEttingerit's a generic type, which actually isn't even used at the VM level. it's the same to clojure as SimpleChannelInboundHandler
07:59TEttingera good example is the Java class ArrayList<T>, which usually contains one type specified by T. you could have, say, ArrayList<Point>
07:59TEttingerbut clojure doesn't care, because the <T> is erased after compilation anyway, and is only used by Java to make sure that the ArrayList is what it thinks it is
07:59farzadwell i subclass that with proxy and i get a class cast exception :/
08:00TEttinger(doc proxy)
08:00clojurebot"([class-and-interfaces args & fs]); class-and-interfaces - a vector of class names args - a (possibly empty) vector of arguments to the superclass constructor. f => (name [params*] body) or (name ([params*] body) ([params+] body) ...) Expands to code which creates a instance of a proxy class that implements the named class/interface(s) by calling the supplied fns. A single class, if provided, must be first. If not provided it default
08:00TEttingerthis is a tough docstring...
08:00farzadlemme read that brb
08:02TEttinger,(.add (proxy [ArrayList] [] (add [o] 5)))
08:02clojurebot#error{:cause "Can't resolve: ArrayList", :via [{:type clojure.lang.Compiler$CompilerException, :message "java.lang.Exception: Can't resolve: ArrayList, compiling:(NO_SOURCE_FILE:0:0)", :at [clojure.lang.Compiler macroexpand1 "Compiler.java" 6636]} {:type java.lang.Exception, :message "Can't resolve: ArrayList", :at [clojure.core$proxy$fn__5680 invoke "core_proxy.clj" 329]}], :trace [[clojure.core...
08:02TEttinger,(.add (proxy [java.util.ArrayList] [] (add [o] 5)))
08:02clojurebot#error{:cause "No matching field found: add for class sandbox.proxy$java.util.ArrayList$ff19274a", :via [{:type java.lang.IllegalArgumentException, :message "No matching field found: add for class sandbox.proxy$java.util.ArrayList$ff19274a", :at [clojure.lang.Reflector getInstanceField "Reflector.java" 271]}], :trace [[clojure.lang.Reflector getInstanceField "Reflector.java" 271] [clojure.lang.Ref...
08:02TEttingerI uh don't use proxy much
08:03farzadwell nothing new in the doc
08:03farzadi use proxy for other thing with no problem
08:03farzadthings*
08:03TEttinger,(.add (proxy [java.util.ArrayList] [] (add [this o] 5)))
08:03clojurebot#error{:cause "No matching field found: add for class sandbox.proxy$java.util.ArrayList$ff19274a", :via [{:type java.lang.IllegalArgumentException, :message "No matching field found: add for class sandbox.proxy$java.util.ArrayList$ff19274a", :at [clojure.lang.Reflector getInstanceField "Reflector.java" 271]}], :trace [[clojure.lang.Reflector getInstanceField "Reflector.java" 271] [clojure.lang.Ref...
08:03TEttingerhm
08:04TEttingeryou don't include the <I> just so we're clear
08:04farzadyup
08:05farzadthis is the proxy (defn get-handler []
08:05farzad (proxy [io.netty.channel.ChannelHandler] []
08:05farzad (channelRead [context msg]
08:05farzad (alert "Channel Read:" "")
08:05farzad (.close context))
08:05farzad (exceptionCaught [context cause]
08:05farzad (println "Exception Caught:" context cause)
08:05farzad (.close context))))
08:05Empperidoesn't proxy methods always have to have "this" as the first argument?
08:06Empperiwhich effectively references the proxy object itself
08:06farzadno its there by default
08:06EmpperiI'm pretty sure it isn't
08:06Empperinot 100% though
08:06farzadEach method fn takes an additional implicit
08:06farzadfirst arg, which is bound to 'this.
08:06farzadread the doc
08:07hyPiRion,(= (proxy [Object] (equals [this that] false)) 1)
08:07clojurebot#error{:cause "Unable to resolve symbol: equals in this context", :via [{:type clojure.lang.Compiler$CompilerException, :message "java.lang.RuntimeException: Unable to resolve symbol: equals in this context, compiling:(NO_SOURCE_PATH:0:0)", :at [clojure.lang.Compiler analyze "Compiler.java" 6535]} {:type java.lang.RuntimeException, :message "Unable to resolve symbol: equals in this context", :at [...
08:08farzadyou need to put [] after [Object]
08:08farzadfor empty param
08:08hyPiRion,(= (proxy [Object] [] (equals [that] true)) 1)
08:08clojurebottrue
08:09hyPiRionwell there you go
08:09hyPiRion,(= (proxy [Object] [] (equals [that] (prn this) true)) 1)
08:09clojurebot#object[sandbox.proxy$java.lang.Object$ff19274a "sandbox.proxy$java.lang.Object$ff19274a@5a7bfbc6"]\ntrue
08:10TEttingerwow nice
08:11hyPiRionthis is the answer to almost every 4clojure problem
08:13farzadso any ideas why i get that cast exception?
08:20TEttingerhyPiRion, that's evil
08:20TEttinger"you just redefine equality so you're always right, classic political computer science"
08:20TEttingerit depends on what the meaning of the word is... is
08:36TEttingerwow. https://twitter.com/servertastic/status/586113649766494208
08:36justin_smithhaha
08:37mavbozoi think i got disconnected
08:37mavbozoTEttinger, i found the source of the problem. but still, very strange
08:37mavbozoit's the ordering in :dependencies for clojure.core.async and pedestal-service. the problem happens if i put pedestal-service before clojure.core.async
08:37TEttingerwoah, wow
08:37TEttingerhow did you find that? nice work
08:39justin_smithgo blocks are weird
08:39TEttinger(inc mavbozo) ; for the independent spirit that keeps clojure going
08:39lazybot⇒ 5
08:39mavbozobisecting the dependencies vector and removing each part til i the problem gone
08:41mavbozoeven writing [io.pedestal/pedestal.service "0.4.0-SNAPSHOT" :exclusions [[org.clojure/core.async]]] still doesn't remove the problem
08:41justin_smithmavbozo: that vector nesting is too deep (has to do with a weird bug in lein deps :tree output that it would even suggest such a thing)
08:42raggemavbozo: did you diff output of `lein deps :tree` with/without problematic dep order?
08:42bordatoueanyone experienced any issue with GC pauses, due to vmop taking long time
08:44mavbozojustin_smith, fixed it like this [io.pedestal/pedestal.service "0.4.0-SNAPSHOT" :exclusions [org.clojure/core.async]]
08:44mavbozojustin_smith, and the problem still happens
08:44justin_smithmavbozo: oh, OK
08:45mavbozoragge, ok, i'll try to diff those
08:46raggemavbozo: this can also be useful: `lein classpath | tr ':' '\n' | sort`
08:47raggeto see what actually ends up on your classpath
09:03mavbozoragge, here is the result from my terminal on diffing the problematic deps with non-problematic deps
09:03mavbozohttps://www.refheap.com/99396
09:04mavbozolooks like the difference is only the version of org.clojure/tools.analyzer.jvm
09:05farzadanyone see something wrong with this error message? "Cannot cast io.netty.channel.ChannelInboundHandlerAdapter to [Lio.netty.channel.ChannelHandler;"
09:05farzadthat [Lio part bugs me
09:06justin_smith[Lio.netty.channel.ChannelHandler; is how the jvm says io.netty.channel.ChannelHandler[]
09:06justin_smithit means the same thing
09:06justin_smith,(type (double-array [0.0]))
09:06clojurebot[D
09:06farzadi see thanks
09:06justin_smith,(type (into-array ["hello" "world"]))
09:06clojurebot[Ljava.lang.String;
09:07justin_smithso anyway, it's getting a ChannelInboundHandlerAdapter where it expects to get an array of ChannelHandlers
09:07justin_smithyou may need to use into-array? perhaps it was a varargs method?
09:08justin_smithyou need to create arrays to use varargs
09:08farzadoh... let me check that
09:08justin_smithif that's the case, the example with the strings above is how you do that
09:08justin_smithit takes an optional type argument
09:09justin_smith,(type (into-array Number [0.0]))
09:09clojurebot[Ljava.lang.Number;
09:09farzadyes! thank you!
09:10justin_smithnp - this is another one to add to my "why did my clojure code broke" blog
09:10justin_smith(which isn't up yet)
09:11farzadXD
09:11farzadthe java code is this: ch.pipeline().addLast(new TimeClientHandler());
09:11justin_smithahah, and addLast was varargs
09:11farzadwhy doesn't that throw cast exception?
09:12farzadoh i see
09:12justin_smithbecause javac turns the varargs into a list automatically
09:12justin_smiththe clojure interop does not do this
09:13farzaddamn, should have checked the addLast doc...
09:13farzadwasted a nice couple of hours on this
09:13justin_smithfarzad: well now, you know that errors mentioning that it expects Lfoo; means it was probably varargs (or at the very least it wanted an array)
09:14justin_smithI mean "now you know"
09:14farzadyep thanks again man!
09:14justin_smithfarzad: and that's why I need to put this oral tradition from #clojure in a blog
09:14justin_smithso many "simple" things that you wouldn't really figure out on your own
09:15mavbozolike dependencies ordering problem
09:15justin_smithhaha, that too
09:16blashyrkcan someone who's willing to help me regarding changing a map (mutability) please send me a private message? thanks
09:16justin_smithclojure hash-maps are not mutable
09:17justin_smithat least not in any sane manner
09:17farzadjustin_smith: if you ever start that blog, post it to /r/clojure maybe they put it next to the must read links XD
09:17justin_smithfarzad: yeah, I'll be sure to put out the signal once it's ready
09:17justin_smithI really need to get off my lazy ass and do more writing for that actually
09:19blashyrk@justin_smith I can see that, but I'd appreciate any help (even doing it in an utterly 'insane' way). I'm about to start pulling my hair out
09:21justin_smithblashyrk: clojure is a functional language, the point of the language is that we can do these things without mutation, maybe if you give a small example of what you are trying to do we can help you. It's an actual proven scientific thing that anything that can be calculated via mutation can be calculated without mutation using recursion
09:21justin_smith"scientific" as in there are CS proofs of this
09:22blashyrkOk, I'll put up a pastebin
09:30dnolenblashyrk: I don't think you need to paste anything yet. If you need state why are you not putting your map in an atom?
09:31blashyrkI don't explicitly need state
09:31blashyrkI just need to alter the map once like this
09:31blashyrkhttp://pastebin.com/cCfRMT7J
09:31blashyrkthis is the fictional map
09:31justin_smithdnolen: he just wants to merge some maps
09:31justin_smithdnolen: he doesn't need mutation at all
09:31blashyrkwhat I want to do is fill the "defaults" onto each "model"
09:31dnolenblashyrk: then you don't need to mutate the map
09:32dnolen,(merge {:foo 1} {:bar 2})
09:32clojurebot{:foo 1, :bar 2}
09:32blashyrkmeaning if :something or :something2 are omitted in the "model" map, they should be added
09:32justin_smithblashyrk: yes, that's what merge does
09:32blashyrkyes, but I also need some aditional logic in case a default value is overriden
09:33dnolenblashyrk: so write that logic
09:34blashyrklet me see
09:39blashyrkso how could I merge those that aren't overriden in the models and do something else for those that are?
09:40dnolenblashyrk: there are lot of ways to do this
09:40blashyrkalso it seems that merge would automatically overwrite the values under the same keys
09:41dnolenyou know the keys in the default map, you can get these keys, you can get the user supplied options keys
09:41dnolenyou can set difference to figure out what precisely is going to be supplied by the user
09:41justin_smithblashyrk: merge goes in a predictable direction
09:42dnolen,(merge {:default 'default} {:default 'custom})
09:42clojurebot{:default custom}
09:42justin_smithblashyrk: the keys from a later argument in the list will not be replaced by keys earlier in the list
09:42dnolen,(merge {:default 'default} {:other 'foo})
09:42clojurebot{:default default, :other foo}
09:42blashyrkalright, that's one part of the problem solved :)
09:43blashyrkthanks guys
09:43blashyrkfor the other part of the problem, let's keep it simple and say I just want to concatenate the two entries under the same key
09:43justin_smithblashyrk: merge-with
09:44dnolen,(merge-with concat {:foo [1]} {:foo [2]})
09:44clojurebot{:foo (1 2)}
09:44blashyrkah
09:44blashyrkso the entire problem turned out to be a two-liner
09:44blashyrkthanks a lot
09:45blashyrkI have still a ways to go in terms of transferring my mindset from imperative to functional programming
09:45justin_smithit's worth it :)
09:46justin_smiththe only drawback is that some things really do require imperative programming for pragmatic reasons, and you won't enjoy going back
09:46puredangerBronsa: yt?
09:46Bronsapuredanger: yes, hi
09:46puredangerhey, I looked through your changes and they look good
09:47puredangernice catch in that one read-tagged* case too :)
09:48puredangerI was just reading through the cljs change dnolen is working on and one thing I really don't like poking through over there is the knowledge of pending-forms
09:48Bronsapuredanger: what do you think about the TaggedLiteral/ReaderConditional change?
09:48puredangerthat's fine
09:49puredangerthe pending-forms stuff is purely an implementation detail and something that we've discussed alternative solutions for
09:49Bronsaright, I saw that in the cljs code too
09:49puredangerin the clojure one, the read arities that take that are private
09:50puredangerdo you think we could pull the read arities that take pending-forms into a different private function?
09:50puredangerread-internal or something?
09:50puredangerwe could either add an arity or cljs could call into the existing opts-only one - I've already recommended he do that
09:50Bronsapuredanger dnolen I don't think cljs needs to use that arity though, the opts+stream arity should be fine
09:50puredangeryes, that's what I'd recommend too
09:51puredangerbut I don't want to expose the pending-forms ones so other people might use them
09:51Bronsapuredanger: current workaround is to inject custom arglists https://github.com/clojure/tools.reader/commit/eb5153cbaec849e726cdac0202c446380a21e19a#diff-c18d0a09dfeefd43739ea3593cf209d2R881
09:52Bronsamoving the impl to a private read-internal is reasonable though
09:52puredangerseems easier to move those to private fn
09:52puredanger(the alternate impl we've talked about is having a reader that could wrap the pbr and allow you to pushback whole forms instead, rather than keeping the side buffer)
09:52puredangerwe still might do that in the clojure one, but we didn't want to gate on getting around to that
09:55raggemavbozo: sorry went away for a while. difference between tools.analyzer versions is huge (0.6.5 vs. 0.1.0-beta12) so I wouldn't be surprised if things expecting 0.6.5 would break
09:56raggethings like the core.async go macro, for instance
09:56dnolenpuredanger: Bronsa: what does it need to look like, two arg read does not work
09:57mavbozoragge, at least my problem gone when I exlude tools.analyzer from pedestal-service and then put core.async after pedestal
09:57mavbozolike this, https://www.refheap.com/99401
09:57Bronsadnolen: (read {:eof eof-sentinel} pbr) should work
09:58mavbozoragge, might be related to this http://dev.clojure.org/jira/browse/ASYNC-86
09:58Bronsamavbozo: next core.async release will be t.a 0.6.5 compatible
09:58dnolenBronsa: strange to flip the order for arity 2 but ok
09:58Bronsadnolen: that's how c.c/read does it
09:58dnolenerg
09:58puredangerBronsa: dnolen rich requested that for partial-ing
09:59mavbozo(inc ragge) ; for pointing the way to find which dependency which causes the problem
09:59lazybot⇒ 1
09:59puredangermavbozo: that change has not yet been released in core.async
10:02dnolenpuredanger: Bronsa: done
10:05acron^noob question?
10:05acron^how would I swap! using cons
10:06acron^I can't seem to get the syntax quite right
10:06justin_smith,(let [a (atom 1)] (swap! a cons '(2 3)))
10:06Bronsadnolen: puredanger merging, will cut 0.9.0 in a couple of minutes
10:06clojurebot(1 2 3)
10:06acron^using conj: (swap! my-atom conj new-value)
10:07justin_smithacron^: not particularly useful - cons requires the thing to be added as the first arg
10:08acron^hmm, i suppose i could just use reverse...
10:08justin_smithwhy reverse?
10:08justin_smithif the collection is not a vector, conj will do the what you expect
10:08justin_smithjust make sure you have the collection type with the behavior you require
10:09acron^i want the item adding at the front of the collection, not the end
10:09acron^that's all
10:09justin_smith,(let [a (atom '(1))] (swap! a conj 0))
10:09clojurebot(0 1)
10:09justin_smithacron^: right, like I said, if you have the right collection type, conj will do what you want
10:09acron^interesting
10:10justin_smithacron^: conj is meant to add in the most efficient place
10:10justin_smithwhich is different for different collection types
10:10acron^I see
10:11acron^Are there any implicit differences for using a list over a vector?
10:11acron^when using*
10:11justin_smithlists are not good for indexed lookup
10:11acron^ok
10:11acron^that's fine
10:11acron^for my use case
10:11acron^thanks justin!
10:11justin_smithnp
10:31m4farrelis there a function like scan in clojure? i.e. reduce with a running total: (scan + 0 [1 2 3]) => [0 1 3 6] ?
10:31justin_smithm4farrel: reductions
10:31justin_smith,(reductions + 0 [1 2 3])
10:31clojurebot(0 1 3 6)
10:32m4farreljustin_smith: thanks
10:52tapHi there, quick question. I want to gen-class that similar to this class https://github.com/properssl/java-jdbc-postgresql/blob/master/src/main/java/org/properssl/SingleCertValidatingFactory.java. What's the equivalent expression to `_factory = ...` in clojure?
10:53tapModifying protected member of a super class
10:53justin_smithwell, initializing right?
10:54justin_smithanyway, I think you would want reify or proxy, and inside that you can establish the values of fields
10:54justin_smithreify if WrappedFactory is an interface, proxy otherwise
10:57tapOk. WrappedFactory is an abstract class. Thanks for pointing out that I shouldn't use gen-class here. Good to know that I was learning the wrong thing for this.
10:57tapNeed to reread a bit more about proxy
10:58justin_smithtap: it would be possible with gen-class, but gen-class usually isn't the easier way to do something - best reserved as the last resort before writing java code
11:02tapjustin_smith: I got a (wrong) impression that proxy is for creating an object. What I want is a class to replace 'NonValidatingFactory' in `sslfactory=org.postgresql.ssl.NonValidatingFactory` . FYI, I'm refering from this document https://jdbc.postgresql.org/documentation/81/ssl-client.html
11:04justin_smithtap: oh, if you specifically need a class and not a class instance, then you I think you'll need gen-class
11:07tapjustin_smith: Ok. So for gen-class, I should be able to set `_factory` from `init` function, right? I can't really find an example to do that.
11:07justin_smithtap: for your initial question, you want the :exposes key to gen-class if you are creating a field that must be visible
11:08tapjustin_smith: please disregard my previous message, didn't saw your recent one.
11:09justin_smithalso, see the :state key if you need to create a field
11:09justin_smithand :init for setting fields of the superclass
11:11justin_smithso if you need to set something protected on the parent, you create a setter with :exposes and then call it in your :init
11:11justin_smithtap: if you haven't seen it, conj.io is helpful in general http://conj.io/store/v1/org.clojure/clojure/1.7.0-alpha4/clj/clojure.core/gen-class/
11:15ircxy,(Math/pow 1.4 1/3)
11:15clojurebot1.1186889420813968
11:15ircxy,(let [y 3] (Math/pow 1.4 1/y)) ; fails
11:15clojurebot#<NumberFormatException java.lang.NumberFormatException: Invalid number: 1/y>
11:15tapjustin_smith: conj.io looks nice. I like the syntax highlight. Never heard about it before. For some reason, it never hit my search result
11:15justin_smithircxy: x/y is not a function call, it is a syntax for literals
11:16justin_smithircxy: you can't embed a symbol in that kind of numeric literal
11:16ircxyIs there a way to use a var in a fraction?
11:16justin_smithircxy: it's the equivalent of (let [x 9] 1.x)
11:16justin_smithircxy: sure, use the / function
11:17justin_smithtap: it's a relatively recent thing, but arrdem puts a lot of work into it
11:17justin_smith,(let [y 3] (/ y))
11:17clojurebot1/3
11:17ircxyjustin_smith: right on! ,(/ 1 3)
11:17justin_smithircxy: it's special cased so that (/ x) is the same as (/ 1 x)
11:17justin_smithwhich is the most frequent usage, so that's cool
11:18ircxyjustin_smith: very cool,thanks!
11:18justin_smith,(/ (/ 20))
11:18clojurebot20N
11:18justin_smith:)
11:18justin_smith,(iterate / 20)
11:18clojurebot(20 1/20 20N 1/20 20N ...)
11:19tapjustin_smith: thanks for pointing out :exposes. I'll learn more about it tomorrow. It's late night here
11:27dnolenClojure 0.0-3190 pre-release going out to Maven and available here https://github.com/clojure/clojurescript/releases/tag/r3190
11:27dnolenincludes conditional reading support, which touched many things
11:28dnolenso needs some serious tire kicking. If no bad news, would like cut a proper release tomorrow
11:29dnolener s/Clojure/ClojureScript of course
11:29saik0Any book recommendations for somebody familiar with java and lisps (scheme in my case), nice and terse?
11:30justin_smith~books
11:30clojurebotbooks is programming clojure
11:31justin_smiththere's also "joy of clojure" which shows more common lisp influence and takes a more erudite approach
11:31justin_smiththat is, it kind of expects you either know things its referencing or can go read up yourself
11:31justin_smithnot that it's a dissertation or anything, just less beginner focused
11:32saik0justin_smith: thanks
11:32tbaldridgesaik0: if you know Java and Scheme, I highly recommend Joy of Clojure...
11:32justin_smithyeah, it's a great book if you don't let it intimidate you :)
11:32tbaldridgelike justin_smith said, it gets rather advanced rather quickly, but sounds like that's what you want/need
11:35saik0tbaldridge: right, I'm mostly concerned with poking Clojure's macros and concurrency/parallism. not a 5 chapter into to functional programming. sounds up my alley thanks both of you.
12:46crazydiamondHi. Is there way to beautify (pretty-print) bunch of data in Clojure other than clojure/pprint.prrint? It fails for me, while println works well
12:47justin_smithcrazydiamond: fails?
12:47justin_smithcrazydiamond: are you trying to supply multiple arguments? the solution is to pprint each thing separately, or put them all in one vector or hash-map
12:48crazydiamondjustin_smith, StackOverflow errr
12:48crazydiamond*error
12:48justin_smithoh, wow
12:48justin_smithinfinite lazyseq?
12:48crazydiamondjustin_smith, may be, yes, something lazy
12:48crazydiamondthough unlikely infinite
12:49crazydiamondmay I... make all lazy stuff non-lazy?
12:49crazydiamondmust I postwalk or something? but with what func
12:49justin_smithif you fully realize the collection via walk/post-walk, do you get the same error?
12:49justin_smithor just walk/tree-seq
12:49justin_smith,(require 'clojure.walk)
12:49clojurebotnil
12:50justin_smith,(clojure.walk/tree-seq {:a 0 :b [1 2 3]})
12:50clojurebot#error{:cause "No such var: clojure.walk/tree-seq", :via [{:type clojure.lang.Compiler$CompilerException, :message "java.lang.RuntimeException: No such var: clojure.walk/tree-seq, compiling:(NO_SOURCE_PATH:0:0)", :at [clojure.lang.Compiler analyze "Compiler.java" 6535]} {:type java.lang.RuntimeException, :message "No such var: clojure.walk/tree-seq", :at [clojure.lang.Util runtimeException "Util.j...
12:50justin_smitherr
12:50justin_smith,(tree-seq {:a 0 :b [1 2 3]})
12:50clojurebot#error{:cause "Wrong number of args (1) passed to: core/tree-seq", :via [{:type clojure.lang.ArityException, :message "Wrong number of args (1) passed to: core/tree-seq", :at [clojure.lang.AFn throwArity "AFn.java" 429]}], :trace [[clojure.lang.AFn throwArity "AFn.java" 429] [clojure.lang.AFn invoke "AFn.java" 32] [sandbox$eval72 invoke "NO_SOURCE_FILE" -1] [clojure.lang.Compiler eval "Compiler.ja...
12:51justin_smith,(tree-seq coll? seq {:a 0 :b [1 2 3]})
12:51clojurebot({:a 0, :b [1 2 3]} [:a 0] :a 0 [:b [1 2 3]] ...)
12:51crazydiamondyep
12:51justin_smithyep as in you do get the same error?
12:51crazydiamond1 sec
12:52crazydiamondyes
12:52justin_smithright, so there is a problem with the code generating one of your lazy-seqs I think
12:53crazydiamondI was thinking to turn it into the str and parse
12:53crazydiamondLOL
12:53crazydiamondbut I don't have anything like (range) though
12:54justin_smithconcat? sometimes nested concat calls can lead to weirdness (especially if you had something chunked like range or a vector going in)
12:54crazydiamonduhm, a lot of vecs
12:55hiredmancrazydiamond: have you tried fipp?
12:55hiredmanhttps://github.com/brandonbloom/fipp
12:55crazydiamondno
12:55crazydiamondhiredman, thanks!
12:56bbloomcrazydiamond: if fipp doesn't work for you, please file an issue w/ a minimal repo
12:57crazydiamondbbloom, hiredman works! excellent
13:00noncomcan anyone confirm that when you add [selmer "0.8.2"] to your project.clj and then (:require [selmer.parser :as selmer]) in some ns of your project, you get an exception of classloading ?
13:00justin_smith(inc bbloom)
13:00lazybot⇒ 54
13:17noncomnope, spotted
13:19mavbozononcom, you found the culprit?
13:20noncommavbozo: yes, had to manually delete the "bin" and "target" folders..
13:33michaler`suddenly cursive went crazy indenting defn and def
13:33michaler`anyone else experience this?
13:33michaler`I think it's related to the latest release which I've updated today
13:34michaler`cfleming: ping
13:36KKalemYou sure you don't have an open paren above somewhere?
13:39michaler`KKalem: pretty sure, it's also shown like that in the preview in the settings screen
13:40michaler`can I downgrade to a previous version with cursive?
13:46michaler`ah it's in the usersguid
13:46michaler`guide
13:51cljnoobI have implemented a "frequencies" like function using reduce... I based it off the example listed on the reduce function documentation. http://pastie.org/10082946 My question is in regard to line 3: " (fn [hm char] (assoc hm char (inc (hm char 0))))". Why is 0 a second argument to the (hm char 0) function call?
13:52justin_smithcljnoob: ##({:a 1} :a 0)
13:52lazybot⇒ 1
13:52justin_smithcljnoob: ##({} :a 0)
13:52lazybot⇒ 0
13:52justin_smith(doc get)
13:52clojurebot"([map key] [map key not-found]); Returns the value mapped to key, not-found or nil if key not present."
13:53cljnoobah, it's a default value. make sense
13:53justin_smith,(update-in {} [\a] (fnil inc 0))
13:53clojurebot{\a 1}
13:53justin_smithanother way to express that assoc
13:54justin_smiththough fnil should be pulled out to a binding if this is a tight loop
13:54justin_smithiirc
13:54michaler`it didn't help
13:54michaler`damn
13:55cljnoobjustin_smith:i'll play around with it. Thanks!
13:55justin_smithmichaler`: you're absolutely certain you don't have something in there that messes up the indentation? extra open parens?
13:55justin_smithor maybe some missing close paren
13:55michaler`justin_smith: nope, it happens in every file
13:55justin_smithweird
13:56michaler`maybe I accidently pressed some key combination that changed something in Intellij
13:56justin_smithmichaler`: my attitude to IDEs in general is kind of like that ancient aliens guy "IDEs" (complete with crazy hair and waving hands)
13:57michaler`heh
13:57michaler`justin_smith: your attitude to IDEs doesn't help me solve my problem ;)
13:58KKalemjustin_smith, you need an IDE with an attitude~
13:58justin_smithclearly the IDE gods have cursed your intellij installation, and you need to delete some fetish file, or offer it a fresh dead chicken
13:58andyfmichaler`: It does if you stop using IDEs :)
14:03constlIs there a way to evaluate an argument inside a string ?
14:04justin_smithconstl: you can use (eval (read-string s)) but usually eval is the wrong thing
14:04justin_smith~eval
14:04clojureboteval is sometimes useful - but only sometimes
14:05constlMaybe "evaluate" was a wrong choice of word
14:05constlhmm
14:06justin_smithconstl: what do you want done? conversion of string to integers / symbols / keywords? read-string suffices for that
14:06constl(let [my-name "Konstantinos"] (print "Hello my-name !)
14:06justin_smithwell, you don't even need to covnert anything for that
14:06justin_smith*convert
14:06constlI recal something that i have to put before my-name so that it prints the value instead of the literal
14:07justin_smithabsolutely not
14:07constlno?
14:07clojurebotno is tufflax: there was a question somewhere in there, the answer
14:07justin_smith,(let [my-name "Konstantinos"] (println "hello" my-name \!))
14:07clojurebothello Konstantinos !\n
14:08justin_smithif you want the literal instead of the value, you can use '
14:08justin_smith,(let [my-name "Konstantinos"] (println "hello" 'my-name \!))
14:08clojurebothello my-name !\n
14:08constljustin_smith: Is there a way to use print with only one argument and have my-name somehow print the value?
14:09justin_smithyou mean string interpolation?
14:09justin_smithwe have format
14:09justin_smithor various templating libs I guess
14:10justin_smith,(let [my-name "Konstantinos"] (println (format "hello %s" my-name)))
14:10clojurebothello Konstantinos\n
14:11justin_smithsomething like eg. selmer will let you use "hello {{my-name}}" or something close to it
14:11constlCan you print the value by only using this form (print "Hello, <my-name-value> !")
14:11justin_smithconstl: you'd need a templating lib for anything like that
14:12justin_smithnot something immediately available in clojure.core
14:12constlI recall something like \" " or something like that
14:12justin_smithand no, you would not be able to do that with just print either
14:12justin_smithconstl: that's just a way to put " in a string
14:12justin_smithand it still involves multiple args
14:13justin_smith,(let [my-name "Konstantinos"] (println (str "hello " my-name)))
14:13clojurebothello Konstantinos\n
14:13justin_smiththere's always that, but that's not much different than just using multiple args to println
14:15danielglauserAnd multiple args to println will put spaces in there
14:15danielglauser,(let [my-name "Konstantinos"] (println (str "hello " my-name)))
14:15clojurebothello Konstantinos\n
14:15danielglauser,(let [my-name "Konstantinos"] (println (str "hello " my-name "!")))
14:15clojurebothello Konstantinos!\n
14:15danielglauserDoh! Third try...
14:16danielglauser,(let [my-name "Konstantinos"] (println "hello" my-name "!")))
14:16clojurebothello Konstantinos !\n
14:16danielglauserIMHO format is the idiomatic way to do what you are looking to do
14:18constlthanks for the help all
14:22oddcully,(let [rep {"name" "World" "greeting" "Hello"}] (clojure.string/replace "<greeting> <name>" #"<(.*?)>" #(get rep (%1 1))))
14:22clojurebot"Hello World"
14:24justin_smithoddcully: nice
14:25oddcullyconstl: ^^ poor mans version of what you are after; yet i'd rather go for some template engine
14:28cflemingmichaler`: Did you get that fixed?
14:43michaler`cfleming: hi
14:43michaler`cfleming: no..
14:44michaler`cfleming: I checked "default to indent only" as a temp workaround
14:44michaler`cfleming: do you have an idea?
14:46cflemingmichaler`: Are you getting a lot of unresolved symbols?
14:46michaler`cfleming: nope
14:46michaler`cfleming: everything works as usual
14:46cflemingmichaler`: Ok - are you using leiningen?
14:46michaler`yes
14:47michaler`is there another way? :)
14:47michaler`yes of course there is..
14:47cflemingOk, is your lein project present in your Leiningen toolwindow?
14:47michaler`let me check
14:47michaler`yes, it's there
14:47michaler`as usual
14:47cflemingHehe, yes - I don't use lein for Cursive, although I do use it to fetch the deps
14:48cflemingWeird - so what's the problem that you're seeing?
14:48michaler`cfleming: would you like to do a remote session?
14:48michaler`teamviewer?
14:49cflemingmichaler`: I'm just about to head in to the office, it would have to be in about 30-45 mins
14:49michaler`cfleming: the problem is that although def/defn is set to ident only, they are formated as if they are set to 1
14:49michaler`cfleming: ok, cool
14:51cflemingmichaler`: Ok, if you got to Settings->Editor->Code Style->Clojure->Form parameters, what are def and defn set to?
14:51michaler`cfleming: indent
14:52cflemingmichaler`: Well that is really weird. Is this problem when you hit enter while typing the form, or when you reformat the whole file?
14:52cflemingmichaler`: Is the code open or is it a work thing?
14:52cflemingmichaler`: Does this happen for other projects as well?
14:53michaler`shit
14:53michaler`it's gone
14:54michaler`sorry
14:54michaler`err
14:54cflemingmichaler`: The problem is gone?
14:54michaler`yes..
14:54cflemingWell that's good :-)
14:54cflemingWhat I suspect has happened is that the indexes might have gotten in a funky state after the update
14:54michaler`i started checking if it happens only on reformat and then it's gone
14:55cflemingTry File->Invalidate caches and restart, which will force them to be rebuilt
14:55michaler`cfleming: yes, it's possible.. I also had a dirty shutdown of the coputer after which intellij complained about some corrupted files
14:55cflemingJust ignore the crazy guy in the corner
14:55justin_smith:)
14:55michaler`cfleming: but it happened this morning..
14:56cflemingmichaler`: Oh ok, I bet that was it then
14:57michaler`cfleming: ok, thanks
14:57michaler`cfleming: when can I start paying you for Cursive? :)
14:58cflemingmichaler`: Soon, I think - sometime after Clojure/West :)
14:58timvisheri _should_ be able to override `:uberjar-name` in a project.clj profile right?
14:59michaler`cfleming: ah, ok.. then I'll patiently wait ;)
15:00mavbozotimvisher, yep
15:00michaler`justin_smith: btw, I hope you are not suggesting emacs as the cure for IDEs..
15:00timvishermavbozo: good :)
15:00justin_smithmichaler`: oh, absolutely not
15:00justin_smithI'm just being a jackass :)
15:00michaler`heh
15:01justin_smithmichaler`: cider has had issues that could compete with any IDE's worst
15:01michaler`yeah, it true.. and emacs is a nightmare on it's own..
15:02amalloyjustin_smith confirmed trouble-maker
15:09andyfI'm not recommending it to anyone that wants IDE-like features, but emacs + clojure-mode is all I use
15:10constlIs there a way to get the number of arguments passed in a function with variadic arity?
15:11justin_smithconstl: ##((fn [& args] (count args)) [1 2 3])
15:11lazybot⇒ 1
15:11justin_smithconstl: ##((fn [& args] (count args)) 1 2 3)
15:11lazybot⇒ 3
15:14constl##((fn [one two & args] (count args)) [1 2 3])
15:14lazybotclojure.lang.ArityException: Wrong number of args (1) passed to: sandbox6330/eval46602/fn--46603
15:16ncthom91hi all. Suppose I have a project wherein I define a simple value at the top of my file.. how can I override/mock that value during testing?
15:17justin_smithncthom91: you can use with-redefs for that
15:17justin_smithncthom91: also worth considering is writing your functions so that the concrete impl that would change at test vs. runtime is a parameter you explicitly pass in
15:18justin_smithand of course defining a trivial wrapper for typical usage
15:18justin_smithmakes testing that much simpler
15:19mavbozoncthom91, there are many ways of managing external dependencies for testing which you can read here http://blog.josephwilk.net/clojure/isolating-external-dependencies-in-clojure.html
15:19justin_smitheg. (defn printer [stream string] (.write stream string)) (def printit (partial printer *out*))
15:21justin_smith(inc mavbozo) ; good link, where'd you find it?
15:21lazybot⇒ 6
15:23mavbozoi spent months studying ways to do dependency injection in clojure until i settle for stuart sierra's approach
15:24mavbozoi think a read almost blog posts
15:24ncthom91hmm cool ok
15:24mavbozos/a/i/
15:27hellofunkif i have (map #(some-fn % (some-op foo bar)) coll) will the (some-op foo bar) run with each pass over a collection item, or does (some-op foo bar) evaluate once into the whole of the map fn?
15:28Kowryhwhat clojure resources would you guys recommend beside the obvious ones (e.g. the docs)
15:28mavbozoKowryh, books
15:28Kowryhhttps://thechangelog.com/rich-hickeys-greatest-hits/ i've yet to watch these, though supposedly they're pretty good
15:29mavbozoKowryh, infoq videos about clojure
15:29justin_smithhellofunk: easy to test ##(map #(cons % (println "check")) (range 10))
15:29lazybot⇒ (check
15:29justin_smithoops
15:29justin_smithhellofunk: easy to test ##(map #(cons % (print "check")) (range 10))
15:29lazybot⇒ (checkcheckcheckcheckcheckcheckcheckcheckcheckcheck(0) (1) (2) (3) (4) (5) (6) (7) (8) (9))
15:29hellofunklazybot is rich! it just wrote a bunch of checks
15:30justin_smithalso, that was some terrible nil punning, before you brought the regular punning in
15:30Kowryhmavbozo: specifically what book(s)?
15:30Kowryhif I were to read only one (for a start)
15:31Kowryhbut thanks, I'll have to check those infoq videos out
15:31mavbozoKowryh, depends on your previous experience with functional programming languages
15:31Kowryhwell it's non-existent
15:31Kowryh(but yeah I should have mentioned that)
15:31mavbozowell, clojure programming or programming clojure
15:32Kowryhthanks, I'll look into those
15:39ncthom91what's the motivation behind putting *earmuffs* on your variable name?
15:40sobelncthom91: keeps ears warm
15:40ncthom91:)
15:40justin_smith,(def *t* 1)
15:40tbaldrid_ncthom91: that normally means that it's a dynamic var, and may be re-bound within a given scope
15:40clojurebot#error{:cause "denied", :via [{:type clojure.lang.Compiler$CompilerException, :message "java.lang.SecurityException: denied, compiling:(NO_SOURCE_PATH:0:0)", :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6732]} {:type java.lang.SecurityException, :message "denied", :at [clojurebot.sandbox$enable_security_manager$fn__835 invoke "sandbox.clj" 69]}], :trace [[clojurebot.sandbox$enable_securit...
15:41ncthom91tbaldrid_ so, convention?
15:41sobelalso helps syntax highlighters find more important variables
15:41sobelncthom91: definitely a convention
15:41tbaldrid_ncthom91: yeah, it's convection
15:41justin_smithncthom91: the usual message for (def *t* 1) would be "Warning: *t* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise."
15:41ncthom91would people use it to identify a variable intended for a with-redefs call in a test suite?
15:41sobelfor example, yes
15:41justin_smithncthom91: well, you wouldn't need with-redefs
15:41tbaldrid_althought, IIRC the compiler does warn you if you create a dynamic var without earmuffs
15:41justin_smithyou could just use binding
15:42sobelor most of the with- family of fcns
15:42justin_smithtbaldrid_: yeah, the warning I was trying to provoke before, but I got bot weirdness instead
15:42ncthom91justin_smith oh, true
15:42sobelit's a common/useful pattern
15:42ncthom91and the ^:dynamic declaration enables binding right?
15:42justin_smithright, and it goes with earmuffs
15:43sobeli like that, earmuffs. i'm going to call the thread macro buttplug.
15:43sobelthreadfirst
15:44ncthom91sobel lol what?? how did we get from earmuffs to buttplug
15:44sobel'we' didn't
15:45ncthom91sorry, you :)
15:46sobeleasily!
15:54puredangertbaldrid_: doesn't it warn if you use earmuffs for a NON-dynamic var?
15:55puredanger,(def *foo* 1)
15:55clojurebot#error{:cause "denied", :via [{:type clojure.lang.Compiler$CompilerException, :message "java.lang.SecurityException: denied, compiling:(NO_SOURCE_PATH:0:0)", :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6732]} {:type java.lang.SecurityException, :message "denied", :at [clojurebot.sandbox$enable_security_manager$fn__835 invoke "sandbox.clj" 69]}], :trace [[clojurebot.sandbox$enable_securit...
15:55justin_smithpuredanger: yeah, I tried to do that above
15:55tbaldrid_yep, it's the other way around
15:55justin_smithclojurebot is a weirdo
15:55puredangersorry :)
15:55tbaldrid_puredanger: is right
15:55tbaldrid_eh... puredanger is right
15:56justin_smith~puredanger is right.
15:56clojurebotIk begrijp
15:56mavbozo~earmuffs
15:56clojurebotTitim gan éirí ort.
16:26akkadin clojure is (sleep 200) the right format?
16:26mavbozo,(doc sleep)
16:26clojurebotexcusez-moi
16:27justin_smithakkad: (Thread/sleep 200)
16:27justin_smithfor jvm clojure
16:27justin_smithit's an interop call
16:27akkadthanks
16:28dnolenBronsa: ping
16:30Bronsadnolen: pong
16:32dnolenBronsa: so any reason (def arr #?(:cljs #js [1 2 3])) might not work?
16:33dnolenBronsa: nothing changed w/ how we bind *data-readers*, the above will read as (def arr [1 2 3])
16:33andyfdnolen: Doesn't splicing need slightly different syntax?
16:34dnolenandyf: this isn't a splicing question
16:35Bronsadnolen: what's not working? I just tried this and it works as expected http://sprunge.us/AZGX?clj
16:35dnolenBronsa: that isn't right
16:35Bronsawhy?
16:35clojurebotwhy is the ram gone
16:35the-kennydnolen: I have a complaint: Why do you always do awesome ClojureScript releases right when I don't have any time to dive into them?
16:37dnolenBronsa: I mean I should see a JSValue in ClojureScript but getting a vector instead
16:37Bronsaah
16:39Bronsadnolen: uh yeah there's definitely a bug there
16:41rurumateIs there something similar to core.logic which produces a (sequence of) random value(s), instead of a list of all values that match the conditions? This would be very useful for unit testing.
16:41dnolenthe-kenny: :), the hard work on this one was done by other people, can't take much credit for this one. Just had to make sure .cljc files can be consumed.
16:42justin_smithrurumate: maybe you want generators?
16:42rurumateI'll check it out thanks
16:42justin_smithrurumate: https://github.com/clojure/test.generative this is what I meant
16:43justin_smithrurumate: see also test.chuck from gfredericks
16:45mavbozowow! a name from a tv series
16:45rurumateI'm looking for something that also generates csv data and strings that match a given pattern, like Xeger
16:45justin_smithrurumate: test.chuck can generate strings that match a regex
16:46rurumateso for instance you could say, I need a list of random vectors [a, b] where a is a number 0 <= a <= 10 and b is (* a 2)
16:46justin_smithyes, test.check can do that
16:47mavbozo(inc gfredericks)
16:47lazybot⇒ 135
16:52programistoreatlively simple clojure problem here
16:52programistohttps://gist.github.com/aaron-lebo/720345a76d08faad4b13
16:52programistoany help appreciated
16:53programisto*spelling
16:53justin_smithprogramisto: looks like you want something more like mapcat
16:53justin_smithrather than map
16:54justin_smithprogramisto: also, it would have worked if you used "apply concat" instead of just "concat"
16:54justin_smithbut that's what mapcat is for, so just use that
16:54programistojustin_smith: thank you
16:54programistoexactly what i needed
16:54justin_smith,(apply concat (map #(vector " " %1) [1 2]))
16:54clojurebot(" " 1 " " 2)
16:55justin_smith,(mapcat #(list " " %) [1 2]))
16:55clojurebot(" " 1 " " 2)
16:55justin_smithlatter is my preferred version, of course
16:55programistoyep it diefnitely worked
16:56programistoi figured something existed, couldn't find it via google
16:58justin_smithprogramisto: conj.io is really useful for this stuff
16:58justin_smithhttp://conj.io/
17:08Bronsadnolen: should be fixed, can you try master? will release 0.9.1 once you confirm it works
17:08dnolenBronsa: trying now
17:15TimMcjustin_smith: Or just use fl-- *is hit by anvil*
17:15justin_smith(inc anvil)
17:15lazybot⇒ 1
17:16justin_smith(inc TimMc)
17:16lazybot⇒ 94
17:16ntaylorhaah
17:19dnolenBronsa: fixed
17:21TimMc(flatten 5) ;;= [1 1 1 1 1]
17:28justin_smith(flatten {:width 1 :height 1 :depth 1}) ;;= {:width 1 :height 1 :depth 0}
17:30TimMc(flatten "a") ;;= ?
17:30TimMc\_
17:33amalloyTimMc: () would be my guess, but i forget
17:33amalloyoh i just got here, you are in some weird fantasy land
17:33TimMcthis should be no surprise
17:33justin_smithhaha
17:34TimMc,(flatten 5) ;; actually
17:34clojurebot()
17:37justin_smithwow, even logicians have a lot of trouble with concurrency and mutability http://en.wikipedia.org/wiki/Yale_shooting_problem
17:38dnolenClojureScript 0.0-3191 going out https://github.com/clojure/clojurescript/releases/tag/r3191, only change is tools.reader bump
17:39TimMcjustin_smith: That's a terrible article.
17:39TimMcit should feel bad
17:41justin_smithTimMc: yes, it's a badly written article
17:42justin_smithhere's another writeup http://web.stanford.edu/~laurik/fsmbook/examples/YaleShooting.html
17:43justin_smithI think the clojure program demonstrating the concept would be pretty short. An agent would be a decent fit.
17:44kwladykaon http://www.clojure-toolbox.com/ there is about 15 web frameworks... why? Are they diffrent or really almost the same?
17:44justin_smithkwladyka: they are not all frameworks. For example Moustache is a templating language.
17:44justin_smithSome of them are defunct.
17:45justin_smithActually, I think most of them on that list are defunct.
17:45kwladykahmm
17:45justin_smithclojure-toolbox should really have a "last updated" date
17:46kwladykai found some atricles, but with data 2014 or older... can you give me some names of web framework what should i be interested in?
17:46kwladykajustin_smith yes it should :)
17:46justin_smithkwladyka: most clojure web devs are not using a framework. There are a number of useful libs. Most of them are compatible with or even dependent on ring.
17:47justin_smithring being the underlying web-server abstraction that is by far most popular
17:47kwladykahmm so are suggesting to use only ring?
17:47justin_smithcompojure is the most popular routing lib. You can do a lot with just compojure and ring (or switch to another router if you get tired of compojure)
17:48kwladykaso use ring + other libs working with ring if i need them?
17:48justin_smithkwladyka: compojure+ring is the most frequent combo I think, but after you get the basics, there are other routing libs too (if you need reverse routing, or dynamically generated routes for example)
17:48justin_smithright
17:48xemdetiasince we are talking about ring is there any neat way to get some verbose build output for lein ring uberwar that I am not seeing?
17:48justin_smithkwladyka: lein new compojure some-name will create a working compojure app
17:49justin_smithxemdetia: not that I know of, are you having some issue with what uberwar does?
17:50dnolenNice https://github.com/LonoCloud/synthread/blob/master/test/lonocloud/synthread/test.cljc
17:51xemdetiajustin_smith, I brought nrepl into my project which is a slew of dependencies but it does not seem like it is ever finishing. I am not seeing io wait or java spinning
17:51kwladykajustin_smith i am thinking about architecture in Clojure. I am reallny not happy with MVC. I believe app should have separated core, UI and database, but.... i am not sure how to build architecure of folders, files, namespaces etc. in Clojure but i feel Clojure will give me power for that :) Can you recommend something to read with example of architecture?
17:52justin_smithin clojure we tend to do things less in terms of architecture and more in terms of well known operations on simple immutible data types
17:52kwladykajustin_smith i can use AngularJS, Clojure, DB it will be easier but if use only Clojure and DB putting HTML into code make me a little confuse how to do that in right way
17:52justin_smiththis is a very broad generalization of course
17:52TimMcdnolen: Does that achieve having a common source file for clj and cljs?
17:53justin_smithxemdetia: you probably do something like (def server (nrepl/start-server)) and that starts a listening server when you compile
17:53xemdetiathat would explain it
17:53justin_smithxemdetia: that's a blind guess, but that's a common source of that problem
17:53xemdetiano the project is pretty much just that. I just want a nice way to shim my tomcats
17:54cflemingping puredanger
17:54puredangeryo
17:54justin_smithxemdetia: if that is the issue, the fix is to have a delay for the nrepl server, that gets forced in -main
17:54justin_smithxemdetia: or a promise that gets delivered if you need parameterization or anything
17:55xemdetiaor a dumb route get request to switch it on
17:55puredangercfleming: question?
17:55justin_smithxemdetia: sure, sure
17:55cflemingpuredanger: I have a reader conditional question: currently I can't see a way that "send top form to REPL" will work with them, since the REPL doesn't know the file type the form came from.
17:55justin_smithxemdetia: but that's compatible with a dleay
17:55justin_smithxemdetia: idea being it's simpler to know that there is only one thing this def could be (even if it isn't realized until later)
17:56puredangercfleming: that was raised by someone on the google group
17:56justin_smithcompare with doing def at runtime, or using a mutable datatype - much more complex
17:56puredangercfleming: I talked to Rich about it briefly and we're considering some way to be able to make the repl understand that
17:56cflemingpuredanger: It was? I didn't see that - I'll check.
17:57puredangerit was a response on the alpha6 release iirc
17:57cflemingpuredanger: Currently it will work in Clojure, because I'm using a horrible load-file hack to get the line numbering right
17:57cflemingpuredanger: But not cljs
17:57xemdetiatrue, I will have to examine that. I just was not identifying me trying to start the nrepl server as a problem when I issued the build job. I am glad I asked
17:58puredangercfleming: the key of course is that repls choose how they read so making the repl more capable enables this (and other things)
17:58cflemingpuredanger: Right, but this needs to be on a form-by-form basis
17:58justin_smithkwladyka: my usual solution is to have a template file (data, from the frontend guy) and a ring request (more data, from the client), and then use a rendering library (I use antlers, selmer is also good, there are other good ones) to synthesize those two data sources (plus maybe some input from clojure.java.jdbc) to make a page
17:59puredangercfleming: in terms of the allowed features or just allowing read conditionals at all?
17:59justin_smithkwladyka: that page is put into a hash map, and returned to ring
17:59kwladykajustin_smith https://github.com/flyingmachine/brave-clojure-web is it good example? Do you know better?
18:00justin_smithkwladyka: is that even a clojure project?
18:00cflemingpuredanger: Just allowing conditionals at all - currently they're not supposed to be allowed in clj files.
18:00kwladykaoh true... its about clojure but not in clojure...
18:00kwladykasorry!
18:00justin_smithkwladyka: like I tried to mention above, if you run "lein new compojure my-app-name" that will create a working webapp from a template
18:00justin_smithand then you can start from there
18:01puredangercfleming: you could programmatically invoke the reader based on the file type, then take the result and send that to the repl :)
18:02kwladykai know but real example will help me to understand the process of code evolving :)
18:02cflemingpuredanger: It wouldn't be the worst thing I've had to do :-)
18:02justin_smithkwladyka: I'd have something to share but sadly my good examples were client work, not open source
18:03kwladykai understand :)
18:03cflemingpuredanger: Like I say, this isn't a problem (for Cursive at least) for Clojure, but it is for CLJS
18:04cflemingpuredanger: CLJS can't use the load-file hack because load-file doesn't return the result of the last evaluation
18:04kwladykathe worst thing in my country (Poland) Clojure is not so popular and i can't find even in one of the biggest city Poznań Clojure programmers, we don't have any meeting groups or something like that. It is really hard to improve skills :)
18:05cflemingpuredanger: Ah yes, I did see those mails but hadn't realised why he would want what he was asking for
18:05justin_smithkwladyka: euroclojure was in Krakow last year iirc
18:05kwladykaBTW: Are you close connected with Clojure? I see you are very active.
18:05justin_smithkwladyka: not to say that means anyone in Poland is using Clojure of course
18:06justin_smithkwladyka: I try to be pretty active, yeah, I am volunteering with clojurebridge next week to teach, and I'll be going to clojure/west in a couple weeks
18:07kwladykathats good, i see Clojure community is very mature :)
18:10cflemingjustin_smith: I'll be keen to hear about your clojurebridge experience, that's cool
18:10cflemingjustin_smith: I volunteer at our local coderdojo, teaching kids to program - mostly with code.org and Scratch
18:10justin_smithcfleming: thanks, I'll be happy to share
18:10justin_smithcool
18:10cflemingjustin_smith: I'm really curious how people with no experience find Clojure
18:11kwladykacfleming if you are asking about people with no functional programming experience i can tell you :)
18:12justin_smithcfleming: yeah, I think some of the women coming to clojurebridge don't even have programming experience. And my suspicion is it will be easier for them (compared to people with just a little programming experience)
18:13maxmartinjustin_smith: don't forget to link to the event :) http://www.eventbrite.com/e/clojurebridge-workshop-for-women-in-software-tickets-16223350478
18:13maxmartinLooking forward to meeting you at the teacher training on Mondayh
18:13amalloyjustin_smith: did you read the article about how learning haskell is not made easier by having no prior programming experience?
18:13amalloywritten by a student of a former loud member of #clojure
18:14justin_smithamalloy: I can guess who you mean, and no, I have not seen that
18:14justin_smithmaxmartin: cool, see you there
18:14kwladykajustin_smith to be honest i feel Clojure is great, because i have even a lot business managin experience. Mayby even more then programming. In most cases i really didn't happy to put business thinking into code, but... but Clojure looks diffrent. I can use there my business thinking, thats what i need.
18:14justin_smithkwladyka: because it is declarative? the immutability?
18:15cflemingamalloy: It's probably made easier by having a math background more than anything
18:15amalloyjustin_smith: https://superginbaby.wordpress.com/2014/11/18/learning-haskell-as-a-nonprogrammer/
18:16cflemingamalloy: She had an interesting post the other day about teaching her 10-year-old Haskell
18:16justin_smithamalloy: in all fairness, that reminds me of my experience trying to learn haskell too
18:16amalloywho is "she", cfleming?
18:17kwladykajustin_smith i am not sure why, but i think it is writing by functions not objects. And i don't have to care about data too much because it is immutability. I want focus on goal and have super redable code. But not readable like i can read for(...){..} and i understand operations. I want read code and uderstand as fast as possible business model and understand what is happening where.
18:17cflemingamalloy: The author of that blog post
18:17cflemingamalloy: https://superginbaby.wordpress.com/2015/04/08/teaching-haskell-to-a-10-year-old-day-1/
18:18kwladykajustin_smith ofcoure it is also possible to write that readable in other langauges but other languages are not really matching with that, it like forcing them to do that.
18:18kwladykabut i am not a standard programmer, because i have really strong business skills and thinking in another way
18:19justin_smithamalloy: that was a really good and informative blog post, thanks
18:19kwladykaClojure looks for me like something what i was looking for years :)
18:20justin_smithbut I think it's less about haskell and more about the common sort of haskell intro that is out there - compare to eg. some of the excellent tabula-rasa intros to scheme
18:20cflemingjustin_smith: I think the "what do I do with this?" is the biggest stumbling block for new programmers - starting by having something you want to achieve is vital. It's why games are such a great gateway drug for programmers.
18:21justin_smithcfleming: heh, yeah
18:21cflemingjustin_smith: I think this particularly applies to Haskell since so little of the introductory stuff is aimed at actually making something useful.
18:21justin_smithcfleming: also, show a way things can go wrong without X before introducing X
18:21justin_smithbefore introducing the concept of a function, show how bad coding without functions is
18:21justin_smithetc.
18:21cflemingjustin_smith: Yeah, no doubt - there's nothing like seeing the problem it solves to make you understand it and remember it.
18:22justin_smithbut that would mean some stuff in haskell won't be teachable in your first few years :)
18:22amalloyjustin_smith: i can't tell if you're saying that's a bad thing to do or a good thing
18:22justin_smithamalloy: which thing to do?
18:22amalloy"show a way things can go wrong without X before introducing X"
18:22justin_smithamalloy: oh, I think that's very important to do
18:23kwladykafrom my point of view the most important thing is to show how easy you can write/read business model into code. This is the clue, beucase people writing code for business :)
18:27ncthom91hi all! How would I cast this ScriptObjectMirror to a normal map in clojure? http://cr.openjdk.java.net/~sundar/jdk.nashorn.api/8u40/javadoc/jdk/nashorn/api/scripting/ScriptObjectMirror.html
18:29amalloythere's no such thing as casting in clojure. banish it from your mind, and then you'll have room to think about what you actually need to do
18:29justin_smithncthom91: (into {} (.entrySet S)) I think?
18:29amalloyjustin_smith: i mean the thing is already a map
18:29amalloyyou can just call get on it
18:29justin_smithoh yeah, sure
18:29dnolenncthom91: it implements Map, you don't need to convert it
18:29amalloyso it depends what ncthom91 actually want to do
18:29justin_smithgood point
18:29amalloydnolen: depends. ncthom91 might want to assoc into it, for example
18:30dnolenamalloy: right though if you're going to interact with ScriptObjectMirror probably not going to do that
18:31ncthom91amalloy justin_smith dnolen i see, thanks
18:43ncthom91another question :).. so I'm trying to instantiate a new Nashorn instance for each thread responsible for a given task. I'd like to test that my thread-local binding is working, so I wrote a test to evaluate a javascript expression in the nashorn engine in several threads: http://pastie.org/10083448
18:44ncthom91`lein test` exits before that println is ever hit... Is this a lazy evaluation issue?
18:44amalloy~for
18:44clojurebotfor is a beautiful person
18:44ncthom91ergh... adding a `doall` seemed to make it work
18:44amalloyclojurebot pls
18:44ncthom91guess it was
18:45amalloytell me for is not a loop
18:45justin_smithncthom91: use doseq
18:45justin_smithncthom91: doseq is the same as for, syntax and execution wise, but without the laziness part
18:45hiredman~for
18:45clojurebotfor is not used often enough.
18:45ncthom91justin_smith cool, thanks
18:45justin_smith(and also it accepts arbitrary numbers of body expressions, because it's not lazy)
18:50ncthom91justin_smith so I took your tip and tweaked my test to actually test instead of just println: http://pastie.org/10083462
18:51ncthom91but `lein test` yields "Ran 0 tests containing 0 assertions."
18:51ncthom91can you help me with what that's about?
18:51justin_smithncthom91: deftest is needed
18:51ncthom91omg >_< thanks, sorry for the dumb question
18:51justin_smithncthom91: clojure.test doesn't know something is a test unless it has the :test metadata
18:52justin_smithncthom91: also, line 8 could be (map deref futures)
18:52justin_smithoh wait, those aren't futures
18:52justin_smiththey are just named "futures"
18:52justin_smithhehe
18:53ncthom91i borrowed that example from a blog post :P
18:53justin_smithno biggie
18:53justin_smithderef would work if they were actual futures
18:53amalloyjustin_smith: are you sure they're not?
18:53amalloy.invokeAll probably returns a List<Future>
18:53justin_smithamalloy: oh, good point
18:54ncthom91`(map deref futures)` here seems to work
18:55amalloytruly clojure is magic
18:55justin_smithawesome - amalloy was right, I forgot that this lower level syntax would return the same type as clojure's "future" would
18:55justin_smith(inc amalloy)
18:55lazybot⇒ 256
18:55amalloyoverflow! i should go reset my karma to 0
18:55justin_smith-256
18:55kwladykawhat tools for clojure continous integration? jenkins or something else?
18:56justin_smithkwladyka: jenkins + lein works in my experience
18:56kwladykathx
18:56justin_smithjust make sure jenkins' lein setup is aproporiate, of course
18:57kwladykaok its 1 a.m., its time to go sleep :) goodnight!
18:58akkadare there any emacs modes to highlight a dangling ]?
18:59justin_smithakkad: highlight-paren-mode should make it turn red when your cursor is on it
18:59justin_smithI think rainbow-parens should make it ugly permanently
19:00akkadthanks
19:00akkadfirst commit and poof, extra ]
19:01justin_smithakkad: also, "lein check" is good for finding goofs like that
19:02justin_smithand then "lein eastwood" for the stuff lein check doesn't find
19:07ncthom91if I've defined a new FixedThreadPool from the Executors class at the top of my file, is it a bad idea for threads to recursively call (.invokeAll) on that pool? The reference to the pool would be shared across the threads, so calling (.invokeAll) from within a thread's task would fill the same work queue as calling (.invokeAll) from the main thread, right?
19:16justin_smithncthom91: yes
19:16ncthom91justin_smith yes it's a bad idea?
19:17justin_smiththey are all using the same pool
19:17justin_smithare you wanting per-thread pools?
19:18ncthom91justin_smith nope. I'm building a graph recursively where I want each node assembled in a thread
19:18ncthom91so the recursive call is actually putting a task back in the thread pool
19:18ncthom91hmm that might be trouble because then threads are waiting on threads...
19:19ncthom91in a fixed thread pool
19:19ncthom91it's like a sophistocated deadlock
19:19ncthom91lol
19:19justin_smithncthom91: a nice way to organize this is to have each thread reading tasks off a queue
19:19justin_smithand then putting tasks onto the queue (but not waiting on them)
19:20justin_smithcore.async has nice abstractions for this stuff, but you can also use clojure.lang.PersistentQueue/EMPTY
19:20justin_smithor even a java.util.concurrent.BlockingQueue
19:20justin_smithI think that's the one
19:21ncthom91i'll have to find a nice way to prevent threads waiting on each other
19:22justin_smithncthom91: for nested dependencies between threads, look into core.async
19:22justin_smithdo channel writes / reads
19:22justin_smithit simplifies this stuff a lot
19:24ncthom91justin_smith any tips on mixing core.async and the Executors framework? I definitely want a fixed thread pool where threads stay alive
19:24justin_smithncthom91: let core.async handle the threads
19:25justin_smithit uses a fixed pool, but you don't have to worry about the details in practice
19:25justin_smithit has a state machine where a given block might be dropped from one thread, and picked up by another later, but all the threads are utilized efficiently
19:26ncthom91justin_smith oh... it does use a fixed pool? Each of my threads needs its own Nashorn scriptengine instance to execute some javascript, and instantiating a new Nashorn engine takes like 500ms, so if threads are constantly spinning up and down i'll incur a lot of overhead
19:26ncthom91that's why I was intrigued by Executors' newFixedThreadPool
19:27justin_smithncthom91: instead of giving a script engine to a thread, give it to a block of code that loops and executes things as needed
19:27justin_smithlet core.async decide which actual thread is running your code
19:28justin_smiththe result is that none of the engines are sharable between threads (each belongs to a single localized block of code), but threads can do other work while a given block is parked on eg. IO
19:28ncthom91justin_smith well the trouble is that Nashorn isn't thread safe yet, so I need to guarantee that each thread gets its own instance
19:28ncthom91oh.. hmm
19:28justin_smithno, you don't
19:28justin_smiththe instances would only be accessible to one thread at a time
19:28ncthom91could you show me a quick example of how to do that?
19:29justin_smith(go-loop (let [task (<! task-chan)] (do-something task engine))
19:29justin_smithassuming engine was locally bound (likely in a surroundign let block)
19:30justin_smiththe only code using the engine is that go-loop
19:30justin_smithI think that code has a few issues, but at least the basic idea is there I hope
19:30ncthom91and `go-loop` puts this off in a thread?
19:30justin_smithno
19:30justin_smithit creates a go block that loops
19:31justin_smiththe go loop is run (when it is ready to be run (not parked on a channel or whatever))
19:31justin_smithit's picked up by whichever thread core.async decides to put it on
19:31justin_smithbut that's implementation, in practice that part you don't really need to think about
19:32justin_smithyou know that engine won't be used in other threads, because it is a local bindign that you don't share with other code
19:32justin_smithso at any time at most one thread can use it
19:33ncthom91interesting... how does core.async fan out the work then? Suppose that task queue that you <! from has like 10 tasks queued up
19:33ncthom91will core.async magically fan it out onto N threads?
19:33justin_smithncthom91: first to read from the queue is first to get the task
19:33justin_smithncthom91: no, if you want N engines working, start N go loops
19:34justin_smithall reading on the same channel
19:34justin_smithlike delivery drivers waiting for the next order that's ready to go
19:34justin_smitheach task is guaranteed to be taken by exactly one consumer
19:34ncthom91I see. So rather than bounding the thread pool I'm kind of bounding the "engine pool"
19:34justin_smithright
19:35ncthom91and letting core.async associate whatever threads it wants to the work
19:35justin_smiththat is kind of inside out, huh :)
19:35justin_smithright
19:35justin_smiththat's the model
19:35justin_smithit's a formal execution model called CSP
19:35justin_smithvery well studied and well documented
19:35justin_smithconcurrent sequential processes iirc
19:35justin_smithcommunicating sequential processes
19:35justin_smithsorry
19:36ncthom91So I could do something like (doseq [engine engines] (go-loop (let [task (<! queue)] (do-something task engine)))
19:36justin_smithexactly
19:36ncthom91which would associate a go-loop with each engine
19:36ncthom91interestingggg
19:36justin_smithI think you actually need a (recur) and a binding block in go-loop
19:37justin_smithbut that's the idea, yeah
19:37ncthom91sure
19:37justin_smithit works out very nicely in practice
19:37justin_smithclean, simple
19:37ncthom91i believe it. It's totally not how I was thinking about this problem :)
19:37justin_smiththe engines can each generate more tasks
19:37justin_smithwithout clogging the whole thing up
19:38justin_smith(unless they produce tasks faster than they consume them of course, nothing is going to help you with that :))
19:38ncthom91well the (do-something) function will be the one making more tasks, probably not the js engine, but I assume it's the same thing
19:38justin_smithright, sorry
19:38justin_smithsure
19:38ncthom91heh, it's a finite recursive problem, so it'll end eventually
19:38justin_smithcool
19:38ncthom91justin_smith are channels essentially queues in this model?
19:38justin_smithexactly
19:39justin_smithqueues with special constraints
19:39justin_smithno peeking for example
19:39ncthom91so I can just create new tasks with (>! queue new-task)
19:39justin_smithexactly
19:39justin_smiththe only way to check if a queue has data for you is to consume it (and remove it from the queue)
19:39justin_smithbut the extra rules actually are needed for the overall provable correctness of the setup
19:41ncthom91how would just close one of those go-loops?
19:41ncthom91how would you*
19:41justin_smithncthom91: if you close the input queue, it will return nil when they read
19:41justin_smiththey can check for nil and exit
19:42ncthom91hm ok
19:42justin_smithand in fact they should :)
19:42justin_smithif you really needed fine grained control, you could give them individual channels, but that seems an odd choice
19:42justin_smithif you have to shut down one, I think it would make sense to shut them all down
19:42ncthom91no, I'm thinking this should work
19:42ncthom91yea
19:43ncthom91the only piece I have left to solve, conceptually, is that right now each node in my graph contains a pointer to its children nodes
19:43ncthom91so in constructing the graph, I need each child node before I can finish building the parent
19:43justin_smithahh
19:43ncthom91that's how I ended up with threads relying on threads
19:43justin_smithncthom91: adjacency list!
19:43ncthom91hahaha
19:43ncthom91exactly my thinking
19:44ncthom91it makes the traversal less fun to write, but I think that solves this problem
19:44justin_smithin all seriousness, when you have immutable data structures, adjacency lists are really the only sane way to do fully general graphs
19:44justin_smiththe traversal only needs some minor adaptor code
19:44ncthom91right.. i was thinking references to atoms actually
19:44ncthom91but that seems unnecessarily messy
19:45justin_smithI'd say one atom, holding an adjacency list expressed as a hash-map
19:45ncthom91and the atom part there guarantees the thread safety?
19:45justin_smithright
19:45justin_smithusing swap! for all modifications
19:45justin_smithit will retry if there are concurrent modifications
19:45ncthom91ok. This makes a lot of sense... probably a far easier approach than what I had in my head lol
19:46justin_smithyou just need to watch out for side effects in the update function (big nono) and if you are hitting too many retries caused by concurrent updates, consider splitting it into sibling refs
19:46ncthom91by update function you mean teh function I pass to swap! ?
19:46justin_smithncthom91: after doing a bunch of other ways of organizing recursive tasks on fully general (potentially cyclic) graphs, this is the sane way
19:47justin_smithyeah
19:47ncthom91what do you mean split into sibling refs?
19:47ncthom91split the map into pieces contained ins eparate atoms?
19:47justin_smithwell, refs, not atoms
19:47justin_smithbecause refs are what you want for coordinated update
19:48justin_smiththat relies on the state of multiple objects that are updated together
19:48justin_smithif you can do a hash map in an atom, that's simpler, but refs are simpler than multiple atoms
19:48ncthom91i see, ok
19:49justin_smithncthom91: the docs on clojure.core are really good for describing the various concurrency primitives in clojure
19:50ncthom91i'm going to tackle it with a single hashmap in an atom at first
19:50justin_smithncthom91: the chapters here on refs, agents, and atoms http://clojure.org/documentation
19:50justin_smithncthom91: yeah, that makes sense
19:50ncthom91Realistically I won't hit a lot of concurrent updates unless I use a bunch of different js engines
19:51ncthom91but I won't know how many engines to use until I can measure the speed increase as I tweak that number
19:51justin_smithcool
19:51ncthom91justin_smith thanks so much. This is been immensely helpful
19:51ncthom91this has* been
19:52justin_smithif you want to dynamically tweak the count without restarting the system, you could assign each an ordinal integer, and send a message saying "everyone with a number higher than N, shut off"
19:52justin_smithncthom91: your welcome, I think this stuff is really cool
19:53ncthom91justin_smith great! Cause I'm sure I'll be back with more questions soon enough hahaha
19:53justin_smithncthom91: another possibility for the "sending a number" idea would be also to turn them on if the number is higher than their N
20:14nicferriermacros. can I read the current namespace for using inside a macro?
20:14justin_smithnicferrier: the ns invoking the macro is *ns*
20:15nicferrierso if I use *ns* I should be ok. I was using that outside macros and it was just "user"
20:15nicferrierof course, if I deliberately changed the namespace (like in a repl) it was correct
20:15justin_smithright, that's the namespace from which everything else is called
20:15nicferrierbut then running outside the repl it was just user all the time.
20:15justin_smithbut at expansion time, *ns* will be the ns in which the macro is expande
20:16justin_smithd
20:16nicferriergot it
20:16nicferrierthanks]
20:17ncthom91hey justin_smith one more question :). If I throw these tasks into the queue, and the go-loops spin and pick them up and update the adjacency list... how can I know get some notification of being "done"
20:17ncthom91where "done" is a state such that the queue is empty because the engines have finished all of the recursive updates to teh graph
20:18justin_smithoh, that's an interesting one
20:18ncthom91:)
20:19ncthom91hmm i suppose I could solve this problem differently
20:20justin_smithncthom91: one possibility is an agent, that gets incremented for each task (including your initial tasks) and decremented when each one is fully processed (including queueing any follow up tasks), and use add-watch to do a special thing when the agent hits 0
20:21justin_smithbecause it can't hit 0 until there is truly no work remaining
20:21justin_smithsince the number can't go up again if no task is still in progress
20:21ncthom91that's a cool idea
20:21justin_smithand it can't hit zero unless none are in progress
20:22ncthom91so my go-loop body could just `send` an `inc` call at the beginning and a `dec` call at the end yea? I'm going to read up on add-watch
20:22justin_smithncthom91: I use a similar concept for testing task-pool abstractions, where I track the max value it hits, and also ensure that it gets back to 0
20:22justin_smiththat showing the total max concurrency
20:23justin_smithncthom91: yeah, that sounds right
20:23justin_smithI suggested an agent specifically because that won't retry (with retries it could hit weird states, better to not have to think about it)
20:24ncthom91justin_smith yea this sounds good, I like the approach
20:26ncthom91thanks!
20:29darthdeusif I have a map of vectors/sets, is there a simple way to add/remove items from a vector/set at a given key?
20:30justin_smithdarthdeus: dissoc and assoc, but these don't replace your collection, they make a new one
20:30darthdeusjustin_smith: yeah, but those work on the map
20:30justin_smithdarthdeus: ahh, I mean update-in
20:30darthdeusoh cool, thanks :)
20:31justin_smith,(update-in {:a [1 2 3]} [:a] pop)
20:31clojurebot{:a [1 2]}
20:31justin_smith,(update-in {:a [1 2 3]} [:a] conj 42)
20:31clojurebot{:a [1 2 3 42]}
20:31darthdeus,(update-in {} [:a] conj 42)
20:31clojurebot{:a (42)}
20:31darthdeushmm
20:32justin_smith,(update-in {} [:a] (fnil conj []) 42)
20:32clojurebot{:a [42]}
20:32justin_smithfnil there will act like conj if it exists, create a vector and then conj if it doesn't
20:32darthdeusinteresting
20:33darthdeusstill not sure if I like this about clojure, that modifying collections is so easy
20:33justin_smithdarthdeus: nothing got modified
20:34justin_smith,(let [a {:a 0}] (assoc a :b 1) a)
20:34clojurebot{:a 0}
20:34justin_smithyou have to use the return value
20:34darthdeusyeah I know about persistent data structures
20:34darthdeuswhat I meant is that the APIs kinda make me want to use raw data strucutres
20:34justin_smiththat's a good thing
20:34justin_smiththat's the right way to do it in clojure
20:34darthdeusthat depends ... coming from haskell it's very unnatural
20:34justin_smithdarthdeus: clojure isn't haskell
20:35darthdeusI know, that's why I'm trying to do it this way and not the haskell way :)
20:35justin_smithalso, you can use defrecord - it supports all hash-map ops, but is also a custom type
20:35darthdeusbut it twists my brain a bit
20:35justin_smithright
20:35justin_smithdefrecord is a great in between, where you get all the standard utility functions and power, but also get to paramaterize on type
20:35justin_smithfor eg. protocols
20:36darthdeushmm
20:37darthdeusI feel like I can hack together a lot of things fast ... which seems good ... though not really sure how this will work out long term
20:37darthdeusbut hey, at least I'm getting work done :D
20:37justin_smithdarthdeus: that is the clojure / haskell trade off in my experience
20:38justin_smithin clojure you get things done fast - but then might discover that you backed yourself into a corner by building so fast
20:38justin_smithwith haskell, you don't know if you are making progress at all until ... BOOM it's done
20:38justin_smithas a vast overgeneralization of both languages, of course :)
20:38darthdeusindeed ... though true
20:39darthdeusat least from my very minor clojure experience
20:39darthdeusit feels that I almost don't have to know anything and it kinda works
20:39darthdeuslike javascript, except a little better
20:39justin_smithonly a little? :P
20:39amalloyclojurebot: clojure is like javascript, except a little better
20:39clojurebotAck. Ack.
20:39justin_smithhaha
20:39darthdeuswell, maybe a lot better :D but still feels a lot like javascript at times
20:40justin_smithdarthdeus: I think this heralds back partially to the javascript / scheme connection
20:42darthdeusmight be
20:43justin_smithbrendan eich: I was recruited to Netscape with the promise of “doing Scheme” in the browser... I’m happy that I chose Scheme-ish first-class functions and Self-ish (albeit singular) prototypes as the main ingredients.
20:44justin_smith"Whether that language should be Scheme was an open question, but Scheme was the bait I went for in joining Netscape."
20:46justin_smithinteresting - if it weren't for the "looks like java" requirement, perl, python, tcl, and scheme would have been in the running
20:46justin_smithhttps://brendaneich.com/2008/04/popularity/
20:48darthdeushehe
20:48darthdeusbtw am I blind or are there no API docs for http-kit? http://www.http-kit.org/ I just can't find them anywhere in the repo or on the site
20:50arrubindarthdeus: Did you click Server or Client? Or did you want something more?
20:50darthdeusarrubin: well those only have examples, not exactly a description of all the functions and params etc
20:52arrubinI do not see anything else, so you might not be blind.
20:52arrubinOr we might both be.
20:59justin_smithdarthdeus: it's actually not a huge lib, the most concise docomentation is probably the code and doc strings in the github repo
21:00justin_smithdarthdeus: I think these three files have all the info you might want https://github.com/http-kit/http-kit/tree/master/src/org/httpkit
21:00justin_smithand the impl details are hidden in the java source
21:01justin_smithhttps://github.com/http-kit/http-kit/tree/master/src/java/org/httpkit
21:02darthdeuscool, thanks
21:14nuwanda_ok, I think I'm going a little crazy. Is there a reason a repl would be able to load a ns with (require 'ns-name) but apparently fail to do (in-ns 'ns-name)?
21:15justin_smithnuwanda_: no, it's the opposite
21:15justin_smithrequire can fail if your ns has errors
21:15justin_smithin-ns doesn't really have a failure case
21:15justin_smithin-ns won't load your code though
21:16nuwanda_well, it doesn't actually fail, it just behaves as if the ns wasn't found
21:16nuwanda_yeah, exactly, it doesn't load my code, while require seems to have no problem with it
21:16justin_smithnuwanda_: all in-ns is change the active ns, and optionally create a totally empty ns if it didn't exist
21:16justin_smithin-ns is not intended to load code
21:16justin_smithall it does is change which ns is active
21:16justin_smithit doesn't look for files or anything
21:17justin_smitheven if you have a file implementing ns-name, it just creates an empty ns, ignoring that file
21:21darthdeusbtw probably a dumb question, but can I expect things like sockets to behave properly if I put them in a Set?
21:22justin_smithdarthdeus: if I understand you correctly, that would be yes, since they use object identity for equality
21:42nuwanda_(inc justin_smith)
21:42lazybot⇒ 236
21:42ShayanjmSo I've got something I need to run via a remote repl on a powerful server. It's going to take a long time, and obviously I don't want to lose the results in case something happens to the session
21:43Shayanjmare there any 'clojure best practices' for dealing with this?
21:43ShayanjmOr is it more or less the same sort of trouble shooting i.e: capture everything into a file?
21:49sattvikShayanjm: It depends on what you need. You could perform the work in a future and stuff the result into a var somewhere (as an atom or a ref). If it needs to persist across JVM restarts, then, yes, you should store that somewhere designed for persistent storage.
21:50Shayanjmsattvik: if I run something in a remote repl and my ssh session dies (connection or something) in the middle
21:50Shayanjmdoes the repl session persist?
21:50ShayanjmNo, right?
21:53sattvikNo, it doesn't.
21:53ShayanjmYeah so that's really my problem
21:53ShayanjmCan't reasonably expect my session to stay live that long
21:55sattvikHowever, if you do something in a future, it will happen in a thread that's independent from the REPL. As such, you could save the future in a namespace somewhere so that you can later reconnect to your server and look it up.
21:55Shayanjmhmm interesting
22:04Shayanjmsattvik: doesn't a future only exist for as long as a REPL session is active?
22:05Shayanjmi.e: If I ssh into remote server, lein repl -> Run some stuff (in a future) that processes a ton of data and writes to a file
22:05xphillyxHey all. Is there a way to memoize on a 2 argument function but say to only "key" on one of the arguments?
22:06Shayanjmand after I run that stuff the session dies. Wouldn't the REPL session die as well - meaning the future is no longer active & therefore stops running?
22:07Shayanjmsattvik: or even more simply taking u
22:07sattvikNo, the future runs a seperate thread. You do have to save it somewhere where you can look it up later, otherwise it will get garbage collected.
22:07Shayanjmsattvik: or even more simply taking out the write-to-file capability*
22:07Shayanjmsattvik: Okay, so what if the future just returns a value. If I ssh back into the server & lein repl again, would the future still be referencable?
22:08ShayanjmDespite the session ending before the future could return?
22:08sattvikSo you can (def my-long-tasks (atom {})). In your REPL, you can (swap! my-long-tasks assoc :my-key (future (long-running-fn)))
22:08sattvikLater, you can (:my-key @my-long-tasks).
22:09Shayanjmsattvik: but that would only work for as long as the REPL is active
22:09Shayanjmthe moment the ssh session dies, the repl would also die -- meaning my-long-tasks would start with a fresh empty value after lein repl is run again
22:10sattvikNope. It's completely independent.
22:10ShayanjmSeriously? That doesn't seem right
22:10sattvikWell, if you do it in the user namespace, yes that may be the case.
22:10sattvikWell, even then, the user namespace persists.
22:10Shayanjmsattvik: my set up is: I have core.clj running some long running processes inside of some clj project
22:11Shayanjmbut the namespace only persists for as long as the repl is active - and I thought it dies the moment the ssh session dies?
22:11ShayanjmHang on, there's an easy way to test this I think
22:11justin_smithShayanjm: if you restart the vm, yes, all things you do in the repl are lost
22:12Shayanjmjustin_smith: Not restarting the vm. If the ssh session dies (due to connectivity drop or hibernation or something)
22:12Shayanjmwould the remote repl session still persist?
22:13Shayanjmor would it die with the ssh session? The machine is still live/running, the only thing that happened was that my laptop dc'd from the server
22:13justin_smithShayanjm: it depends on what the OS decided to do. If you used nohup for example, it would not exit. Otherwise it gets an EOF, and a signal, and if you don't handle that signal, it will be shut down.
22:13ShayanjmAh, so this is more an OS thing than anything else
22:13Shayanjmany suggestions for how best to handle this on a remote Ubuntu machine?
22:13justin_smithyeah, the OS decides what happens when a remote user disconnects without shutting a program down
22:13sattvikThe REPL session doesn't persist as such, but the namespaces don't just unload themselves. (Although the proposed new socket REPL works a bit differently)
22:14justin_smithShayanjm: if you want the repl to stay running, use nohup
22:14justin_smiththis is handy because it also make a log file
22:18Shayanjmhmm interesting
22:20Shayanjmjustin_smith: If I use nohup, run the process, and want to check on the value after x hours
22:20Shayanjmhow would I reconnect to that repl instance?
22:21justin_smithShayanjm: lein repl :connect port
22:22justin_smithor any other repl client you like
22:22justin_smithin fact you can use the -L arg to create an ssh tunnel, and use your editor or ide repl client
22:22Shayanjmjustin_smith: Oh so just standard lein repl :connect port?
22:23justin_smithyeah, or if you have a tunnel, you can even run the repl on your local box
22:23justin_smithwith your preferred tools
22:23justin_smithand the jvm and actual repl instance are on the other host accepting connections
22:23Shayanjmooh
22:23Shayanjmand I can disconnect/reconnect at any time?
22:23justin_smithright, nrepl is nice like that
22:24ncthom91hey justin_smith if you're around, quick question: http://pastie.org/10083752
22:24Shayanjmgame changer. How would I set this up on emacs cider?
22:24ncthom91this is a test for verifying the graph that we were talking about earlier gets updated properly
22:24justin_smithShayanjm: instead of cider-jack-in just use cider
22:24justin_smithit will ask for a port
22:24Shayanjmoic
22:24Shayanjmand point it to the remote IP + port?
22:24ncthom91but the tests inside the add-watch callback don't get run, it looks like
22:24ncthom91or at least they don't contribute to the test reporting
22:24justin_smithShayanjm: no, since it's a tunnel, just the port suffices
22:25Shayanjmoh right because -L
22:26justin_smithShayanjm: I think at this point even cider has options for making the remote connection, but I think it makes more sense to create the tunnel myself with ssh
22:26justin_smithmaybe because I am old fashioned
22:26Shayanjmjustin_smith: so workflow here would be: ssh with -L, run nohup lein repl, connect via cider, run stuff, disconnect (also disconnect tunnel?) -- reconnect at some later point via ssh tunnel & cider and check values?
22:26justin_smithyup
22:27ShayanjmThat sounds fantastic
22:27justin_smithyou can disconnect the tunnel if you like if you are not using it
22:27Shayanjmand I'm assuming I can just kill the repl with a standard (exit) despite nohup, yeah?
22:27justin_smithShayanjm: it makes debugging prod so much easier
22:27justin_smithShayanjm: from within the repl you can use (System/exit 0)
22:27Shayanjmis (exit) the same thing?
22:27justin_smithor any handy cider tool that does that for you, I guess
22:27justin_smithI have no idea what (exit) is
22:27ShayanjmWeird, my repl always starts and prompts me to use (exit) to exit lol
22:28Shayanjmmight've been some config magic when I first set up lein
22:28justin_smithShayanjm: it's probably some nice feature I just never use
22:28justin_smithI just tried typing in exit (no parens) in my repl and it disconnected me
22:28justin_smithprobably nrepl magic
22:28justin_smithhaha
22:29Shayanjmhahaha that sounds about right
22:29Shayanjmcool thanks a lot justin_smith, gonna try this
22:30justin_smithncthom91: well, the test/is calls are not tests
22:30justin_smiththey are assertions within a test
22:31justin_smithI don't think they do the right thing if they execute in another thread
22:31justin_smithusually what I do is create a "logging atom" and use swap! to poke that atom inside the async code
22:31justin_smiththen I make assertions about the data in that atom
22:32kevinwebsterIm trying to find out why Clojure has yet to support regex named capture groups. I dont see any discussion in JIRA or google groups about it. Anyone know why that is?
22:32justin_smitheg. have a cycle count, or a concurrency count that tracks its max value so far, etc.
22:32justin_smithkevinwebster: if java supports them, clojure does
22:32ncthom91justin_smith but how do you know when to make the assertions?
22:33aperiodicin om, when I have multiple om/build calls in the body of my om/IRender render implementation, it seems like only the last one is actually called
22:33justin_smithncthom91: when the processes are done, at the end of that test
22:33aperiodicdoes anyone know why that happens?
22:35justin_smithkevinwebster: clojure directly uses java regexes, including the extended syntax http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html
22:35justin_smithkevinwebster: the docs there explicitly mention named capture groups
22:36justin_smith#"foo" is equivalent to Pattern.compile("foo")
22:39ncthom91justin_smith not sure what you mean. By the time i've hit the end of my test, the async code hasn't necessarily finished
22:40justin_smithncthom91: then make sure you wait for it
22:40justin_smithncthom91: each go loop returns a channel when constructed, when that channel returns a value on read, that means the loop has exited
22:40justin_smithyes, testing async things is weird
22:42Shayanjmjustin_smith: nohup doesn't seem to be working, or I'm ignorant of how to even use it
22:43Shayanjmon remote machine: nohup lein repl
22:43justin_smithyes
22:43ShayanjmNo output, looks like it runs without failing
22:43Shayanjmso A) I don't know the nrepl port
22:43Shayanjmand B) If I try looking for a java process I don't see one
22:43Shayanjmps aux | grep java
22:43justin_smithShayanjm: it creates a log file
22:43justin_smithnohup.out
22:43justin_smithif it is exiting, that's likely an issue
22:44justin_smithit should just sit there, not printing but also not ending
22:44justin_smithyou can bg it safely
22:44Shayanjmoh gotcha
22:44justin_smith(Control-Z, bg, in most shells)
22:44Shayanjmdoes nohup.out get updated live?
22:44Shayanjmor only on exit?
22:44justin_smithlive
22:44justin_smithyou can tail it
22:44justin_smithor whatever
22:44ShayanjmOkay, yeah there was an error running with nohup
22:44Shayanjmbut not regular lein repl
22:45justin_smithwhat was the error?
22:45justin_smithI usually am using lein run, and then starting a repl server from my -main
22:45justin_smithso maybe lein is being dumb about the tty here
22:45Shayanjmhttps://gist.github.com/shayanjm/15fad6a7c27c9127c461
22:46justin_smithyeah, lein is trying to do stuff with stdio that doesn't work in nohup
22:46justin_smithyou're better off making an uberjar and using lein run anyway
22:46justin_smitherr, not lein run
22:46justin_smithI mean java -jar, or you can use lein run instead of lein repl
22:46justin_smithand manually connect
22:47justin_smithShayanjm: starting an nrepl server is a oneliner, example is in the readme https://github.com/clojure/tools.nrepl#embedding-nrepl-starting-a-server
22:47Shayanjmsweet, looking
22:49Shayanjmjustin_smith: what if instead of the repl, I just make -main execute everything that needs to be executed and prints to stdout?
22:49Shayanjmuberjar that, nohup java -jar
22:49justin_smithShayanjm: if that's all you need, sure, then you can just open up nohup.out
22:50Shayanjmyeah
22:50justin_smithor make a proper log file
22:50justin_smithif that's all you need, even better :)
22:50ShayanjmYeah now that I think about it I don't really need to live-debug
22:50Shayanjmbecause these are long running processes, they don't fail fast.
22:50justin_smiththough sometimes being able to get into prod can be a lifesaver
22:50ShayanjmYeah definitely
22:50justin_smithfor figuring out a weird state interactively
22:50Shayanjmif I see that that's a benefit I'll definitely spin up a repl instance inside main
22:51Shayanjmbut this is mostly a data project
22:51justin_smithfair enough
22:51Shayanjmso there isn't a whole lot of state that needs to be managed
22:51justin_smithnice, sounds like you found the simple solution then
22:51Shayanjmthis has been very enlightening though, I didn't know you could embed repl instances inside your applications
22:51ShayanjmI could see that definitely coming in handy
22:52justin_smithyeah - definitely be careful though, an nrepl connection means full access to your program (and your program's user on that host)
22:52Shayanjmah right
22:52justin_smithwhich is why it only accepts connections on localhost by default
22:52justin_smithwhich is mostly safe enough, since nobody uses multi user machines any more
22:53ShayanjmRight, so the 'actual' workflow for that would be to ssh in to the remote machine ahead of time
22:53Shayanjmand run the repl with nohup
22:53justin_smithShayanjm: right, like I was mentioning the ssh tunnel
22:53ShayanjmYeah, and then ssh tunnel afterwards
22:53Shayanjmwith -L you can't run anything on the machine during that session, right?
22:53justin_smithno, it's a normal shell
22:54Shayanjmseriously?
22:54Shayanjmgonna try 1 min
22:54justin_smithwhich is why I just make creating the tunnel part of the command when I ssh in
22:54Shayanjmso what's the syntax? somelocalport:remotehost:22? or localport:remotehost:remotereplport?
22:55justin_smithssh -L localport:127.0.0.1:remoteport
22:55justin_smithsince it's a thing that only listens on 127.0.0.1
22:55justin_smithor localhost whatever
22:55justin_smithmy habit is using that "magic" ip
22:56justin_smithso you could optionally make a "hop" by connecting to yet another host (proxy tunnel) - ssh is very flexible
23:07Shayanjmjustin_smith: I guess my confusion is: the remote port, should that be some random port or the nrepl port?
23:07Shayanjmif it's the nrepl port, I would have to specify the port in the code -- I wouldn't be able to let lein generate that for me randomly
23:08justin_smithShayanjm: the nrepl port. You can specify a specific port to nrepl
23:08Shayanjmyou can?
23:08justin_smithright
23:08ShayanjmTIL
23:08ShayanjmOh
23:08Shayanjmyou mean when you spin it up inside main
23:08justin_smiththere's a project.clj option
23:08Shayanjmooh
23:08justin_smith:repl-options https://github.com/technomancy/leiningen/blob/master/sample.project.clj#L354
23:09Shayanjmawesome -- thanks for letting me pick your brain justin_smith
23:09justin_smithbut yes, it's also easy in your own code, since it's a one liner
23:09justin_smithnp
23:09justin_smithI know how many days one can waste on this stuff the first time
23:09justin_smithnot because of not being capable, just not having a decent lead on what works