0:15 mindbender1: Is boot operations slower than lein operations?
0:19 TEttinger: mindbender1: it's a good question.
0:19 ~faster
0:19 clojurebot: faster is https://
0:19 TEttinger: those are some suggestions for lein, they may be some for boot and some may apply to both (I think drip works for either)
0:22 mindbender1: TEttinger: I just wanted to be sure this was not happening only on my system.
0:23 TEttinger: are you using Boot and it's noticeably slower?
0:30 mindbender1: TEttinger: 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.
0:31 TEttinger: mm. lein repl takes a fair bit of time too for me
0:32 mindbender1: I 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.
0:33 One of the reasons I like lein is the author's will to make lein bendable to the user's will.
0:53 nys-: what does the .nrepl-port file do?
1:01 ridcully: nys-: it contains the port number of the nrepl
1:03 e.g. tools/editors can pick it up. the port usually is random
4:00 favetelinguis: im 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?
7:25 nicola: hi - 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?
7:26 there 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
7:46 pvinis: hello. 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?
7:47 if i do (myfn a) then its just one arg
7:47 can i explode it somehow?
7:50 luma: (apply myfn a)
7:54 pvinis: aha..
7:55 cool. thanks
8:51 favetelinguis: what 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:15 justin_smith: favetelinguis seems to have left, but they can block on the incoming channel and a timeout at the same time, by using alts!
10:18 TimMc: clojurebot: mutation is exciting!
10:18 clojurebot: c'est bon!
10:22 g0w: hi everyone.. i'm having some trouble understanding this syntax. How do I pass-in a different value of tempo?
10:22 https://
10:23 Can't quite the understand the destructuring that's going on in the function argument
10:23 clojurebot: Huh?
10:23 justin_smith: g0w: (test-args [] :tempo 80)
10:23 and we don't really use the & {} thing much any more
10:23 g0w: hello again @justin_smith
10:23 ah okay! thanks a lot!
10:24 what do we generally use in these cases?
10:24 justin_smith: g0w: just a hash map with keys and values
10:24 TimMc: Just drop the & and have a map arg there :-)
10:24 justin_smith: (like what you tried to use)
10:24 yeah
10:24 g0w: got it! thanks!
10:24 TimMc: You can add another arity to default the map to empty or nil.
10:25 g0w: @TimMc yup.. that would be my preference too.. i found this code in a book
10:26 so I had one meta question with immutability in clojure..
10:27 does the immutability thing hold true only for clojure datatypes?
10:27 for example, I was using a BitSet yesterday, and calling (.set bitset) didn't return a new bitset
10:27 justin_smith: the clojure datatypes, strings, and primitives are all effectively immutable
10:27 everything else is mostly mutable, it's the same objects java uses
10:27 engblom: I 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:28 And 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:28 justin_smith: engblom: yes, but it might not do what you want. Where is the name being assigned?
10:28 do you mean def?
10:29 g0w: so 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:29 justin_smith: g0w: pretty much, yeah. And you shouldn't put mutable objects inside atoms or refs either
10:30 g0w: ok.. got it.. what's the accepted best practice in these cases? rely as less as you can on java objects?
10:30 yenda: is there a way to check for more recent dependencies with boot ?
10:30 justin_smith: engblom: 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:32 engblom: justin_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:32 ?
10:34 TimMc: g0w: Clojure doesn't change the way Java and the JVM work, it just provides alternatives and wrappers.
10:34 justin_smith: engblom: 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:34 engblom: this is just one reason def at runtime is usually wrong
10:35 TimMc: g0w: 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:35 g0w: cloning? can you elaborate a bit more?
10:35 engblom: justin_smith: To be more specific, I am looking at this library: https://
10:36 TimMc: g0w: If I hand you a mutable object, you might want to create a copy so that I can't accidentally modify your instance.
10:36 g0w: but woulnd't a deep clone of every object be expensive with no structural sharing in place?
10:37 TimMc: It can be, yes.
10:37 justin_smith: but you shouldn't need deep cloning, because you don't need the mutable collection types
10:37 engblom: justin_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:37 g0w: justin_smith: BitSet is a mutable collection type, right?
10:38 engblom: But 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:38 justin_smith: kind 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:39 g0w: @justin_smith: ah yes, I get what you mean.
10:39 justin_smith: engblom: 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:05 jjttjj: I 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:12 justin_smith: jjttjj: 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:24 m1dnight_: A bit off topic, but are there some more general programming-related channels I could check out on freenode (or others)?
11:30 sdegutis: m1dnight_: ##programming
11:30 m1dnight_: ##webdev
11:30 m1dnight_: Oh, that is rather obvious :> thanks
11:30 Joined them
11:30 sdegutis: :)
12:04 favetelinguis: i 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:35 TimMc: ,(clojure.string/escape "foo" {\o \e})
12:35 clojurebot: "fee"
12:36 TimMc: favetelinguis: IPersistentCollection is pretty vague. Do you know anything else about the value?
12:51 sfz-: ,(clojure.string/escape "foo.com?q=bar baz qux" {' ' '+'})
12:51 clojurebot: #<RuntimeException java.lang.RuntimeException: Map literal must contain an even number of forms>
12:51 sfz-: hm
12:51 MJB47: use " instead of '
12:51 sfz-: ,(clojure.string/escape "foo.com?q=bar baz qux" {" " "+"})
12:51 clojurebot: "foo.com?q=bar baz qux"
12:52 sfz-: nope, how would you replace a space?
12:52 MJB47: try string/replace
12:53 TimMc: ,(clojure.string/escape "f " {space \o})
12:53 clojurebot: #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:53 TimMc: urgh
12:53 ,(clojure.string/escape "f " {\space \o})
12:53 clojurebot: "foo"
12:53 TimMc: sfz-: ^ But really you wouldn't, you'd use a URL library.
12:53 sfz-: ,(clojure.string/escape "foo.com?q=bar baz qux" {\space \+})
12:53 clojurebot: "foo.com?q=bar+baz+qux"
12:53 justin_smith: favetelinguis: when you call conj on any object implementing IPersistentCollection you get a copy with your data added to the collection
12:54 sfz-: TimMc: right, was just curious, thanks!
12:54 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:55 justin_smith: ,(java.net.url/URLEncode "foo.com?q=bar baz qux" "UTF-8")
12:55 clojurebot: #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:56 justin_smith: ,(java.net.URLEncoder/encode "foo.com?q=bar baz qux" "UTF-8")
12:56 clojurebot: "foo.com%3Fq%3Dbar+baz+qux"
12:56 justin_smith: really you would only encode the part that goes after the ? of course
12:56 sfz-: right
12:56 thanks again
12:56 TimMc: ,(->> (range 256) (map char) (filter #(not= (count (pr-str %)) 2)))
12:56 justin_smith: ,(str "foo.com?" (java.net.URLEncoder/encode "q=bar baz qux" "UTF-8")
12:56 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>
12:56 (\backspace \tab \newline \formfeed \return ...)
12:57 justin_smith: ,(str "foo.com?" (java.net.URLEncoder/encode "q=bar baz qux" "UTF-8"))
12:57 clojurebot: "foo.com?q%3Dbar+baz+qux"
12:57 TimMc: except URLEncoder is wrong :-(
12:57 justin_smith: TimMc: I still think I'm using it wrong...
12:57 TimMc: and this is where replace actually does come in
12:57 sfz-: ,(ring.util.codec/url-encode "clojure url")
12:57 clojurebot: #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:57 sfz-: aw, no clojars eh?
12:57 justin_smith: sfz-: clojurebot won't have any ring stuff
12:57 TimMc: justin_smith: https://
12:58 justin_smith: sfz-: it might use clojars, but that's not how you add something ot the classpath
12:58 TimMc: ahh
12:58 TimMc: wait, that's decoding... but you just do it in reverse
13:47 jjttjj: how 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:48 maybe i'll just do ecs/ECS?
13:49 justin_smith: why are you clojureizing a class name?
13:49 jjttjj: i need to stick the connection object in a map, trying to figure out what to name the key
13:51 justin_smith: I would usually use a key like :socket - depending on context etc. of course
13:51 jjttjj: justin_smith: cool thanks! getting hung up on dumb things today
14:02 TimMc: :☃-socket
14:03 justin_smith: TimMc: well, it is a Snowman, so as an initialism :☃ ocket should work
14:07 TimMc: nice, even more concise
14:07 justin_smith: it even has a compatible outline
15:08 TimMc: Incanter doesn't appear to have fourier transforms... what am I missing?
15:36 justin_smith: TimMc: clearly they expect every user to hand-roll their own fft
15:36 creese: I'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:37 Kajtek: Hi guys, so I've run into a problem when using map destructuring and lazy sequences.
15:37 Basically, whenever I pass a lazy seq with odd number of elements to a function that uses destructuring I get an exception.
15:37 Even-numbered sequences work as expected.
15:38 Here's a minimal reproduction: ((fn [{:keys [k]}] k) (lazy-seq [{:k :a}]))
15:38 Is it a known bug? I don't really follow Clojure development.
15:38 Also, this happens on Clojure 1.7.0.
15:38 MJB47: {:keys...} only works correctly if the input is a map
15:38 justin_smith: Kajtek: that argument is incorrect
15:38 MJB47: you have a sequence of maps
15:39 justin_smith: if you replaced [{:keys [k]}] with [[{:keys [k]}]] in the function definition it would work
15:39 (but other calls would likely break)
15:40 Kajtek: Then it working for even-numbered seqs is kind of misleading.
15:40 justin_smith: Kajtek: yes, it works accidentally, and is unlikely to give a correct result
15:40 Kajtek: there are many things in clojure that work accidentally
15:41 ,(:or :a :b) ; a classic mistake, which might even pass your tests sometimes
15:41 clojurebot: :b
15:42 Kajtek: I guess warts happen.
15:42 Thanks for the help. I suppose I'll get rid of destructuring and check if the argument passed is a map beforehand.
15:43 ystael: justin_smith: *chokes on popcorn* that's a trap that never occurred to me
15:43 justin_smith: ystael: I've seen it!
15:43 ,(:or false :a) ; the version that looks like it works
15:44 clojurebot: :a
15:44 ystael: i don't think i knew that keyword-as-map-extractor could take a second arg
15:44 justin_smith: ystael: see also (:require '[it doesn't matter what you put here]) - returns nil, as you expect
15:44 and of course, does nothing at all
15:45 ystael: this sounds like an argument for tutti frutti syntax coloring
15:46 justin_smith: heh - or a stricter programming language :P
15:46 ystael: Well, yes, but this is #clojure :)
15:46 justin_smith: ystael: 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:47 ystael: Fortunately I typically err in the opposite direction instead, typing (require '[...) inside the ns macro
15:48 justin_smith: it'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:48 ystael: ah well, I use clojure because it's a good set of practical compromises, not because I think it's perfect :)
15:48 justin_smith: thinko is of course short for thinkographical error
15:50 * TimMc updates wikipedia
16:00 jiamo: I find hard to transalte this algorthm into clojure
16:00 n=”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:01 It is a Procedural paradigm
16:02 justin_smith: jiamo: the trivial transormation is to turn the while into a loop, and make every value mutated inside the while into a loop binding
16:02 that doesn't always give the best result of course, but its the version that is easiest to translate
16:03 nested while might require a let binding to bind the loop variables coming out from the inner loop
16:04 also, 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:13 oh, 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:16 sohail: is 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:17 justin_smith: sohail: what do you mean by "without unpacking it" ?
16:18 sohail: justin_smith: I mean without doing something like (my-multi (first data) (second data))
16:18 justin_smith: (defmulti my-multi first)
16:18 sohail: oh!
16:19 I think I need to read this stuff more carefully
16:19 justin_smith: or maybe (defmulti my-multi (comp type first)) if you still want to dispatch by type...
16:19 and that needs adjusting if your method takes multiple args too, of course
16:20 sohail: there are a lot of examples of defmulti on grimoir - it can do a lot!
16:20 sohail: what is grimoir?
16:20 justin_smith: http://
16:20 conj.io is grimoir
16:21 incidentally, I fixed and/or wrote most of the defmulti examples myself
16:22 sohail: awesome, thanks justin_smith
16:24 amalloy: justin_smith has accidentally betrayed his alter-ego, MultiMethodMan
16:25 justin_smith: what's that? commisioner Gordon has lit the dispatch signal - wait a moment while I look up the method that signal dispatches to
16:28 amalloy: oh no! the joker has replaced your dispatch function with (#(% %) #(% %))! now you'll never get to the crime scene in time!
16:28 justin_smith: haha
16:29 holy combinators batman!
16:34 TimMc: I 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:34 I think my best bet is a loop and split-with, but is there something even simpler?
16:35 justin_smith: ,(group-by #(count (str (/ % 1000))) [1 35 456 2005 3045 3987]
16:35 oops
16:35 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>
16:35 justin_smith: ,(group-by #(count (str (/ % 1000))) [1 35 456 2005 3045 3987])
16:35 clojurebot: {6 [1 456], 5 [35], 7 [2005 3045], 9 [3987]}
16:36 justin_smith: oh, that wasn't a truncating divide, d'oh
16:37 TimMc: The key is that I also want empty buckets.
16:37 justin_smith: ,(group-by #(int (/ % 1000)) [1 35 456 2005 3045 3987])
16:37 clojurebot: {0 [1 35 456], 2 [2005], 3 [3045 3987]}
16:37 justin_smith: ahh
16:38 TimMc: maybe a trick with (comp max keys) and range and (fnil (m %) [])
16:38 TimMc: hrm
16:38 ystael: or you could just write the reduce by hand
16:38 luma: ,(mod 2005 1000)
16:39 clojurebot: 5
16:39 luma: ah, not modulo
16:39 ystael: (you have reduce, why do you need anything else? :))
16:39 TimMc: I think loop is better here since I need to bind 2-3 values on each iteration.
16:39 luma: ,(quot 2005 1000)
16:39 clojurebot: 2
16:39 luma: this one
16:40 justin_smith: luma: yeah, better to use quot than (comp int /)
16:42 TimMc: Here's my solution: https://
16:43 justin_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:43 ,(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:43 clojurebot: ([1 35 456] [] [2005] [3045 3987])
16:44 TimMc: "now make it lazy"
16:44 justin_smith: :)
16:45 TimMc: I've made a maximally lazy coll-of-colls splitter like this before and it was annoying to write: https://
16:46 The approach was to lazily inject sentinels at the boundaries, then lazily group on the sentinels.
16:58 justin_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:58 clojurebot: ((1 35 456) [] (2005) (3045 3987))
16:59 justin_smith: there is probably a way to make that less loony
17:02 also that [0] should probably be a -1 and the behavior around various orders of magnitude as starting values probably needs fixing
17:05 tolstoy: clojars still out, eh?
17:06 justin_smith: oh wow, what happened?
17:06 tolstoy: No idea. My "lein ancient" was having issues. Checked: https://
17:07 Ah, it's back in the browser, now.
17:07 justin_smith: tolstoy: https://
17:07 oh, d'oh, while I am looking that up you mention their twitter, heh
17:07 tolstoy: Yeah, that was Dec 27.
17:08 justin_smith: do you know which location they are using?
17:08 tolstoy: Okay, it's back.
17:08 No idea.
17:11 TimMc: linode is being DOS'd
17:11 Has been for a couple days, I think?
17:12 tolstoy: Fastmail's been having a problem as well.
17:12 AIs getting a little feisty?
17:19 TimMc: Someone's probably trying to extort them.
17:53 justin_smith: repeating my core.async / cljs question here because #clojurescript is looking a bit underattended right now
17:53 OK, I have an issue that comes up because <!! is missing in cljs
17:53 in 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:54 in other words I need to block until I get a message - but can't use <!!
17:54 is 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:54 tolstoy: Are you using one of the reacty things?
17:54 justin_smith: yes, but none of the reacty crap is running yet when this happens
17:55 tolstoy: Oh. I was going to suggest just run as normal, but set a prop in the state such that nothing gets rendered.
17:55 justin_smith: this 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:55 tolstoy: When the appropriate message comes in, reset that, and the GUI will pop-up.
17:55 justin_smith: tolstoy: yeah, this is about more than props
17:55 right
17:56 tolstoy: (swap! state assoc :view :loading)
17:56 I do that, anyway.
17:56 justin_smith: tolstoy: 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:56 tolstoy: If (:user state) is nil, render a loading component. Eventually, data comes in and it works.
17:57 justin_smith: other components do things (before react renders) that will break badly if this data is not present
17:57 tolstoy: Oy.
17:57 justin_smith: and I can't just put the data in the cljs file
17:58 tolstoy: That's a bit of a monkey-wrench.
17:58 bja: justin_smith: could you use take! and write a function that delivers to a promise then deref that?
17:58 justin_smith: bja: no promises in cljs!
17:58 I thought of that one too
17:58 bja: could you use $.deferred or something likethat?
17:58 justin_smith: hmm... we aren't using $ at all, but maybe there's an alternative I could use
17:59 bja: isn't there a pure-cljs promise library
17:59 justin_smith: bja: maybe, I didn't check for that
17:59 bja: https://
17:59 justin_smith: it would be just the thing I guess as long as it played nicely with async stuff that needs to happen
17:59 tolstoy: https://
18:00 justin_smith: and when I say that, I start to think maybe I do need to suck my whole component system into core.async... oh no
18:00 tolstoy: Maybe have a whole bootstrap system, then invoke component stuff once it's complete?
18:01 justin_smith: maybe I could pull this component out of stuartsierria/component and start it first
18:02 usint take with a "start all the other components" as the callback?
18:02 clearly we need "components, but async"
18:02 bja: does component work in cljs now?
18:03 tolstoy: (go (let [data (<! (bootstrap))] (start-system data)))
18:03 justin_smith: yeah - I did my own cljc port ages ago, and eventually I will switch to the official cljc port which came out more recently
18:03 tolstoy: exactly
18:03 tolstoy: that's probably what I need to do, thanks
18:04 the 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:05 but it's probably for the best, there was a high density of conditionals already
18:06 tolstoy: I'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:07 bja: as 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:09 tolstoy: Maybe take a config prop and add it to the SystemMap depending on that prop?
18:10 bja: maybe
18:11 justin_smith: yeah - I would make a component that is either optionally part of the system map, or optionally starts the nrepl
18:11 tolstoy: Yeah. Could just take a config and then when "start" is called, does (potentially) nothing.
18:11 I like that better.
18:11 justin_smith: if 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:12 bja: right now mine just conditionally starts
18:12 justin_smith: I 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:12 bja: or rather, it always tries to start, but we accept failure as an option, and we never actually stop it
18:13 justin_smith: it's all data!
18:13 bja: from 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:14 since different bolts needed different stuff
18:14 so I ended up with a myriad of systems
18:14 I also have a settings component
18:15 that, out of the box, uses environ to resolve settings, reconciles those against a schema for the system, and if all that works, continues
18:15 justin_smith: cool
18:15 bja: it's pretty cool what you can do with something represented as data structures
18:15 bja: so that my settings are available in the map (to be depended on (and destructured, but that's a different story))
18:16 so that components can want something like db-uri, but I can destructure/rename analytics-db-uri for that component
18:17 yeah
18:17 the 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:18 leads 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:20 justin_smith: this 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:21 tolstoy: Yeah, even just storing the config as EDN (or JSON, I guess) and using prismatic really makes QA think you're with it.
18:21 bja: yeah
18:22 basically all of our apps have something like this: https://
18:23 it'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:23 also nice not having to validate that all over the app
18:23 justin_smith: very cool
18:26 tolstoy: Speaking of p/schema: vectors of variable types. Not [(s/enum t1 t2 t3)]?
18:30 justin_smith: (s/validate [s/Any] [:a 1]) works
18:30 depends what all needs to be in there?
18:30 Any may be broader than what you want of course
18:31 tolstoy: {:id uuid :type :a :data [...]} with three different "type" values. The data depends on the type.
18:31 I can make a schema for each one, but not sure how to put them in the envelope.
18:31 justin_smith: oh, so what is allowed in :data needs to be calculated based on the value for :type
18:32 tolstoy: Yeah. Kinda like {:id "asda" :type :num :data 23}.
18:32 justin_smith: once you have that piece of data, you can do (s/validate [(:type m)] (:data m))
18:32 wait, that's not in a vector!
18:33 you said it would be in a vector
18:33 tolstoy: Well, I'm trying to be abstract.
18:33 Imagine a collection schema with three possible shapes. Enum isn't working.
18:33 Perhaps "maybe".
18:33 justin_smith: tolstoy: sure - general idea, you can look up the schema (in a map you make for example) based on the :type tag
18:33 then validate the :data key
18:34 tolstoy: Ah, so a two part validation step.
18:34 justin_smith: right
18:34 this is a lisp after all!
18:34 tolstoy: this is of course more fiddly and less general than a regular schema
18:35 there 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:35 tolstoy: Yeah. Seems like they'd have a way to validate a heterogeneous collection of values.
18:35 Given that's allowable in Clojure. Perhaps it's just too ill-advised. ;)
18:36 Maybe "either" is it.
18:37 Deprecated. Hm. "conditional" I guess.
18:38 rhg135: pred is also an option
18:40 tolstoy: java.lang.IllegalArgumentException: No implementation of method: :spec of protocol: #'schema.core/Schema found for class: clojure.lang.Keyword
18:41 *sigh*
18:42 Can you validate exact keywords?
18:42 justin_smith: tolstoy: this is why I was suggesting looking up the schema in a hash map, based on the key under :data
18:42 oh, I misunderstood
18:43 tolstoy: I think there's a facility for that (s/contitional :a ThisSchema :b ThatSchema).
18:43 Assuming :a is invoked as a function in the value. No actual example of contitional.
18:44 rhg135: s/eq
18:45 that validates equality
18:46 tolstoy: thanks!
18:46 Hm. The s/conditional is "cond" like, but how do you get a reference to the value?
18:48 rhg135: I think the first args of the pairs, like :a or :b in your example, are ifn
18:49 predicates
18:49 tolstoy: I end up having to do (s/condition (= #(:type %) :text) TextSchema ..).
18:49 Now I get a "value does not match schema" and it prints 15 lines. ;)
18:55 Hah! Worked!
18:56 rhg135: yay
18:56 tolstoy: (s/conditional #(= (:type %) :foo) FooSchema #(= (:type %) :bar) BarSchema)
18:56 justin_smith: tolstoy: sweet
18:56 TIL
18:56 tolstoy: Sure is nice, in Cider, to just C-x, C-e stuff and have to shoot out the side of the function.
18:58 justin_smith: It was basically what you said, except inside the DSL.
18:58 rhg135: now just factor it out to a type? function that returns a predicate, and BAM!; declarative!
18:58 tolstoy: Yeah.
18:58 justin_smith: (inc rhg135)
18:59 rhg135: I'm glad they finally implemented this
19:02 tolstoy: It's almost like having algebraic types.
19:03 rhg135: if you squint hard, defschema looks like type
19:08 tolstoy: I kinda like the schema emphasis on data validation rather than type signatures. Feels like lateral thinking compared to most language concerns.
19:51 TimMc: justin_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:51 justin_smith: woah
19:51 TimMc: ohshi-
19:52 justin_smith: TimMc: well I did show you that lazy version (which might have an issue or two still, but not like that...)
19:52 TimMc: I know what went wrong! The data wasn't monotonically increasing, that's how I screwed up.
19:52 hahahahaha
19:52 justin_smith: oh, that would do it!
19:53 TimMc: I wonder how long it takes to sort a million timestamps.
19:53 justin_smith: one million
19:55 TimMc: O(100000*log(1000000))
19:56 justin_smith: I had tried to do a fourier transform on the event counts per second and got this: https://
19:57 justin_smith: pretty!
19:57 TimMc: yeah!
19:57 (the graph oscillates between two curves, creating a solid appearance)
19:58 But clearly screwed up, since I was expecting something mostly flat with a big spike and a couple side spikes.
19:58 justin_smith: at 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:59 tolstoy: Heh. That really screwed me up for a while, missing that fact.
20:00 How come component worked in the repl, but not when starting via a main method?
20:00 (I thought the SystemMap contained an atom or something.)
20:33 athan: Does clojure like monads?
21:25 tolstoy: athan: https://
21:37 princeso: 1) write 0. (zero dot) in your REPL. 2) put the cursor between them (0|.) . 3) write a digit 4) ?? 5) profit.
21:38 justin_smith: princeso: what was that supposed to do?
21:38 g0w: https://
21:39 princeso: this is expected, right?
21:39 princeso: justin_smith There is some bug that prevents from writing digits. i dont know.
21:39 justin_smith: princeso: not in my repl
21:40 g0w: princeso: works for me too
21:40 justin_smith: princeso: what repl - maybe it's a bug in your editor or terminal?
21:42 g0w: anyone done with problem 8 with advent of code? I'm stuck on it since like forever :|
21:43 princeso: it is the one provided by CCW i guess.
21:49 justin_smith im using this clojuresque:clojuresque-nrepl:1.0.0
21:50 justin_smith: princeso: CCW has been unsupported for a while, right?
21:52 princeso: g0w that was like ... you profited
21:53 g0w: :D
21:55 princeso: what repl are you using?
21:58 g0w what problem is that?
21:59 g0w: me? the standard one... lein repl - http://
21:59 justin_smith: nice prompt string
22:00 princeso: good
22:00 tester: hey all
22:00 g0w: princeso: the problem about escaping strings - having a hard time figuring out how to escape the ", \ etc. http://
22:00 thanks @justin_smith
22:01 justin_smith: g0w: oh, interesting - did you check out pr-str ?
22:02 ,(pr-str "\"")
22:02 clojurebot: "\"\\\"\""
22:02 justin_smith: ,(count (pr-str "\""))
22:02 clojurebot: 4
22:02 g0w: ,(count (pr-str "\x27"))
22:02 clojurebot: #<RuntimeException java.lang.RuntimeException: Unsupported escape character: \x>
22:02 g0w: how do i get the \x27 testcase to work?
22:02 justin_smith: yeah, we don't use the same escapes
22:02 you need an adaptor I guess...
22:03 ,(count (pr-str "\\x27"))
22:03 clojurebot: 7
22:03 justin_smith: they they don't expect "\\x27" to print as \x27
22:04 g0w: "\x27" is 6 characters of code
22:04 that's the part i'm struggling with
22:06 justin_smith: well, it's 6 characters in some language
22:06 illegal in ours
22:06 g0w: yup
22:07 but if we can't somehow make it match 6, we wouldn't be able to make the testcase pass right?
22:08 justin_smith: g0w: oh, you could compare count of str of the string to count of print-str of string
22:08 ,(map count (juxt str print-str) "\\")
22:08 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.core$juxt$fn__4498>
22:09 justin_smith: ,(map count ((juxt str print-str) "\\"))
22:09 clojurebot: (1 1)
22:09 justin_smith: err
22:09 I know there is a way to make this work!
22:10 ,(map count ((juxt str pr-str) "\"\\x27\""))
22:10 clojurebot: (6 11)
22:13 g0w: the output we're looking for is (6 1) right/
22:13 ?
22:14 justin_smith: yeah, so that's not helping at all
22:14 you would need your own rule to turn \xNN into a single result
22:15 ,\u0027
22:15 clojurebot: \'
22:15 justin_smith: turn every \x into a \u00 ?
22:15 amalloy: it'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:16 justin_smith: yeah, probably not, you're right
22:16 amalloy: like my solution in haskell was trivially short, and very simple/clear: https://
22:17 g0w: ,(- (count "\"\u0027\"") 2)
22:17 clojurebot: 1
22:18 g0w: @amalloy: is this for part 1 or part 2?
22:18 amalloy: both. the first function is part1, the second part2
22:19 g0w: is that pattern matching?
22:19 amalloy: yeah
22:19 g0w: sorry.. i've never read haskell code before
22:20 amalloy: you could do something similar in clojure with a bunch of cond clauses
22:20 justin_smith: or the silly way, with multimethods
22:21 amalloy: (cond (empty? s) 2, (.startsWith s "\\x") (+ 3 (overhead (drop 4 xs))) ...)
22:21 though i guess you'd need to use subs instead of drop, if you want to use string operations
22:22 multimethod man to the rescue?
22:22 g0w: amalloy: the trick is to replace "\x" into a \u00?
22:22 amalloy: well that was justin_smith's proposal
22:23 justin_smith: I think amalloy has the better plan here
22:23 amalloy: i'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:23 g0w: amalloy: got it.. let me give this a shot
22:26 amalloy: justin_smith: i did try implementing it with haskell's versions of pr-str and read-string though, first
22:26 princeso: ,(type .123456789012345678901234567890)
22:26 amalloy: i 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:26 clojurebot: #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:27 justin_smith: princeso: numbers can't start with a . in clojure, you need 0.
22:28 princeso: justin_smith that makes sense
22:29 justin_smith: I think it's partially because we use . so much for interop stuff? dunno