#clojure logs

2015-12-30

00:15mindbender1Is boot operations slower than lein operations?
00:19TEttingermindbender1: it's a good question.
00:19TEttinger~faster
00:19clojurebotfaster is https://github.com/technomancy/leiningen/wiki/Faster
00:19TEttingerthose are some suggestions for lein, they may be some for boot and some may apply to both (I think drip works for either)
00:22mindbender1TEttinger: I just wanted to be sure this was not happening only on my system.
00:23TEttingerare you using Boot and it's noticeably slower?
00:30mindbender1TEttinger: I have not really taken it for a proper test drive just the time it takes to do `boot -h` and `boot repl` got me concerned.
00:31TEttingermm. lein repl takes a fair bit of time too for me
00:32mindbender1I guess I should play with it a bit more. And they better have good documentation for speed optimizations such as the one you pointed to.
00:33mindbender1One of the reasons I like lein is the author's will to make lein bendable to the user's will.
00:53nys-what does the .nrepl-port file do?
01:01ridcullynys-: it contains the port number of the nrepl
01:03ridcullye.g. tools/editors can pick it up. the port usually is random
04:00favetelinguisim building a webserver and am now looking for a way to spawn worker processes using core.async, both go blocks and threads will be used, the problem i have is how to manage starting and stopping of the processes at runtime, any known framworks that deals with this?
07:25nicolahi - i'm building something with lein uberjar, and i'm deciding where to put the resulting jar file in the unix filesystem (I'm making a debian package). Is there a conventional directory for these?
07:26nicolathere will be a shell script that invokes 'java -cp ... args...' and it will go in /usr/local/bin, but i'm not sure where the jar itself should go
07:46pvinishello. i have a list like (def a '(1 2 3 4)), and a fn that takes 4 args. how can i call that with my list?
07:47pvinisif i do (myfn a) then its just one arg
07:47pviniscan i explode it somehow?
07:50luma(apply myfn a)
07:54pvinisaha..
07:55pviniscool. thanks
08:51favetelinguiswhat is the idomatic way to spawn and kill core-async go blocks at runtime? for example i need an go block to what makes rest request every 5sec push this out on a websocket, i need to be able to kill this go block when im done with it but since i want it to be controlled by time i cant use the pattern och blocking on the incomming channel
10:15justin_smithfavetelinguis seems to have left, but they can block on the incoming channel and a timeout at the same time, by using alts!
10:18TimMcclojurebot: mutation is exciting!
10:18clojurebotc'est bon!
10:22g0whi everyone.. i'm having some trouble understanding this syntax. How do I pass-in a different value of tempo?
10:22g0whttps://www.irccloud.com/pastebin/3fktOx7x/tempo.clj
10:23g0wCan't quite the understand the destructuring that's going on in the function argument
10:23clojurebotHuh?
10:23justin_smithg0w: (test-args [] :tempo 80)
10:23justin_smithand we don't really use the & {} thing much any more
10:23g0whello again @justin_smith
10:23g0wah okay! thanks a lot!
10:24g0wwhat do we generally use in these cases?
10:24justin_smithg0w: just a hash map with keys and values
10:24TimMcJust drop the & and have a map arg there :-)
10:24justin_smith(like what you tried to use)
10:24justin_smithyeah
10:24g0wgot it! thanks!
10:24TimMcYou can add another arity to default the map to empty or nil.
10:25g0w@TimMc yup.. that would be my preference too.. i found this code in a book
10:26g0wso I had one meta question with immutability in clojure..
10:27g0wdoes the immutability thing hold true only for clojure datatypes?
10:27g0wfor example, I was using a BitSet yesterday, and calling (.set bitset) didn't return a new bitset
10:27justin_smiththe clojure datatypes, strings, and primitives are all effectively immutable
10:27justin_smitheverything else is mostly mutable, it's the same objects java uses
10:27engblomI am new to concurrent programming with Clojure and I want to check up if I understand things right. First, can I from two different threads define the same named promise?
10:28engblomAnd if I am able to define the same named promise in both, and I deliver from a third thread, will only one of the other threads quit blocking if both do deref?
10:28justin_smithengblom: yes, but it might not do what you want. Where is the name being assigned?
10:28justin_smithdo you mean def?
10:29g0wso the issues with using java objects in writing concurrent code still exist? ie. i would need to manually synchronize access to a bitset object ?
10:29justin_smithg0w: pretty much, yeah. And you shouldn't put mutable objects inside atoms or refs either
10:30g0wok.. got it.. what's the accepted best practice in these cases? rely as less as you can on java objects?
10:30yendais there a way to check for more recent dependencies with boot ?
10:30justin_smithengblom: to be super pedantic, promises never have names, but using let or def you can bind one to a name, and either will let you bind two things to the same name, and simply render the first one inaccessible by name
10:32engblomjustin_smith: Assume I have two threads, both doing binding my-promise either through let or def (for example (def my-promis (promise)) ) Then a third thread is started and it does (deliver my-promise "whatever"). Both original threads are doing @my-promise, will one of them continue to block
10:32engblom?
10:34TimMcg0w: Clojure doesn't change the way Java and the JVM work, it just provides alternatives and wrappers.
10:34justin_smithengblom: well, you can't have more than one thread binding values in a single let block, so we have to assume it is defs. and yes, the one waiting on the first promise will wait forever, because nobody else has a handle on the old promise, and nobody will deliver to it.
10:34justin_smithengblom: this is just one reason def at runtime is usually wrong
10:35TimMcg0w: If you need to modify BitSets, your functions will need to be defensive in the same way that Java methods need to be defensive -- cloning.
10:35g0wcloning? can you elaborate a bit more?
10:35engblomjustin_smith: To be more specific, I am looking at this library: https://github.com/juxt/dirwatch
10:36TimMcg0w: If I hand you a mutable object, you might want to create a copy so that I can't accidentally modify your instance.
10:36g0wbut woulnd't a deep clone of every object be expensive with no structural sharing in place?
10:37TimMcIt can be, yes.
10:37justin_smithbut you shouldn't need deep cloning, because you don't need the mutable collection types
10:37engblomjustin_smith: I wish to use it in this way: Wait blocking until a certain file has changed. So I planned to use promises, and have the function 'watch-dir' will run to deliver
10:37g0wjustin_smith: BitSet is a mutable collection type, right?
10:38engblomBut then I begun to wonder if this is thread-safe. What will happen if several processes does the very same on the same file?
10:38justin_smithkind of - it's not really a container though, it can only hold bits (a real container can contain any Object type). you don't "deep copy" a bitset, you just copy it
10:39g0w@justin_smith: ah yes, I get what you mean.
10:39justin_smithengblom: if you set up the promise to be delivered to, the process waiting on the promise, and the watcher to deliver to the promise, all in one local scope, there's no chance of "clobbering". The clobbering would happen if you were using a def and there was a race condition in your def usage.
11:05jjttjjI have a connection object from a java library i'm working with. It relies on some external state, for instance a new client-id is needed for each connection. requests can be made from the connection, and each request must have a unique, auto-incrementing ID, and i’m queueing all responses to the requests in a core.async chan. do i just shove all these things in a map when I create a connection and pass it around everywhere?
11:12justin_smithjjttjj: there are many ways to handle this. You could use an atom with a map, you could create a go block that lexically closes over each ID and then broadcast via core.async...
11:24m1dnight_A bit off topic, but are there some more general programming-related channels I could check out on freenode (or others)?
11:30sdegutism1dnight_: ##programming
11:30sdegutism1dnight_: ##webdev
11:30m1dnight_Oh, that is rather obvious :> thanks
11:30m1dnight_Joined them
11:30sdegutis:)
12:04favetelinguisi want to conj to a IPersistentCollection, is this possible or how can to clone the IPersistentCollection vector and then use the new to conj what i want?
12:35TimMc,(clojure.string/escape "foo" {\o \e})
12:35clojurebot"fee"
12:36TimMcfavetelinguis: IPersistentCollection is pretty vague. Do you know anything else about the value?
12:51sfz-,(clojure.string/escape "foo.com?q=bar baz qux" {' ' '+'})
12:51clojurebot#<RuntimeException java.lang.RuntimeException: Map literal must contain an even number of forms>
12:51sfz-hm
12:51MJB47use " instead of '
12:51sfz-,(clojure.string/escape "foo.com?q=bar baz qux" {" " "+"})
12:51clojurebot"foo.com?q=bar baz qux"
12:52sfz-nope, how would you replace a space?
12:52MJB47try string/replace
12:53TimMc,(clojure.string/escape "f " {space \o})
12:53clojurebot#error {\n :cause "Unable to resolve symbol: space in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: space in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6704]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: space in this...
12:53TimMcurgh
12:53TimMc,(clojure.string/escape "f " {\space \o})
12:53clojurebot"foo"
12:53TimMcsfz-: ^ But really you wouldn't, you'd use a URL library.
12:53sfz-,(clojure.string/escape "foo.com?q=bar baz qux" {\space \+})
12:53clojurebot"foo.com?q=bar+baz+qux"
12:53justin_smithfavetelinguis: when you call conj on any object implementing IPersistentCollection you get a copy with your data added to the collection
12:54sfz-TimMc: right, was just curious, thanks!
12:54sfz-TimMc: I know ring lib has stuff for that, still a relative n00b to clj though so trying to pick up all the tricks I can
12:55justin_smith,(java.net.url/URLEncode "foo.com?q=bar baz qux" "UTF-8")
12:55clojurebot#error {\n :cause "java.net.url"\n :via\n [{:type java.lang.ClassNotFoundException\n :message "java.net.url"\n :at [java.net.URLClassLoader$1 run "URLClassLoader.java" 366]}]\n :trace\n [[java.net.URLClassLoader$1 run "URLClassLoader.java" 366]\n [java.net.URLClassLoader$1 run "URLClassLoader.java" 355]\n [java.security.AccessController doPrivileged "AccessController.java" -2]\n [java.net.U...
12:56justin_smith,(java.net.URLEncoder/encode "foo.com?q=bar baz qux" "UTF-8")
12:56clojurebot"foo.com%3Fq%3Dbar+baz+qux"
12:56justin_smithreally you would only encode the part that goes after the ? of course
12:56sfz-right
12:56sfz-thanks again
12:56TimMc,(->> (range 256) (map char) (filter #(not= (count (pr-str %)) 2)))
12:56justin_smith,(str "foo.com?" (java.net.URLEncoder/encode "q=bar baz qux" "UTF-8")
12:56clojurebot#<RuntimeException java.lang.RuntimeException: EOF while reading>
12:56clojurebot(\backspace \tab \newline \formfeed \return ...)
12:57justin_smith,(str "foo.com?" (java.net.URLEncoder/encode "q=bar baz qux" "UTF-8"))
12:57clojurebot"foo.com?q%3Dbar+baz+qux"
12:57TimMcexcept URLEncoder is wrong :-(
12:57justin_smithTimMc: I still think I'm using it wrong...
12:57TimMcand this is where replace actually does come in
12:57sfz-,(ring.util.codec/url-encode "clojure url")
12:57clojurebot#error {\n :cause "ring.util.codec"\n :via\n [{:type java.lang.ClassNotFoundException\n :message "ring.util.codec"\n :at [java.net.URLClassLoader$1 run "URLClassLoader.java" 366]}]\n :trace\n [[java.net.URLClassLoader$1 run "URLClassLoader.java" 366]\n [java.net.URLClassLoader$1 run "URLClassLoader.java" 355]\n [java.security.AccessController doPrivileged "AccessController.java" -2]\n [java...
12:57sfz-aw, no clojars eh?
12:57justin_smithsfz-: clojurebot won't have any ring stuff
12:57TimMcjustin_smith: https://github.com/timmc/johnny/blob/master/src/main/java/org/timmc/johnny/Codecs.java#L28
12:58justin_smithsfz-: it might use clojars, but that's not how you add something ot the classpath
12:58justin_smithTimMc: ahh
12:58TimMcwait, that's decoding... but you just do it in reverse
13:47jjttjjhow should i clojureize the name of the java class EClientSocket... "e-client-socket"? "eclientsocket"? first seems more typical but looks weird here is the second one dumb to do?
13:48jjttjjmaybe i'll just do ecs/ECS?
13:49justin_smithwhy are you clojureizing a class name?
13:49jjttjji need to stick the connection object in a map, trying to figure out what to name the key
13:51justin_smithI would usually use a key like :socket - depending on context etc. of course
13:51jjttjjjustin_smith: cool thanks! getting hung up on dumb things today
14:02TimMc:☃-socket
14:03justin_smithTimMc: well, it is a Snowman, so as an initialism :☃ ocket should work
14:07TimMcnice, even more concise
14:07justin_smithit even has a compatible outline
15:08TimMcIncanter doesn't appear to have fourier transforms... what am I missing?
15:36justin_smithTimMc: clearly they expect every user to hand-roll their own fft
15:36creeseI've been reading about om.next. I'm wondering what if anything has been done on the back-end portion. Has anyone build a ring app that takes om.next queries and return responses using a datastore other than Datomic?
15:37KajtekHi guys, so I've run into a problem when using map destructuring and lazy sequences.
15:37KajtekBasically, whenever I pass a lazy seq with odd number of elements to a function that uses destructuring I get an exception.
15:37KajtekEven-numbered sequences work as expected.
15:38KajtekHere's a minimal reproduction: ((fn [{:keys [k]}] k) (lazy-seq [{:k :a}]))
15:38KajtekIs it a known bug? I don't really follow Clojure development.
15:38KajtekAlso, this happens on Clojure 1.7.0.
15:38MJB47{:keys...} only works correctly if the input is a map
15:38justin_smithKajtek: that argument is incorrect
15:38MJB47you have a sequence of maps
15:39justin_smithif you replaced [{:keys [k]}] with [[{:keys [k]}]] in the function definition it would work
15:39justin_smith(but other calls would likely break)
15:40KajtekThen it working for even-numbered seqs is kind of misleading.
15:40justin_smithKajtek: yes, it works accidentally, and is unlikely to give a correct result
15:40justin_smithKajtek: there are many things in clojure that work accidentally
15:41justin_smith,(:or :a :b) ; a classic mistake, which might even pass your tests sometimes
15:41clojurebot:b
15:42KajtekI guess warts happen.
15:42KajtekThanks for the help. I suppose I'll get rid of destructuring and check if the argument passed is a map beforehand.
15:43ystaeljustin_smith: *chokes on popcorn* that's a trap that never occurred to me
15:43justin_smithystael: I've seen it!
15:43justin_smith,(:or false :a) ; the version that looks like it works
15:44clojurebot:a
15:44ystaeli don't think i knew that keyword-as-map-extractor could take a second arg
15:44justin_smithystael: see also (:require '[it doesn't matter what you put here]) - returns nil, as you expect
15:44justin_smithand of course, does nothing at all
15:45ystaelthis sounds like an argument for tutti frutti syntax coloring
15:46justin_smithheh - or a stricter programming language :P
15:46ystaelWell, yes, but this is #clojure :)
15:46justin_smithystael: syntax highlighting wouldn't work with the :require mistake - you expect it to be a keyword, you just don't realize it only works like that inside the ns macro...
15:47ystaelFortunately I typically err in the opposite direction instead, typing (require '[...) inside the ns macro
15:48justin_smithit's an easy typo/thinko to make, because the syntaxes are so similar, and they do the same thing, they just happen to be incompatible and one of them tends to be a silent noop
15:48ystaelah well, I use clojure because it's a good set of practical compromises, not because I think it's perfect :)
15:48justin_smiththinko is of course short for thinkographical error
16:00jiamoI find hard to transalte this algorthm into clojure
16:00jiamon=”the evil big number” if n mod 2=0 then lastFactor=2 n=n div 2 while n mod 2=0 n=n div 2 else lastFactor=1 factor=3 maxFactor= n while n>1 and factor<=maxFactor if n mod factor=0 then n=n div factor lastFactor=factor while n mod factor=0 n=n div factor maxFactor= n factor=factor+2 if n=1 then output lastFactor else output n
16:01jiamoIt is a Procedural paradigm
16:02justin_smithjiamo: the trivial transormation is to turn the while into a loop, and make every value mutated inside the while into a loop binding
16:02justin_smiththat doesn't always give the best result of course, but its the version that is easiest to translate
16:03justin_smithnested while might require a let binding to bind the loop variables coming out from the inner loop
16:04justin_smithalso, if you have multiple mutations inside one cycle, you can use shadowing in a let block, or explicitly transform it into multiple vars, each chaining from the previous one's value
16:13justin_smithoh, how sad, I started to play with how one would translate that, then realized the block syntax in that pseudo code is totally ambiguous and jiamo isn't here to ask for clarification
16:16sohailis there a way to dispatch on the values in a vector without unpacking it just for dispatch? Specifically, I have a vector that looks like this: [:keyword {..}]
16:17justin_smithsohail: what do you mean by "without unpacking it" ?
16:18sohailjustin_smith: I mean without doing something like (my-multi (first data) (second data))
16:18justin_smith(defmulti my-multi first)
16:18sohailoh!
16:19sohailI think I need to read this stuff more carefully
16:19justin_smithor maybe (defmulti my-multi (comp type first)) if you still want to dispatch by type...
16:19justin_smithand that needs adjusting if your method takes multiple args too, of course
16:20justin_smithsohail: there are a lot of examples of defmulti on grimoir - it can do a lot!
16:20sohailwhat is grimoir?
16:20justin_smithhttp://conj.io/store/v1/org.clojure/clojure/1.7.0/clj/clojure.core/defmulti/
16:20justin_smithconj.io is grimoir
16:21justin_smithincidentally, I fixed and/or wrote most of the defmulti examples myself
16:22sohailawesome, thanks justin_smith
16:24amalloyjustin_smith has accidentally betrayed his alter-ego, MultiMethodMan
16:25justin_smithwhat's that? commisioner Gordon has lit the dispatch signal - wait a moment while I look up the method that signal dispatches to
16:28amalloyoh no! the joker has replaced your dispatch function with (#(% %) #(% %))! now you'll never get to the crime scene in time!
16:28justin_smithhaha
16:29justin_smithholy combinators batman!
16:34TimMcI want to bucket a list of monotonically increasing numbers by multiples of 1000, e.g. [1 35 456 2005 3045 3987] => [[1 35 456] [] [2005] [3045 3987]]
16:34TimMcI think my best bet is a loop and split-with, but is there something even simpler?
16:35justin_smith,(group-by #(count (str (/ % 1000))) [1 35 456 2005 3045 3987]
16:35justin_smithoops
16:35clojurebot#<RuntimeException java.lang.RuntimeException: EOF while reading>
16:35justin_smith,(group-by #(count (str (/ % 1000))) [1 35 456 2005 3045 3987])
16:35clojurebot{6 [1 456], 5 [35], 7 [2005 3045], 9 [3987]}
16:36justin_smithoh, that wasn't a truncating divide, d'oh
16:37TimMcThe key is that I also want empty buckets.
16:37justin_smith,(group-by #(int (/ % 1000)) [1 35 456 2005 3045 3987])
16:37clojurebot{0 [1 35 456], 2 [2005], 3 [3045 3987]}
16:37justin_smithahh
16:38justin_smithTimMc: maybe a trick with (comp max keys) and range and (fnil (m %) [])
16:38TimMchrm
16:38ystaelor you could just write the reduce by hand
16:38luma,(mod 2005 1000)
16:39clojurebot5
16:39lumaah, not modulo
16:39ystael(you have reduce, why do you need anything else? :))
16:39TimMcI think loop is better here since I need to bind 2-3 values on each iteration.
16:39luma,(quot 2005 1000)
16:39clojurebot2
16:39lumathis one
16:40justin_smithluma: yeah, better to use quot than (comp int /)
16:42TimMcHere's my solution: https://gist.github.com/timmc/35c969e97ac1c5e7f72f
16:43justin_smith(let [in [1 35 456 2005 3045 3987] by-count (group-by #(quot % 1000) in)] (map #(get by-count % []) (range (inc (apply max (keys by-count))))))
16:43justin_smith,(let [in [1 35 456 2005 3045 3987] by-count (group-by #(quot % 1000) in)] (map #(get by-count % []) (range (inc (apply max (keys by-count))))))
16:43clojurebot([1 35 456] [] [2005] [3045 3987])
16:44TimMc"now make it lazy"
16:44justin_smith:)
16:45TimMcI've made a maximally lazy coll-of-colls splitter like this before and it was annoying to write: https://github.com/timmc/rand/blob/master/src/rand/core.clj#L26
16:46TimMcThe approach was to lazily inject sentinels at the boundaries, then lazily group on the sentinels.
16:58justin_smith,(let [ord #(quot % 1000)] (apply mapcat (fn [prev sub] (concat (repeat (dec (- (ord (first sub)) (ord (first prev)))) []) [sub])) ((juxt identity rest) (cons [0] (partition-by ord [1 35 456 2005 3045 3987]) )))) ; bizarre, but works and is lazy
16:58clojurebot((1 35 456) [] (2005) (3045 3987))
16:59justin_smiththere is probably a way to make that less loony
17:02justin_smithalso that [0] should probably be a -1 and the behavior around various orders of magnitude as starting values probably needs fixing
17:05tolstoyclojars still out, eh?
17:06justin_smithoh wow, what happened?
17:06tolstoyNo idea. My "lein ancient" was having issues. Checked: https://linode.statuspage.io, which clojars mentioned on their twitter account 3 days ago.
17:07tolstoyAh, it's back in the browser, now.
17:07justin_smithtolstoy: https://twitter.com/clojars
17:07justin_smithoh, d'oh, while I am looking that up you mention their twitter, heh
17:07tolstoyYeah, that was Dec 27.
17:08justin_smithdo you know which location they are using?
17:08tolstoyOkay, it's back.
17:08tolstoyNo idea.
17:11TimMclinode is being DOS'd
17:11TimMcHas been for a couple days, I think?
17:12tolstoyFastmail's been having a problem as well.
17:12tolstoyAIs getting a little feisty?
17:19TimMcSomeone's probably trying to extort them.
17:53justin_smithrepeating my core.async / cljs question here because #clojurescript is looking a bit underattended right now
17:53justin_smithOK, I have an issue that comes up because <!! is missing in cljs
17:53justin_smithin my cljs startup, I need to delay the rest of the app coming up until I get a specific message on a core.async channel
17:54justin_smithin other words I need to block until I get a message - but can't use <!!
17:54justin_smithis there a sane / normal way to do this? - I understand realistically that the code which sends the message would be blocked if I used <!!, but I also don't want to suck all my init code up into a go block just so I can synchronize on a channel at one place
17:54tolstoyAre you using one of the reacty things?
17:54justin_smithyes, but none of the reacty crap is running yet when this happens
17:55tolstoyOh. I was going to suggest just run as normal, but set a prop in the state such that nothing gets rendered.
17:55justin_smiththis is during initial page load, handshaking a websocket with the server, and then I need a specific message from the server before the rest of the code in the app can safely run
17:55tolstoyWhen the appropriate message comes in, reset that, and the GUI will pop-up.
17:55justin_smithtolstoy: yeah, this is about more than props
17:55justin_smithright
17:56tolstoy(swap! state assoc :view :loading)
17:56tolstoyI do that, anyway.
17:56justin_smithtolstoy: I'm actually using stuart sierra's component lib, and this is a component init, and really I don't want to return from the init of this component until the confirmation message (and the data it sends) is present
17:56tolstoyIf (:user state) is nil, render a loading component. Eventually, data comes in and it works.
17:57justin_smithother components do things (before react renders) that will break badly if this data is not present
17:57tolstoyOy.
17:57justin_smithand I can't just put the data in the cljs file
17:58tolstoyThat's a bit of a monkey-wrench.
17:58bjajustin_smith: could you use take! and write a function that delivers to a promise then deref that?
17:58justin_smithbja: no promises in cljs!
17:58justin_smithI thought of that one too
17:58bjacould you use $.deferred or something likethat?
17:58justin_smithhmm... we aren't using $ at all, but maybe there's an alternative I could use
17:59bjaisn't there a pure-cljs promise library
17:59justin_smithbja: maybe, I didn't check for that
17:59bjahttps://github.com/funcool/promesa
17:59justin_smithit would be just the thing I guess as long as it played nicely with async stuff that needs to happen
17:59tolstoyhttps://github.com/jamesmacaulay/cljs-promises
18:00justin_smithand when I say that, I start to think maybe I do need to suck my whole component system into core.async... oh no
18:00tolstoyMaybe have a whole bootstrap system, then invoke component stuff once it's complete?
18:01justin_smithmaybe I could pull this component out of stuartsierria/component and start it first
18:02justin_smithusint take with a "start all the other components" as the callback?
18:02justin_smithclearly we need "components, but async"
18:02bjadoes component work in cljs now?
18:03tolstoy(go (let [data (<! (bootstrap))] (start-system data)))
18:03justin_smithyeah - I did my own cljc port ages ago, and eventually I will switch to the official cljc port which came out more recently
18:03justin_smithtolstoy: exactly
18:03justin_smithtolstoy: that's probably what I need to do, thanks
18:04justin_smiththe sad thing is that I had been using a shared component for the websockets - same code for frontend and backend, this would mean splitting them
18:05justin_smithbut it's probably for the best, there was a high density of conditionals already
18:06tolstoyI've never have luck with shared code until the end of a project. That's when I figure out the abstractions I actually needed.
18:07bjaas an aside, people who start nrepls outside of lein repl and use components, do you have an nrepl component? Do you start it outside the rest of your system?
18:09tolstoyMaybe take a config prop and add it to the SystemMap depending on that prop?
18:10bjamaybe
18:11justin_smithyeah - I would make a component that is either optionally part of the system map, or optionally starts the nrepl
18:11tolstoyYeah. Could just take a config and then when "start" is called, does (potentially) nothing.
18:11tolstoyI like that better.
18:11justin_smithif you have lots of things that conditionally start, then it can be cool to manipulate that in the system map rather than having lots of conditional short circuits in the components
18:12bjaright now mine just conditionally starts
18:12justin_smithI even made a simple "resolver", which says "start my system, but without foo" and it removes foo, and anything that depends on foo, before starting the system
18:12bjaor rather, it always tries to start, but we accept failure as an option, and we never actually stop it
18:13justin_smithit's all data!
18:13bjafrom when I was doing storm stuff I was making a lot of systems and so I represent logical systems as maps and then merge those together before creating the system map
18:14bjasince different bolts needed different stuff
18:14bjaso I ended up with a myriad of systems
18:14bjaI also have a settings component
18:15bjathat, out of the box, uses environ to resolve settings, reconciles those against a schema for the system, and if all that works, continues
18:15justin_smithcool
18:15justin_smithbja: it's pretty cool what you can do with something represented as data structures
18:15bjaso that my settings are available in the map (to be depended on (and destructured, but that's a different story))
18:16bjaso that components can want something like db-uri, but I can destructure/rename analytics-db-uri for that component
18:17bjayeah
18:17bjathe basis of most of the "amazing wins" (to some of the people I work with) are just due to representing as much of my world as data as possible
18:18bjaleads to some really cool wins like being able to use the same query language to define data permissions as well as store partial filters and execute real-time matches against incoming docs
18:20justin_smiththis line of thought makes me think we could do some really amazing things if we made better data validation tools (prismatic/schema is great, but I think other tools could be useful too (even if I don't know what they look like yet))
18:21tolstoyYeah, even just storing the config as EDN (or JSON, I guess) and using prismatic really makes QA think you're with it.
18:21bjayeah
18:22bjabasically all of our apps have something like this: https://gist.github.com/emidln/005fa93f70744cc5fe5f
18:23bjait's very nice to be able to be able to know exactly where to look for config settings and what their expected format is
18:23bjaalso nice not having to validate that all over the app
18:23justin_smithvery cool
18:26tolstoySpeaking of p/schema: vectors of variable types. Not [(s/enum t1 t2 t3)]?
18:30justin_smith(s/validate [s/Any] [:a 1]) works
18:30justin_smithdepends what all needs to be in there?
18:30justin_smithAny may be broader than what you want of course
18:31tolstoy{:id uuid :type :a :data [...]} with three different "type" values. The data depends on the type.
18:31tolstoyI can make a schema for each one, but not sure how to put them in the envelope.
18:31justin_smithoh, so what is allowed in :data needs to be calculated based on the value for :type
18:32tolstoyYeah. Kinda like {:id "asda" :type :num :data 23}.
18:32justin_smithonce you have that piece of data, you can do (s/validate [(:type m)] (:data m))
18:32justin_smithwait, that's not in a vector!
18:33justin_smithyou said it would be in a vector
18:33tolstoyWell, I'm trying to be abstract.
18:33tolstoyImagine a collection schema with three possible shapes. Enum isn't working.
18:33tolstoyPerhaps "maybe".
18:33justin_smithtolstoy: sure - general idea, you can look up the schema (in a map you make for example) based on the :type tag
18:33justin_smiththen validate the :data key
18:34tolstoyAh, so a two part validation step.
18:34justin_smithright
18:34justin_smiththis is a lisp after all!
18:34justin_smithtolstoy: this is of course more fiddly and less general than a regular schema
18:35justin_smiththere may be a way to "hoist" this concept into a proper schema that validates if the :data and :type keys agree in the way we are describing
18:35tolstoyYeah. Seems like they'd have a way to validate a heterogeneous collection of values.
18:35tolstoyGiven that's allowable in Clojure. Perhaps it's just too ill-advised. ;)
18:36tolstoyMaybe "either" is it.
18:37tolstoyDeprecated. Hm. "conditional" I guess.
18:38rhg135pred is also an option
18:40tolstoyjava.lang.IllegalArgumentException: No implementation of method: :spec of protocol: #'schema.core/Schema found for class: clojure.lang.Keyword
18:41tolstoy*sigh*
18:42tolstoyCan you validate exact keywords?
18:42justin_smithtolstoy: this is why I was suggesting looking up the schema in a hash map, based on the key under :data
18:42justin_smithoh, I misunderstood
18:43tolstoyI think there's a facility for that (s/contitional :a ThisSchema :b ThatSchema).
18:43tolstoyAssuming :a is invoked as a function in the value. No actual example of contitional.
18:44rhg135s/eq
18:45rhg135that validates equality
18:46tolstoythanks!
18:46tolstoyHm. The s/conditional is "cond" like, but how do you get a reference to the value?
18:48rhg135I think the first args of the pairs, like :a or :b in your example, are ifn
18:49rhg135predicates
18:49tolstoyI end up having to do (s/condition (= #(:type %) :text) TextSchema ..).
18:49tolstoyNow I get a "value does not match schema" and it prints 15 lines. ;)
18:55tolstoyHah! Worked!
18:56rhg135yay
18:56tolstoy(s/conditional #(= (:type %) :foo) FooSchema #(= (:type %) :bar) BarSchema)
18:56justin_smithtolstoy: sweet
18:56justin_smithTIL
18:56tolstoySure is nice, in Cider, to just C-x, C-e stuff and have to shoot out the side of the function.
18:58tolstoyjustin_smith: It was basically what you said, except inside the DSL.
18:58rhg135now just factor it out to a type? function that returns a predicate, and BAM!; declarative!
18:58tolstoyYeah.
18:58justin_smith(inc rhg135)
18:59rhg135I'm glad they finally implemented this
19:02tolstoyIt's almost like having algebraic types.
19:03rhg135if you squint hard, defschema looks like type
19:08tolstoyI kinda like the schema emphasis on data validation rather than type signatures. Feels like lateral thinking compared to most language concerns.
19:51TimMcjustin_smith: Something went *deeply* wrong with that bucketing code I wrote. I know that it should only have about 4 items per bucket, but I graphed the results, and 2 of the buckets ended up with ~30000 items.
19:51justin_smithwoah
19:51TimMcohshi-
19:52justin_smithTimMc: well I did show you that lazy version (which might have an issue or two still, but not like that...)
19:52TimMcI know what went wrong! The data wasn't monotonically increasing, that's how I screwed up.
19:52TimMchahahahaha
19:52justin_smithoh, that would do it!
19:53TimMcI wonder how long it takes to sort a million timestamps.
19:53justin_smithone million
19:55TimMcO(100000*log(1000000))
19:56TimMcjustin_smith: I had tried to do a fourier transform on the event counts per second and got this: https://i.imgur.com/XODAZSp.png
19:57justin_smithpretty!
19:57TimMcyeah!
19:57TimMc(the graph oscillates between two curves, creating a solid appearance)
19:58TimMcBut clearly screwed up, since I was expecting something mostly flat with a big spike and a couple side spikes.
19:58justin_smithat this moment I would like to say that stuartsierra's decision to make hash maps implement component by returning themselves when you call start was a very smart decision that makes this refactor very easy
19:59tolstoyHeh. That really screwed me up for a while, missing that fact.
20:00tolstoyHow come component worked in the repl, but not when starting via a main method?
20:00tolstoy(I thought the SystemMap contained an atom or something.)
20:33athanDoes clojure like monads?
21:25tolstoyathan: https://github.com/clojure/algo.monads ?
21:37princeso1) write 0. (zero dot) in your REPL. 2) put the cursor between them (0|.) . 3) write a digit 4) ?? 5) profit.
21:38justin_smithprinceso: what was that supposed to do?
21:38g0whttps://usercontent.irccloud-cdn.com/file/LiQkSixv/Screen%20Shot%202015-12-30%20at%209.37.40%20PM.png
21:39g0wprinceso: this is expected, right?
21:39princesojustin_smith There is some bug that prevents from writing digits. i dont know.
21:39justin_smithprinceso: not in my repl
21:40g0wprinceso: works for me too
21:40justin_smithprinceso: what repl - maybe it's a bug in your editor or terminal?
21:42g0wanyone done with problem 8 with advent of code? I'm stuck on it since like forever :|
21:43princesoit is the one provided by CCW i guess.
21:49princesojustin_smith im using this clojuresque:clojuresque-nrepl:1.0.0
21:50justin_smithprinceso: CCW has been unsupported for a while, right?
21:52princesog0w that was like ... you profited
21:53g0w:D
21:55princesowhat repl are you using?
21:58princesog0w what problem is that?
21:59g0wme? the standard one... lein repl - http://i.imgur.com/PVbYrDX.png
21:59justin_smithnice prompt string
22:00princesogood
22:00testerhey all
22:00g0wprinceso: the problem about escaping strings - having a hard time figuring out how to escape the ", \ etc. http://adventofcode.com/day/8
22:00g0wthanks @justin_smith
22:01justin_smithg0w: oh, interesting - did you check out pr-str ?
22:02justin_smith,(pr-str "\"")
22:02clojurebot"\"\\\"\""
22:02justin_smith,(count (pr-str "\""))
22:02clojurebot4
22:02g0w,(count (pr-str "\x27"))
22:02clojurebot#<RuntimeException java.lang.RuntimeException: Unsupported escape character: \x>
22:02g0whow do i get the \x27 testcase to work?
22:02justin_smithyeah, we don't use the same escapes
22:02justin_smithyou need an adaptor I guess...
22:03justin_smith,(count (pr-str "\\x27"))
22:03clojurebot7
22:03justin_smiththey they don't expect "\\x27" to print as \x27
22:04g0w"\x27" is 6 characters of code
22:04g0wthat's the part i'm struggling with
22:06justin_smithwell, it's 6 characters in some language
22:06justin_smithillegal in ours
22:06g0wyup
22:07g0wbut if we can't somehow make it match 6, we wouldn't be able to make the testcase pass right?
22:08justin_smithg0w: oh, you could compare count of str of the string to count of print-str of string
22:08justin_smith,(map count (juxt str print-str) "\\")
22:08clojurebot#<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.core$juxt$fn__4498>
22:09justin_smith,(map count ((juxt str print-str) "\\"))
22:09clojurebot(1 1)
22:09justin_smitherr
22:09justin_smithI know there is a way to make this work!
22:10justin_smith,(map count ((juxt str pr-str) "\"\\x27\""))
22:10clojurebot(6 11)
22:13g0wthe output we're looking for is (6 1) right/
22:13g0w?
22:14justin_smithyeah, so that's not helping at all
22:14justin_smithyou would need your own rule to turn \xNN into a single result
22:15justin_smith,\u0027
22:15clojurebot\'
22:15justin_smithturn every \x into a \u00 ?
22:15amalloyit's really not hard to implement that by hand. trying to use pr-str and such is cute, but not really worth the hassle
22:16justin_smithyeah, probably not, you're right
22:16amalloylike my solution in haskell was trivially short, and very simple/clear: https://github.com/amalloy/advent-of-code/blob/master/day8/src.hs
22:17g0w,(- (count "\"\u0027\"") 2)
22:17clojurebot1
22:18g0w@amalloy: is this for part 1 or part 2?
22:18amalloyboth. the first function is part1, the second part2
22:19g0wis that pattern matching?
22:19amalloyyeah
22:19g0wsorry.. i've never read haskell code before
22:20amalloyyou could do something similar in clojure with a bunch of cond clauses
22:20justin_smithor the silly way, with multimethods
22:21amalloy(cond (empty? s) 2, (.startsWith s "\\x") (+ 3 (overhead (drop 4 xs))) ...)
22:21amalloythough i guess you'd need to use subs instead of drop, if you want to use string operations
22:22amalloymultimethod man to the rescue?
22:22g0wamalloy: the trick is to replace "\x" into a \u00?
22:22amalloywell that was justin_smith's proposal
22:23justin_smithI think amalloy has the better plan here
22:23amalloyi'm just saying to write a recursive function on a string, and if you find it starts with \x then remove 4 characters from the string and add 3 to the recursive call
22:23g0wamalloy: got it.. let me give this a shot
22:26amalloyjustin_smith: i did try implementing it with haskell's versions of pr-str and read-string though, first
22:26princeso,(type .123456789012345678901234567890)
22:26amalloyi think it's a reasonable shortcut to try to take, but if anything goes wrong with that shortcut i'd just abandon it and do it by hand
22:26clojurebot#error {\n :cause "Unable to resolve symbol: .123456789012345678901234567890 in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: .123456789012345678901234567890 in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6704]}\n {:type java.lang.RuntimeException\n...
22:27justin_smithprinceso: numbers can't start with a . in clojure, you need 0.
22:28princesojustin_smith that makes sense
22:29justin_smithI think it's partially because we use . so much for interop stuff? dunno