#clojure log - Aug 31 2014

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

0:20 meoblast001: is there a way to map in clojure and get the previous item without using reduce?

0:33 xeqi: ,(map (juxt identity inc) [1 2 3])

0:33 clojurebot: ([1 2] [2 3] [3 4])

0:33 xeqi: meoblast001: ^ ?

0:34 maravillas: ,(let [c (range 4)] (map vector c (drop 1 c)))

0:34 clojurebot: ([0 1] [1 2] [2 3])

0:34 meoblast001: hmm. that works i think

0:34 xeqi: or did you mean the previous in the list?

0:34 meoblast001: previous or next works really

0:34 maravillas: ,(map identity (partition 2 1 (range 4)))

0:34 clojurebot: ((0 1) (1 2) (2 3))

0:35 xeqi: meoblast001: then something like maravillas's answer

0:35 meoblast001: hmm

0:35 i don't think i understand juxt :/

0:36 maravillas: ah, yes. just throwing the partition in could do it

0:36 thanks

0:36 maravillas: welcome :)

0:36 gws: ,(map (juxt inc) [1 2 3])

0:37 clojurebot: ([2] [3] [4])

0:37 gws: ,(map (juxt inc dec) [1 2 3])

0:37 clojurebot: ([2 0] [3 1] [4 2])

0:38 gws: meoblast001: does that help?

0:39 meoblast001: hmm

0:39 gws: so juxt produces a new function which will call each of the functions you passed to it on the element you give the new 'juxt-function', and return a vector with those results

0:39 meoblast001: so it takes arbitrary functions with 2 parameter

0:39 and creates one function with 1 parameter

0:40 gws: you can give juxt as many functions as you like

0:40 as i did above

0:40 meoblast001: that 1 parameter is a list,and it applies those arbitrary functions to all of those functions to each element in the list

0:40 hmmm okay

0:40 makes sense. thanks

0:40 gws: ,(map (juxt inc dec inc dec) [1 2 3])

0:40 clojurebot: ([2 0 2 0] [3 1 3 1] [4 2 4 2])

0:41 meoblast001: ,((juxt inc dec) 5)

0:41 clojurebot: [6 4]

0:41 meoblast001: yeah, makes sense

0:50 wildnux: when i do (seq "abcd") it shows ("a", "b", "c", "d") in clojurescript but shows (\a, \b, \c, \d) in clojure, why is it different, and how do i know which "seq" funtion i am using?

0:51 how do i know the full namespaced form of a function or var?

0:52 rhg135: wildnux, in js there are no characters, they're single char strings

0:53 wildnux: rhg135: aah :)

0:53 rhg135: how do i get the full namespaced form of a function/symbol/vars in clojure?

0:53 i thought #'varname would show but it doesnot :D

0:53 rhg135: ,(symbol (resolve '+))

0:53 clojurebot: #<ClassCastException java.lang.ClassCastException: clojure.lang.Var cannot be cast to java.lang.String>

0:53 rhg135: hmm

0:55 ,(symbol (-> (resolve '+) str (subs 2)))

0:55 clojurebot: clojure.core/+

0:55 rhg135: very hackish tho

0:55 verma: the syntax quote should work too right?

0:55 ,`+

0:55 clojurebot: clojure.core/+

0:55 rhg135: oh

0:55 duh

0:55 thank you

0:56 verma: :)

0:56 wildnux: what does resolve do?

0:56 rhg135: resolves a symbol to a var in clj

1:02 fifosine: ,(let [word "0123"]

1:02 (loop [coll (butlast word)]

1:02 (if (empty? coll)

1:02 (println (last word))

1:02 (do

1:02 (println (first coll))

1:02 (println "join")

1:02 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

1:02 fifosine: (recur (rest coll))))))

1:07 opqdonut: fifosine: you should've given the whole sexp on one line

1:15 fifosine: What's a macro that will take something like

1:15 ,(take 5 (repeat '(println 5)))

1:15 clojurebot: ((println 5) (println 5) (println 5) (println 5) (println 5))

1:15 fifosine: and wrap it in a do form?

1:57 blaenk: I realize this may be a very broad/open question, but can anyone imagine why it takes two sends for my core.async to register a receive?

1:58 I made the channel with (chan), and am only using put! and <!

2:16 harja: Hi all, a very dumb question, how do I perform a long lasting calculation once and bind it to a name in the ns? I tried (def foo (filter ... pmap ....))

2:17 hm, now it was instantaneous... what the

2:17 So that is the right way then? :)

7:50 kqr: haroldwu, your question isn't entirely clear, but it's possible that filter/map doesn't perform the computation until it is needed, and then it's only done once

7:50 haroldwu, never mind

7:50 haroldwu, that was meant for someone else who isn't hear anymore and i'm tired enough to not notice the tab completion going wrong

7:54 Rhainur: kqr: haha I was trying to figure out where the question was

8:18 martinklepsch: in the core.async documentation functions like map< have a note "Deprecated - this function will be removed. Use transformer instead" — whats a transformer in that context?

8:18 john2x: hello. how do I stop a function from running in a CIDER repl?

8:19 martinklepsch: I think they refer to transducers http://blog.cognitect.com/blog/2014/8/6/transducers-are-coming

8:21 the post includes an example using it with channels.. so the doc could be a typo/needs updating..

8:21 kqr: yeah that looks like that'd be it

8:23 john2x: ah here "So, reducing function transformers are getting a name - 'transducers', and first-class support in Clojure core and core.async."

8:30 kqr: is there some version of contains? that works for a set of keys, and checks if all of them exists in the indexable? (as opposed to some which only checks for if at least one of them exists)

8:31 martinklepsch: john2x: that was the first thing that popped to my mind as well but the name confused me. thanks!

8:32 kqr: ah, (every?) does that, it seems

8:32 wait no

8:32 that's not quite it either I don't think

8:35 john2x: kqr: superset?

8:35 ah but both needs to be sets

8:36 kqr: yeah

8:36 if it helps, what is happening is that i'm trying to write a test for a function that returns a map

8:36 that map is supposed to have a few things

8:36 though now that I say it

8:36 i think I might be doing the entire thing wrong

8:52 but how *do* I express "I want this map to be equal to this map except it might contain some more things?"

8:52 it's not a transitive relation, but it shouldn't be too weird anyway, I think

8:53 it's like superset? but for maps

8:54 I guess I can convert to sets and then check superset?

8:54 ephemeron: kqr: There are many ways to approach the problem; if you would like to use sets, you can just extract the keys from the map with `keys`.

8:55 kqr: ephemeron, in this case I realised I want keys and values

8:55 john2x: hmm why does `((fn [] [:a :b]))` work but `(#([:a :b]))` doesn't?

8:55 kqr: ephemeron, so I have a function that returns {:name "kqr" :age 27 :occupation :unemployed} and I want to check that it contains *at least* {:name "kqr" :age 27}

8:55 but it can contain more than that

8:56 john2x, it evaluates the thing inside #() as something inside normal parens

8:56 john2x, with the exception of argument expansion

8:57 john2x, so it tries to interpret your vector as a function or special form, I guess?

8:57 john2x, #(quote [1 2]) works

8:57 john2x, so does #(identity [1 2])

8:58 ephemeron: kqr: Are you looking to validate the values, or just check if they are present?

8:58 john2x: oh so it's more ((fn [] ([:a :b])))?

8:58 kqr: john2x, exactly

8:58 john2x: ok, makes sense. thanks

8:58 kqr: ephemeron, i'm writing a test for a parser. i give it a string and I want to check that it gives me the correct map back (which contains the result of the parse)

9:01 ephemeron: kqr: If you trust the values and only want to verify that the required keys are present,

9:02 you could do e.g. (superset? (into #{} (keys some-map)) required-keys)

9:02 kqr: ephemeron, I don't trust the values :>

9:07 ephemeron: If it is just for a one-off predicate, you could convert both the to-be-tested map and the test-map to sets; for full validation, you might want to seek a library.

9:09 kqr: thanks

9:09 ephemeron: e.g. (into #{} {:a 1 :b 2 :c 3}) is a superset of (into #{} {:a 1 :b 2})

9:09 but not of (into #{} {:a 1 :b 3}).

9:12 kqr: is there a particular reason to use (partial into #{}) instead of (set)?

9:12 gfredericks: kqr: into uses transients

9:12 until 1.7, then clojure.core/set should be upgraded to use transients as well

9:13 kqr: ah

9:40 wow I went from trying to write a few tests to majorly reworking parts of my design to be much better

9:40 that's what I really like about tests

10:44 hm

10:44 what I don't like is that so many functions return nil when they fail

10:46 mi6x3m: kqr: why is this?

10:47 kqr: maybe that's just me but it feels like I have to do so many explicit checks

10:47 though perhaps I should just set up a precondition on my function that guarantees no nils creeping in

10:51 mi6x3m, what my function does is it takes a map, and then produces a new map from it

10:51 mi6x3m, but if the original map doesn't have all the values it's supposed to, the new map will contain nils in certain places

10:51 mi6x3m, which is bad

10:52 mi6x3m, because then i'll use the new map expecting it to have no nils in those places, and whenever the program finally crashes or shows bad behaviour, the cause is far from the effect

10:55 thesaskwatch: Hi, why when I do (swap! (atom "abc") str "def") I get abcdef instead of def?

10:57 ok, now I know

10:57 nvm

10:57 ephemeron: thesaskwatch: `swap!` passes the current value of the atom to the applied function.

10:57 You most likely want `reset!`

10:58 thesaskwatch: ephemeron: thanks .. you I should just read the friendly manual

10:58 you -> yeah

10:59 jbaiter: when i open a repl with 'lein repl', how can I add the current working directory to the classpath?

11:00 when i try to do '(use my-ns)' it says that it can't find "my_ns.clj" on the classpath, even though a file with that name exists in the directory i start the repl from

11:18 fifosine: I've got these two function which follow the same form https://www.refheap.com/89623 in which a no-arg, side-effectful function is executed in between the execution of a one-arg, side-effectful function for each element in a list. Is there a way to write a function that abstracts this form based on the two functions and the collection?

11:25 mi6x3m: fifosine: some more info please?

11:25 I see they are quite similar

11:25 fifosine: mi6x3m: What info do you need?

11:25 mi6x3m: yet how many such functions do you expect to have?

11:25 fifosine: I expect 1 function to abstract the similar functionality seen in the paste

11:26 mi6x3m: ehm, i'm not sure if I am going to do that

11:26 in fact, in their current form

11:26 both functions are extremely hard to comprehend

11:27 for someone else than you

11:28 fifosine: maybe I can make more sense of them: the doseq is there only to execute the list of functions that's being created. the list of functions is created by the interposing of 1) a sleep function and 2) a function that makes a noise for each dit-dah in a khar

11:28 that's in the first function

11:29 the second is the same but the sleep function is different and it makes noises for each khar in a word instead of dit-dah in a khar

11:33 mi6x3m: fifosine: I see

11:33 well, I would first start by abstracting the xyz-to-sound function

11:34 because they are quite similar

11:34 fifosine: right, that's what I'm asking for help on

11:35 mi6x3m: fifosine: first, let's see about the states

11:35 word-to-sound has side effects so I think 'read-word!' is more suitable

11:35 or something like that

11:36 then instead of using interpose

11:36 you can just do li

11:37 (doseq [c (charater...)]

11:37 (read-char! c)

11:37 (sleep))

11:37 this would make it a bit more readable

11:37 fifosine: but then there's an added sleep at the end. This is the purpose of the transpose call

11:39 mi6x3m: well you are introducing aritificial complexity right now with all the anonymous functions

11:39 so output the first element separately and then the doseq loop

11:43 fifosine: something like that, for starters

11:43 http://pastebin.com/ciLKD9mh

11:43 fifosine: ok, that makes sense, thanks!

11:44 mi6x3m: fifosine: then you immediately see the pattern for abstraction

11:44 1. the function, read-char!

11:44 2. the delay

11:44 3. the collection, chars

11:45 read-with-delay! f d col

12:02 justin_smith: kqr: hey, have you considered using schema to verify your maps?

12:04 kqr: justin_smith, no! what's that?

12:04 justin_smith: https://github.com/Prismatic/schema

12:04 kqr: it's a lib designed to verify the structure and contents of clojure data

12:04 which sounds perfect for what you are trying to do

12:05 you can use it to annotate functions, giving a name to the structure of data it should take or return

12:06 kqr: that looks amazing

12:09 justin_smith: sure beats a bunch of calls to nil?

12:12 kqr: sure does

13:01 fifosine: ,(doseq [x '((println 1) (println 2))] x)

13:01 clojurebot: nil

13:02 fifosine: why does that not print?

13:02 teslanick: Because it's just a list of symbols.

13:05 llasram: ,(for [x '((println 1) (println 2))] x)

13:05 clojurebot: ((println 1) (println 2))

13:07 fifosine: teslanick, llasram: I'm trying to write a macro that wraps doseq. I have this so far, but as you pointed out teslanick, it just yields a list of symbols.

13:07 (defmacro wrap-doseq [body] `(doseq [~'x '~body] ~'x))

13:08 how do I get it to eval?

13:08 bbloom: fifosine: it seems like you're just using ~ and ' indiscriminately

13:08 justin_smith: fifosine: the point of doseq is that it do something - but the ~'x in the body won't do anything that the expansion of ~body did not do

13:08 bbloom: fifosine: it's worth experimenting with ` without defmacro

13:08 fifosine: bbloom: I might be, I'm using this as an exercise to learn how to use quoting etc

13:08 bbloom: fifosine: forget macros for a moment and play with the quoting operators in your repl

13:09 fifosine: it will let you iterate much faster and you'll probably figure it out on your own

13:09 and also experiment with x# instead of ~'x

13:09 fifosine: What is x#?

13:09 bbloom: fifosine: try it in your repl and it should become clear pretty quickly

13:09 (with quoting)

13:10 fifosine: how do you mean

13:10 bbloom: fifosine: you've got a repl right?

13:10 fifosine: if you could provide a quick example, I'll start experimenting

13:10 yes

13:10 justin_smith: ,`(let [x# 1] x#)

13:10 clojurebot: (clojure.core/let [x__93__auto__ 1] x__93__auto__)

13:10 bbloom: ,x#

13:10 arrdem: does anyone know of a Clojure java.net.URI wrapper which allows for multimethod dispatch on URI type when attempting to slurp? clojure.java.io doesn't provide this and I'm not seeing it with a quick google.

13:10 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: x# in this context, compiling:(NO_SOURCE_PATH:0:0)>

13:10 bbloom: ,'x#

13:10 clojurebot: x#

13:10 bbloom: ,`x#

13:10 clojurebot: x__164__auto__

13:10 bbloom: ,'[x# x#]

13:10 clojurebot: [x# x#]

13:11 bbloom: ,`[x# x#]

13:11 clojurebot: [x__213__auto__ x__213__auto__]

13:11 bbloom: there's like a dozen examples fo ryou

13:11 just type some crap in to the repl and see what happens!

13:11 your computer won't explode, i promise

13:15 fifosine: bbloom: Okay, so I've got the macro working the way I want. It looks like

13:15 (defmacro wrap-doseq [body] `(doseq [x# '~body] (eval x#)))

13:15 but isn't using eval discouraged?

13:15 how do I get around this?

13:15 bbloom: fifosine: quote and eval are (more or less) opposite operations

13:15 llasram: fifosine: What are you actually trying to make the macro even do?

13:15 bbloom: they cancel each other out

13:16 fifosine: so if you've got one too many evals, you might have one too many quotes

13:16 fifosine: llasram: given a list of unevaluated function calls, wrap it in a doseq (as opposed to a do)

13:16 bbloom: fifosine: but in this case, you're generating code that has a loop, rather than using a loop to generate code

13:16 fifosine: bbloom: Yes, that's intended

13:16 llasram: fifosine: "wrap it in a doseq" isn't well-defined

13:17 bbloom: fifosine: i think your intention is wrong then :-P

13:17 justin_smith: also, '(println :x) is a list of a symbol and a keyword, it is not an unevaluated function call

13:17 llasram: fifosine: Are you kind trying to re-implement `do` in terms of `doseq`?

13:18 fifosine: bbloom: actually, you're right, I don't need the doseq to be generated, I could just perform the doseq within the macro

13:18 bbloom: fifosine: and now it's time to experiment with ~@ outside of defmacro

13:18 ,`~@(range 3)

13:18 clojurebot: #<IllegalStateException java.lang.IllegalStateException: splice not in list>

13:18 bbloom: ,`[~@(range 3)]

13:18 clojurebot: [0 1 2]

13:18 bbloom: ,`[~@(range 0)]

13:18 clojurebot: []

13:18 Bronsa: `(~@()) :(

13:18 ,`(~@()) :(

13:18 clojurebot: nil

13:19 bbloom: Bronsa: hmmm

13:19 justin_smith: Bronsa: that last one is like bizarro ascii art

13:19 Bronsa: I should get clojurebot to automatically dec me each time I write clojure code without "," in front of it

13:20 maybe that'll make me remember

13:20 bbloom: Bronsa: if it could detect that, then it might as well just damn evaluate it :-P

13:20 Bronsa: bbloom: http://dev.clojure.org/jira/browse/CLJ-1444

13:20 bbloom: Bronsa: is that not a giant breaking change?

13:21 justin_smith: Bronsa: add a hook to your client inserting , before all your messages to this channel

13:21 :P

13:21 Bronsa: , justin_smith: that might get annoying pretty fast

13:21 clojurebot: #<RuntimeException java.lang.RuntimeException: Invalid token: justin_smith:>

13:21 Bronsa: ^

13:21 justin_smith: yeah :)

13:22 Bronsa: bbloom: maybe, but I think everybody would expect (~@whatever) to always return a list, not nil

13:22 I doubt there's code that depends on that returning nil

13:22 bbloom: Bronsa: by that logic, i doubt there's code that would desire it to return ()

13:22 fifosine: bbloom: I have this now, but it still uses eval

13:22 (defmacro wrap-doseq [body] (doseq [x body] (eval x)))

13:23 Janiczek: Hi, is there a way for Schema to throw an exception when I'm using a schema B instead of schema A, but they are the same under the hood? Example code: https://gist.github.com/Janiczek/e9c74130f18dd17c6d11

13:23 bbloom: fifosine: how come you're still trying to make this work with defmacro? i'm not sure how much clearer i can be about this: get it working without defmacro, using only quoting in your repl

13:24 fifosine: you're confused about both defmacro and quote, so you're definitely not going to understand them both at the same time

13:24 Bronsa: bbloom: find me one guy in this room that knows `(~@x) might return nil (except you and me now) :P

13:24 bbloom: Bronsa: all i'm saying is that i'm sure there's a library somewhere that will break

13:24 :-P

13:24 Bronsa: whether or not you care is another question

13:24 fifosine: bbloom: You're saying, get it working w/out defmacro and without eval, right?

13:24 bbloom: fifosine: i'm saying forget defmacro until you understand quoting

13:26 Bronsa: bbloom: "For Lists/Vectors/Sets/Maps, syntax-quote establishes a template of the corresponding data structure"

13:26 bbloom: the documentation is clear, if a library breaks, it deserves to.

13:27 brb dinner

13:27 bbloom: Bronsa: ok, so you don't care :-P

13:27 fifosine: bbloom: If I understand quoting, should I be able to remove the call to eval in the snippet?

13:28 bbloom: e.g., I still have

13:28 (doseq [x '((println 1) (println 2))] (eval x))

13:28 bbloom: fifosine: if you understand quoting, you'll understand whether or not you need an eval too

13:28 justin_smith: ,(map #(.getScheme (java.net.URI. %)) ["telnet://foo/bar" "file:///twiddle" "http://example.com"]) ; arrdem maybe I misunderstand your question, but why not use #(.getScheme %) as a dispatch for a multimethod?

13:28 clojurebot: ("telnet" "file" "http")

13:29 fifosine: bbloom: Ah, okay, I see what you're saying. Well, it seems like if I ever need code to not be evaluated, I need to quote it so that it's known as a list of symbols. If I later need to take that same list of symbols and then evaluate it as I would expect, I have to use eval.

13:30 justin_smith: fifosine: you can also delay evaluation by constructing a function, and later calling it

13:30 bbloom: fifosine: except that you don't have to evaluate it yourself

13:30 fifosine: i.e. if I quote something and then want it evaluated, I need to use eval

13:30 bbloom: fifosine: a macro takes code in and returns code out

13:30 fifosine: the compiler will ensure that the generated code gets evaluated

13:31 fifosine: hmmm

13:31 bbloom: fifosine: like i said, quote and eval cancel each other out

13:32 fifosine: a macro is quoting something, applying a function to it, then evaluating the result of that function call

13:33 fifosine: bbloom: Given that, I don't think it's possible to write this w/out eval

13:33 arrdem: justin_smith: that's what I want to do... issue is that as implemented clojure.java.io doesn't provide such extensible dispatch. URIs are handled as (slurp (.toURL my-uri))

13:33 bbloom: fifosine: you're wrong

13:33 arrdem: justin_smith: pondering how to package such an extension lib

13:34 bbloom: fifosine: if i give you the answer, you won't get to experience the joyous insight of understanding syntax quote

13:34 fifosine: your goal is to write an expression that returns the right code you want to run, not to actually run the code

13:34 fifosine: ok, don't tell me then, I do want to figure it out I just feel slow

13:35 bbloom: fifosine: go away and play with your repl, you'll get it

13:35 fifosine: bbloom: If what I get from defmacro is a list of lists of symbols already quoted, i.e. '((println 1) (println 2)), and I want to iterate over this list, evaling each element, how can I not use eval

13:36 bbloom: fifosine: why are you still talking about defmacro?

13:37 fifosine: because before, when I assumed not using defmacro, if I wanted to quote things, later I *had* to use eval. as you said, they're "opposite" operations. and then you said "except that you don't have to evaluate it yourself", which I thought was referring to the power of macros

13:37 so then I thought the solution isn't possible w/out them

13:37 but I guess it is

13:38 bbloom: fifosine: you don't have to evaluate it yourself when you use defmacro

13:38 justin_smith: fifosine: he's saying, play with syntax-quote outside macros for a while, see what they really do, then use it inside a macro

13:39 bbloom: which is why i'm advising you to not think about defmacro for a bit, b/c it does some extra operations that make it harder to understand the primitives

13:39 your goal is to generate the right code, not to run it

13:39 if you want to make sure you generated the right code, you can call eval on that

13:39 but my advice, is to do it like this:

13:39 fifosine: then, is there another way of writing this w/out eval and w/out defmacro

13:39 (doseq [x '((println 1) (println 2))] (eval x))

13:39 bbloom: ,'(println 5)

13:39 clojurebot: (println 5)

13:39 fifosine: is that what I'm missing?

13:39 bbloom: ,(eval *1)

13:39 clojurebot: #<Unbound Unbound: #'clojure.core/*1>

13:39 bbloom: oh, well that would work :-P

13:40 use (eval *1) to test code you generate in your repl

13:40 fifosine: I gotcha

13:40 bbloom: at this point i'm going to stop talking b/c really there's only two ways for you get figure this out 1) somebody tells you or 2) you go experiment for a while and you'll understand it much more deeply

13:41 go! have fun

13:41 fifosine: ugh ok

13:41 I'm losing sight of the goal

13:44 Bronsa: bbloom: right, I don't care indeed, but my point is that I don't think anybody should care about libraries that depend on behaviour different than that documented

13:44 about not breaking*

13:44 they depend on a bug and bugs should get fixed

13:45 bbloom: Bronsa: i'm just playing devil's advocate here. personally i don't care one way or another, but if you're the only person who has ever noticed, then it's not worth risking any breaking change at all

13:45 Bronsa: potentially, anyway

13:46 Bronsa: it'd be one thing if no code could break and new code was possible, but somebody might depend on the falseness of that, and you say you don't care, but somebody might be scratching their heads for 3 friggin days after upgrading clojure

13:46 Bronsa: bbloom: that's what changelogs are for :P

13:46 bbloom: Bronsa: you gotta weigh cost & benefit

13:46 cost is potential head scratching & broken lib w/ an absent maintainer

13:46 and benefit is what exactly?

13:47 it matches the "spec" which is a one liner on a page nobody reads?

13:47 don't get me wrong, i think it probably should return empty list

13:47 Bronsa: bbloom: yeah, I understand what you're saying

13:47 bbloom: and i'd be totally fine if your patch got accepted

13:47 but then again i'm not a clojure maintainer

13:48 Bronsa: it's just it makes me feel really bad when edge-cases don't work as they should :P

13:48 bbloom: switching from devil's advocate to being just a plain old joker:

13:48 you should go write a programming language with NO EDGE CASES :-)

13:51 fifosine: bbloom: here's I've been able to write the snippet above w/out eval and w/out defmacro

13:51 (doseq [x '((println 1) (println 2))] (apply (resolve (first x)) (rest x)))

13:51 ,(doseq [x '((println 1) (println 2))] (apply (resolve (first x)) (rest x)))

13:51 clojurebot: 1\n2\n

13:52 bbloom: fifosine: lol well i gotta give you credit, that's creative

13:52 fifosine: ugh, not what you were thinking?

13:52 Bronsa: fifosine: resolve falls into the same category as eval

13:52 fifosine: aargggggg

13:52 Bronsa: somewhat

13:52 bbloom: fifosine: you're still running the code, rather than returning the code that you want to run...

13:53 ,(let [x 5] `(* ~x ~x))

13:53 clojurebot: (clojure.core/* 5 5)

13:53 bbloom: ,(let [x 5] (eval `(* ~x ~x)))

13:53 clojurebot: 25

13:53 bbloom: fifosine: do you understand the difference between those two?

13:54 fifosine: yes, the first is returning a list of symbols, the second is evaluating that list

13:54 bbloom: ,(let [form '(prn 1)] (eval `(do ~form ~form))) ; do you understand why this prints two ones?

13:54 clojurebot: 1\n1\n

13:54 bbloom: can you write an expression that returns (do (clojure.core/println 1) (clojure.core/println 2)) ?

13:54 fifosine: yes, ~form turns into (prn 1), then (do (prn 1) (prn 1)) is eval'd

13:55 bbloom: (eval (doseq [x '((println 1) (println 2))] (apply (resolve (first x)) (rest x)))) ; this is what a macro is going to do to your code

13:55 ,(eval (doseq [x '((println 1) (println 2))] (apply (resolve (first x)) (rest x)))) ; this is what a macro is going to do to your code

13:55 clojurebot: 1\n2\n

13:55 bbloom: that *looks* like it works, but it's not quite right

13:56 ,(def foo (doseq [x '((println 1) (println 2))] (apply (resolve (first x)) (rest x)))) ; let's defer evaluation

13:56 clojurebot: 1\n2\n#'sandbox/foo

13:56 bbloom: ^^ whoops! it evaluated

13:56 ,(eval foo)

13:56 clojurebot: nil

13:56 bbloom: fifosine: your goal is to produce code which will evaluate correctly, not to evaluate it yourself

13:57 fifosine: experiment with ` and ~@ and replace your doseq with a for

13:57 fifosine: is for preferrable?

13:58 ,(let [x '((println 1) (println 2))] `(do ~@x))

13:58 clojurebot: (do (println 1) (println 2))

13:58 bbloom: fifosine: it's different

13:59 fifosine: the reason you're avoiding doseq or avoiding eval is not that there's something wrong with either of them... it's that they don't do what you need them to do....

13:59 but you should experiment with for and doseq and see how they differ

13:59 look at their source code

13:59 use eval to understand eval

13:59 and to understand quote

14:00 fifosine: bbloom: Will I use for to generate code that uses doseq? Or do you suggest replacing doseq with for

14:00 Rhainur: so I'm a Ruby on Rails dev who's trying to learn Clojure, and I'm having a hard time adjusting to freedom :P Specifically Rails was very heavy on convention, and when I'm developing using Luminus I don't really know where to place my code :(

14:00 any guides that I can read with regards to this?

14:01 bbloom: fifosine: can you explain the difference between doseq and for?

14:01 Bronsa: https://github.com/clojure/tools.reader/commit/98d04ddce7152f69ac741ec783d0ce577075aef8 I feel kinda better now

14:01 fifosine: for will return a list

14:01 doseq returns nil

14:01 bbloom: fifosine: and?

14:01 fifosine: more specifically, the list returned by for is the concatenation of the results of apply the body to each element in the specified list

14:02 bbloom: fifosine: doseq also supports concatenating nested loops

14:02 ,(doseq [m "abc" n "xyz"] [m n])

14:02 clojurebot: nil

14:02 bbloom: ,(doseq [m "abc" n "xyz"] (println [m n]))

14:02 clojurebot: [a x]\n[a y]\n[a z]\n[b x]\n[b y]\n[b z]\n[c x]\n[c y]\n[c z]\n

14:03 bbloom: (doc doseq)

14:03 clojurebot: "([seq-exprs & body]); Repeatedly executes body (presumably for side-effects) with bindings and filtering as provided by \"for\". Does not retain the head of the sequence. Returns nil."

14:03 fifosine: oh ok, like a cartesian product? I didn't know that

14:03 bbloom: note the parenthetical:

14:03 "presumably for side-effects"

14:03 fifosine: to be clear, I'm assuming side-effecful functions

14:03 part of the reason why i've been using println

14:04 bbloom: fifosine: if you are writing a macro, your goal is NOT TO RUN THE CODE

14:04 your goal is to return the code that you want to run

14:04 Shoop: quick question is there any simpler way to write (for [a seq b seq c seq d seq.........] [a b c d.....])

14:04 bbloom: fifosine: macros should not have side effects! although the code generated by the macro may have side effects

14:04 justin_smith: (doc interpose) ; Shoop

14:04 clojurebot: "([sep coll]); Returns a lazy seq of the elements of coll separated by sep"

14:05 bbloom: justin_smith: that's not what Shoop wants

14:05 fifosine: bbloom: The question I need to answer is, what code do I want to be generated w/out using eval

14:05 justin_smith: Shoop: oh wait, that's for, never mind

14:05 Bronsa: Shoop: do you care about the combination order?

14:05 Shoop: Bronsa: not really

14:05 fifosine: bbloom: and w/out using resolve, I guess

14:06 Bronsa: Shoop: then there's `cartesian-product` in math.combinatorics that does exactly that

14:06 bbloom: fifosine: sorry man, but i kinda give up....

14:06 Bronsa: Shoop: https://github.com/clojure/math.combinatorics

14:06 Shoop: Bronsa: thanks :D

14:07 bbloom: ,`(do ~@(for [x '((println 1) (println 2))] x)))

14:07 clojurebot: (do (println 1) (println 2))

14:07 fifosine: bbloom: I already have (defmacro wrap-do [body] `(do ~@body))

14:07 I thought that writing it in terms of doseq might be enlightening

14:07 bbloom: fifosine: i have no idea what you're talking about

14:08 alexyakushev: Hi, quick question. Why the following exception slips through catch: (try (map str 'foo) (catch Exception ex "failed"))

14:08 Bronsa: fifosine: I suggest you read (or re-read) an introductory clojure book or a documentation series before trying to do what you're doing. You clearly haven't understood yet how evaluation & macros work

14:08 fifosine: bbloom: What I mean to say is, maybe my aim was fruitless. I thought that writing a macro which took a list of function calls, and evaluated the list using doseq as opposed to using do (as above) would be interesting.

14:08 but I guess it's not

14:09 alexyakushev: I mean, I know it's probably because of the laziness, but what the hell

14:09 Bronsa: alexyakushev: yes, it's because of map being lazy

14:10 fifosine: bbloom: sorry to have wasted your time, but thanks for sticking with me for as long as you did

14:11 Bronsa: alexyakushev: the only way to make that work is to force the evaluation of map inside the try, with a doall

14:14 alexyakushev: Bronsa: yeap, that's what I thought

14:14 Seems awfully surprising and confusing to me

14:16 Bronsa: alexyakushev: there's no other way to do it and preserve the lazyness of map

14:19 alexyakushev: Bronsa: why the try-catch context cannot be enclosed the same way the closed variables are?

14:22 It doesn't feel good to know that the only Clojure's error handling system will let you down as soon as you call a single sequence-operating function

14:22 Bronsa: alexyakushev: locals have lexical extent, try-catch blocks have dynamic extent, it's not the same thing

14:23 dbasch: alexyakushev: what do you mean by let you down? It fails when it’s supposed to

14:23 alexyakushev: it’s the same thing as saying “why does the compiler let me compile code that will fail at runtime?”

14:24 Bronsa: alexyakushev: it doesn't let you down. if you're using map you should be aware of its lazyness and of the behaviour it implies

14:25 alexyakushev: dbasch: No, it's not the same. What is the point of an exception that I can't catch? It could just segfault with the same outcome

14:25 Bronsa: alexyakushev: it's the same for dynamic vars, really, the only difference is that vars being implemented by clojure and not in the jvm, can be "captured" manually

14:26 alexyakushev: you can catch that exception. you just need to realize the lazy sequence inside the try block instead of outside

14:26 dbasch: alexyakushev: you can catch it

14:26 Bronsa: ,(try (doall (map str 'foo)) (catch Exception _))

14:26 clojurebot: Bronsa: Huh?

14:26 alexyakushev: Bronsa: point is, everyone's using map. So far the only implied behavior to care about for lazyness were side-effects

14:26 Bronsa: clojurebot: what.

14:26 clojurebot: Pardon?

14:26 alexyakushev: Bronsa: Clojail is trained to act dumb when it sees a "catch"

14:27 dbasch: ,(try (first (map str 'foo)) (catch Exception ex "failed"))

14:27 clojurebot: dbasch: Titim gan éirí ort.

14:27 alexyakushev: safety reasons I guess

14:27 Bronsa: alexyakushev: clojurebot doesn't use clojail

14:27 dbasch: &(try (first (map str 'foo)) (catch Exception ex "failed"))

14:27 lazybot: java.lang.SecurityException: You tripped the alarm! catch is bad!

14:27 alexyakushev: OK, then whatever else it uses

14:27 Bronsa: alexyakushev: exceptions are not side-effects?

14:28 alexyakushev: Bronsa: I don't see a reason why they should be

14:29 Bronsa: alexyakushev: it's a side-effect that acts on the state of the program

14:30 alexyakushev: Bronsa: in which way?

14:30 Bronsa: alexyakushev: anyway, lazyness is not only about side-effects, it's about delayed evaluation

14:31 alexyakushev: Overall, I wonder what was the point of doing lazy evaluation the default one if a lot of other concepts of the language don't work well with it

14:31 "doall your lazy collections to trigger side-effects"

14:31 "Don't use dynamic binding with lazy collections"

14:31 Bronsa: lazy evaluation is not the default evaluation strategy

14:32 alexyakushev: Now it's "doall your lazy collections to handle exceptions properly"

14:32 Bronsa: clojure is a strictly evaluated language

14:32 alexyakushev: I don't argue, except that almost all sequence processing library is lazy

14:33 I'm trying to find a reason why should I care whether my collections is lazy or not when I want to catch an exception

14:34 Bronsa: alexyakushev: the evaluation of a lazy collection doesn't imply its realization

14:34 ,(def a (map str 'foo))

14:34 clojurebot: #'sandbox/a

14:34 Bronsa: you can't catch the exception caused by evaluation that sequence, if you don't realize it

14:35 xeqi: ,a

14:35 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol>

14:35 Bronsa: until you realize a lazy sequence, it's just a box with the recipe for building itself

14:36 alexyakushev: Nicola, you are saying everything correctly from the implementation standpoint

14:36 Bronsa: alexyakushev: if you want to make sure (map f y=[x ..]) succeds assuming that (f x) returns a correct value, you need to validate y

14:37 e.g. (assert (seq y))

14:37 alexyakushev: But it doesn't answer the question why can't I have an error handling mechanism that lets me not care whether my collection is lazy or not

14:38 Or not a collection at all

14:38 justin_smith: alexyakushev: do proper validation. the schema library can help there. or you may find yourself happier using a statically typed language. but clojure simply isn't one.

14:40 alexyakushev: justin_smith: well, actually I use Clojure exactly for the reason that I don't have to put static types everywhere. I don't want that code to fail during compilation (like it would in statically typed language), I don't want it to fail at all

14:41 xeqi: alexyakushev: what would try/catch do when half the sequence would evaluate successfully?

14:42 Bronsa: xeqi: he's expecting the try-catch block to be "captured" by the lazy-seq, and its evaluation be done using that try-catch context

14:43 which is not something that's really possible on the JVM

14:44 alexyakushev: Bronsa: That's what I "expected", that is right

14:44 I'm not saying that's what I really want

14:44 Bronsa: you'd have to reify every try-catch block and somewhat attach it to its body

14:44 alexyakushev: I understand that implementing this requires special handling in the compiler, and besides you say it is not at all possible

14:45 But then it means that the current error handling system cannot work well with other primary language concepts (like laziness)

14:46 Bronsa: alexyakushev: right, that's a tradeoff you're supposed to be making when using lazy sequences

14:47 features that have a dynamic extent like dynamic vars and exception handling don't know how to interact with lazyness

14:47 justin_smith: let's remember that with (map str 'foo) the argument isn't even valid - you can use schema validation to catch the error without needing to do anything fancy with try/catch here

14:49 alexyakushev: justin_smith: Thank you for trying to put me on the right path, but this is half-artificial example and in my case I actually need the try/catch

14:50 Bronsa: alexyakushev: (map f x) might fail for two reasons: either x is not seqable or (f y) fails with y an element of x

14:51 alexyakushev: to avoid the first occurrence, rewrite f as #(try (f %) (catch Exception _ ..))

14:51 to avoid the second, validate x before calling map over it

14:51 that might involve realizing all, or some part of x, clojure can't do that automatically for you

14:51 bbloom: Bronsa: i've got a compiler question for you

14:52 Bronsa: if i return a closure from a method, will that closure keep any pointers to the containing instance?

14:52 Bronsa: that is (deftype T [foo] SomeProtocol (someMethod [this] (fn [x] foo))) ; will this be captured at all?

14:53 Bronsa: bbloom: yes if you're using a field of that instance

14:53 bbloom: Bronsa: argh. what if i copy it to a local?

14:55 Bronsa: bbloom: nvm, sorry, it only captures the value

14:55 bbloom: Bronsa: you sure? :-)

14:56 Bronsa: it will capture the instance if you use (.-foo this) rather than foo

14:56 bbloom: Bronsa: ok that makes sense

14:56 thanks

14:56 Shoop: I am new to clojure coming from an imperative programming background. Can someone help me translate a simple python function into clojure?

14:56 http://pastebin.com/ezD3bCgv

14:57 alexyakushev: Bronsa: btw speaking of doall, too bad it will help only if you control the sequence generation https://www.refheap.com/89629

14:57 gfredericks: Shoop: depends on how direct you want; lines 13 and 16 aren't very idiomatic, since they're linear time

14:58 Bronsa: alexyakushev: yeah, doall isn't recursive

14:58 it only forces the sequence you give it, not the subsequences

14:58 Shoop: gfredericks: i was looking for something more functional

14:58 gfredericks: i tried doing it with recurse but i was having trouble

14:58 *recursion

14:59 gfredericks: Shoop: clojure style usually involves higher level operations on collections when possible

14:59 Shoop: in this case clojure.core/frequencies is an interesting way to get a lot of the logic you have

14:59 ,(def list1 [1 2 3])

14:59 clojurebot: #'sandbox/list1

14:59 gfredericks: ,(def list2 [3 3 4 5])

14:59 clojurebot: #'sandbox/list2

14:59 gfredericks: ,(frequencies list1)

14:59 clojurebot: {1 1, 2 1, 3 1}

15:00 gfredericks: ,(frequencies list2)

15:00 clojurebot: {3 2, 4 1, 5 1}

15:00 Shoop: oh and then you could zip them and work from there

15:00 gfredericks: sorta yeah

15:00 I would just iterate through the first one and use the second one at each point

15:00 Shoop: ok

15:00 ill mess around with that

15:00 thanks

15:00 gfredericks: np

15:01 also look at map, filter, reduce...

15:01 which work with maps as well

15:01 Bronsa: bbloom: I just checked the bytecode to make sure, I can confirm what I said

15:01 alexyakushev: Bronsa: Yup. So it appears that Clojure pushes laziness down your throat without having the proper infrastructure to deal with its nuances

15:01 Shoop: ok :D

15:01 bbloom: Bronsa: awesome, thank you

15:01 Bronsa: working on some fiddly external resource management/cleanup nonsense

15:02 alexyakushev: Which probably means that you have to explicitly doall every place you call map/filter/remove if you know you don't need laziness there

15:02 Bronsa: alexyakushev: if you don't need lazyness, don't use it

15:03 alexyakushev: I use mapv instead of map when I don't need lazyness

15:03 now that transducers are a thing, I'll probably use those

15:03 gfredericks: clojurebot: transducers |are| a thing

15:03 clojurebot: Ok.

15:04 alexyakushev: Bronsa: now that's better. What about filter, can I easily replace it?

15:04 gfredericks: ,(doc filterv)

15:04 clojurebot: "([pred coll]); Returns a vector of the items in coll for which (pred item) returns true. pred must be free of side-effects."

15:04 alexyakushev: OK, great

15:05 Two words that could save me an hour of ranting and wasting everyone's time:)

15:05 Bronsa: alexyakushev: you can use filterv

15:05 (inc gfredericks)

15:05 lazybot: ⇒ 86

15:05 justin_smith: Shoop: https://www.refheap.com/89630 my imperfect version of example (returns the right results, code could be better)

15:05 Bronsa: alexyakushev: or, with transducers, use the filter transducer :)

15:06 alexyakushev: you never said you didn't need the lazyness

15:06 if you did, I'm sorry I missed that

15:06 alexyakushev: Bronsa: yeah, but I suspect it will take a while before 1.7 will become the oldest supported Clojure version

15:06 justin_smith: alexyakushev: I don't doubt that people use laziness in clojure without thinking about it, but it is not forced on you - my above function, coincidentially, has no lazy values in it

15:07 alexyakushev: Or will transducers be somehow backported into 1.5/1.6 (via a library of sorts)?

15:07 Bronsa: alexyakushev: I doubt they will

15:08 alexyakushev: Bronsa: I might have forgot to say that I don't need laziness in this particular example. But regardless, the map/filter are the functions that you read about in all books, and everyone uses them rather than mapv/filterv

15:08 Bronsa: ,(:added (meta #'mapv))

15:08 clojurebot: "1.4"

15:08 Bronsa: alexyakushev: I'll be surprised if books covering clojure >=1.4.0 didn't mention them

15:08 alexyakushev: I meant transducers when I talked about versions

15:09 They do, I knew about mapv

15:09 gfredericks: alexyakushev: I missed what your main issue with laziness is; something about error handling?

15:09 alexyakushev: But I thought of it more like "map for vectors"

15:09 Rather than "non-lazy map"

15:10 justin_smith: gfredericks: the realizing of the lazy sequence can escape a try/catch, and thus not be caught as expected

15:10 Shoop: thanks justin_smith, looks good. im going to try a version using frequencies as well

15:10 gfredericks: yeah I guess that is kind of unfortunate

15:10 you can't write generic error handling code

15:10 justin_smith: Shoop: the definition of checkout there is a bit verbose - I opted for clarity over conciseness there

15:11 gfredericks: alexyakushev: I think it takes a bit of concentration wrt the boundaries of your functional vs imperative code

15:11 the error handling lives in the imperative part, and you stop using laziness somewhere around the boundary

15:11 alexyakushev: gfredericks: I'm used to that, just didn't think about error-handling as imperative before

15:11 Bronsa: btw c.c/iteration is awesome

15:12 gfredericks: alexyakushev: I probably wouldn't have either except that haskell makes you do it in the IO monad :D

15:12 Shoop: justin_smith: well thanks, its very readable :D

15:13 Bronsa: ,(def a (into [] (filter odd?) (map #(doto % println) (range 10))))

15:13 clojurebot: 0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n#'sandbox/a

15:13 Bronsa: ,(def a (into [] (iteration (filter odd?) (map #(doto % println) (range 10)))))

15:13 clojurebot: 0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n#'sandbox/a

15:13 Bronsa: ,(def a (sequence (iteration (filter odd?) (map #(doto % println) (range 10)))))

15:13 clojurebot: 0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n#'sandbox/a

15:14 Bronsa: uhm

15:14 hiredman: ~clojurebot

15:14 clojurebot: clojurebot is in the Clojure IRC channel. Good work.

15:14 hiredman: ~clojurebot

15:14 clojurebot: clojurebot is pretty cool

15:14 hiredman: hmm

15:14 gfredericks: ~hiredman

15:14 clojurebot: hiredman is an evil genius.

15:14 Bronsa: clojurebot is not my repl? :)

15:14 hiredman: I could be here all day looking for the "is not a benchmarking platform" one

15:15 gfredericks: ~not a benchmarking platform

15:15 clojurebot: excusez-moi

15:15 hiredman: ~clojurebot

15:15 clojurebot: clojurebot is a multimap

15:15 hiredman: ~clojurebot

15:15 clojurebot: clojurebot queues for elephants

15:15 justin_smith: clojurebot: benchmark is clojurebot is not a benchmarking platform

15:15 clojurebot: Roger.

15:15 gfredericks: ~benchmark

15:16 clojurebot: criterium or gtfo

15:16 hiredman: justin_smith: you have to wonder, which is did clojurebot take as the assertion there

15:16 justin_smith: ouch

15:16 gfredericks: clojurebot: forget benchmark |is| clojurebot is not a benchmarking platform

15:16 clojurebot: I forgot that benchmark is clojurebot is not a benchmarking platform

15:16 alexyakushev: All right, thank you Bronsa, justin_smith, gfredericks. I will go and rewrite the code now

15:16 hiredman: did it?

15:16 alexyakushev: btw, there is no mapcatv, so meh:(

15:17 gfredericks: alexyakushev: start a library called v

15:17 Bronsa: alexyakushev: AFAIK there are only mapv filterv and removev

15:17 justin_smith: (into [] (mapcat ...))

15:17 Bronsa: no removev.

15:17 gfredericks: In clojure, the only functions are mapv, filterv, and removev. And there is no removev.

15:18 justin_smith: gfredericks: worst esoteric lang ever

15:18 Bronsa: I was pretty sure there were 3 $somethingv functions

15:18 meh.

15:18 alexyakushev: gfredericks: v library — sounds like a plan

15:18 AllThingsV

15:18 gfredericks: ,(->> (ns-publics 'clojure.core) keys (filterv #(re-find #"v$" (name %))))

15:18 clojurebot: [filterv reduce-kv mapv]

15:19 justin_smith: ,(->> (ns-publics 'clojure.core) (map (comp name first)) (filter #(re-matches #".*v$" %)))

15:19 clojurebot: ("filterv" "reduce-kv" "mapv")

15:19 justin_smith: hah, I had the same thought

15:20 gfredericks: mine used filterv though which was more in line with the theme

15:20 justin_smith: heh, good point

15:20 yours was better expressed all around

15:24 Bronsa: uhm

15:24 gfredericks: ,(defn setv "Like set, but returns a vector" [coll] (vec (set coll)))

15:24 clojurebot: #'sandbox/setv

15:25 dnolen_: gfredericks: you tolling? :)

15:25 s/tolling/trolling

15:25 justin_smith: do not ask for whom gfredericks tolls, for he tolls for thee

15:25 gfredericks: dnolen_: no more than usual

15:25 ~gfredericks

15:25 clojurebot: gfredericks is a menace to bots everywhere

15:26 Bronsa: I wonder if (sequence (iteration (filter odd?) (range 10))) is supposed to realize the first element

15:27 alexyakushev: gfredericks: setv goes to the library for sure

15:27 (inc gfredericks)

15:27 lazybot: ⇒ 87

15:27 gfredericks: ,(defn incv "Like inc but returns a vector." [x] [(inc x)])

15:27 clojurebot: #'sandbox/incv

15:28 Bronsa: lol

15:29 philandstuff: strv?

15:29 alexyakushev: lazy-seqv — like lazy-seq but not lazy?

15:29 gfredericks: this library is really shaping up

15:29 listv

15:30 justin_smith: vecv

15:30 gfredericks: nice

15:30 doseqv (always returns empty vector)

15:31 justin_smith: reduce-kvv

15:31 alexyakushev: (defn shutdown-agents "Like shutdown-agents but returns a vector." [] (shutdown-agents) (vector))

15:31 philandstuff: ,(def emptyv (constantly []))

15:31 clojurebot: #'sandbox/emptyv

15:31 Shoop: gfredericks: I think i figured out a way using list comprehensions - (apply + (for [a (frequencies list1), b (frequencies list2) :when (and (= (first a) (first b)) (>= (second a) (second b)))] (second b))))

15:32 gfredericks: Shoop: after calling frequencies you should only have to do one iteration

15:33 justin_smith: Shoop: yeah, that's ignoring the wonderful associative property of a map, but walking it linearly

15:33 Shoop: a little silly

15:33 Shoop: gfredericks: but testing if the item is in list2 is another iteration

15:34 gfredericks: Shoop: it's a map, so you can do a direct lookup

15:34 hiredman: hey, I got JDBC-99, next person to file an issue gets 100

15:34 Shoop: gfredericks: oh yeah

15:34 justin_smith: ,(reduce + (for [x (range 10) y (range 10)] 1)) ; Shoop

15:34 clojurebot: 100

15:34 gfredericks: hiredman: oh snap!

15:34 justin_smith: Shoop: for on two collections does a lot my iterations than you might think :)

15:35 gfredericks: justin_smith: I think s/he knew that part, just didn't know it could be avoided

15:35 justin_smith: Shoop: frequencies returns a map - you can find out if a key is in a map without iterating

15:35 Shoop: justin_smith: its O(n^2) right?

15:35 justin_smith: yeah i realized that

15:35 he

15:36 justin_smith: ,(get (frequencies "hello world") \l)

15:36 clojurebot: 3

15:36 gfredericks: gender discovery protocol complete

15:36 devn: wait... what

15:36 justin_smith: Shoop: I didn't need to walk the map to find that result - it supports directl lookup

15:36 bbloom: com.sun.jna.Pointer .... is friggin mutable!

15:36 * bbloom facepalm

15:36 Shoop: justin_smith: i see, well back to the drawing board

15:37 gfredericks: Shoop: want to see mine?

15:37 Shoop: justin_smith: its implemented as a hashtree right?

15:37 bbloom: it just wraps a long and has a frickin static method com.sun.jna.Pointer.nativeValue(Pointer p, long value) to set it

15:37 * bbloom throws up his hands

15:37 Shoop: gfredericks: give me a try, i want to use my brain

15:37 justin_smith: Shoop: a hashmap, which has a few backing datastructures depending on size

15:38 Shoop: Shoop: I thought it was a tree with a branching factor of 32

15:38 justin_smith: ,(type (frequencies "hello world"))

15:38 clojurebot: clojure.lang.PersistentArrayMap

15:38 gfredericks: I have no idea what the branching factor on the hashmaps is

15:39 Shoop: gfredericks: docs say access is log base 32 n

15:39 so

15:39 gfredericks: where does it say that?

15:39 Clarice: I remember hearing that in a talk some years ago

15:39 It's based on the implementation of tries

15:40 gfredericks: not to be confused with vectors of course

15:40 justin_smith: Shoop: anyway, point is that the datastructure gives us fast lookup, so we should be suspicious if we are walking all the keys unless the point is to do something to every key

15:40 Clarice: Right, but as far as I can tell pretty much all the basic data types are persistent collections implemented as tries, so that should apply to all of them

15:41 gfredericks: well the 32 bit might not

15:41 Clarice: Has anyone tried Clojure on an Azul machine with great success? I think that'd be a good selling point for them: "Look! Clojure runs super fast with real time garbage collection!"

15:42 Shoop: justin_smith: ok let me try again

15:47 gfredericks: the number 32 does appear a few times in PersistentHashMap.java, so I'm just going to assume that's right

15:51 michaniskin: i remember seeing a clojure library for data schema validation, but not the prismatic/schema one. does anyone remember what it's called?

15:53 mynomoto: michaniskin: https://github.com/miner/herbert maybe?

15:53 gfredericks: also flatland/schematic

15:54 michaniskin: mynomoto: i think that's the one! thanks!

15:59 Shoop: ok its not perfect and i can get rid of a bunch of duplicated stuff with let but how is this? (reduce + (for [a (frequencies guess) :when (and (contains? (frequencies code) (first a)) (>= (second a) (get (frequencies code) (first a))))] (get (frequencies code) (first a))))

15:59 oops guess should be list1 and code list2

16:00 (reduce + (for [a (frequencies list1) :when (and (contains? (frequencies list2) (first a)) (>= (second a) (get (frequencies list2) (first a))))] (get (frequencies list2) (first a))))

16:06 justin_smith: Shoop: yeah, a let would help a lot there

16:06 Shoop: but i think its down to O(n) now?

16:07 gfredericks: Shoop: I'm not sure that does the same thing?

16:07 Shoop: justin_smith: also sorry about the variable name mixup, this is part of a bigger project

16:07 gfredericks: your >= filter there seems to be not what you want

16:08 Shoop: gfredericks: how so?

16:08 gfredericks: you want (example [42] [42 42]) to return 1, no?

16:08 Shoop: yes

16:09 gfredericks: but your >= there becomes (>= 1 2)

16:09 ignoring the (first a) at the end which I don't understand at all

16:09 oh wait nm

16:09 Shoop: gfrederickks ah

16:09 i see

16:09 gfredericks: I do understand it but my objection remains :)

16:09 Shoop: so it should be <=?

16:09 gfredericks: Shoop: I used min for this bit of logic instead of a >= chechk

16:10 Shoop: Can i see your version?

16:10 gfredericks: https://www.refheap.com/89635

16:12 Shoop: oh i've never seen ->> before

16:12 thats fancy :D

16:14 gfredericks: btw if you are curious this is for the game http://en.wikipedia.org/wiki/Mastermind_(board_game) if you have ever played it

16:14 gfredericks: I guessed that by your variable names :)

16:17 * gfredericks fails to find his old TI-83+ programs

16:33 TimMc: I wonder if I sitll have my TI-89 stuff.

16:33 That calculator is... 18 years old now?

16:36 gfredericks: I think I transferred them off the calculator once but there's the question of how they're encoded and also where I put the files

16:36 justin_smith: TimMc: I still have a working tandy 102 - nigh indestructible, those are

16:37 gfredericks: I got super excited when I learned Java and discovered I could have more than one letter in my variable names

16:37 tac_: TimMc: and still sold at $100+ to high school students everywhere in the US

16:37 Ven: tac_: and outside of the US, don't worry...

16:37 tac_: despite having less computational power than an arduino

16:43 SagiCZ1: are there any timers in clojure?

16:46 justin_smith: SagiCZ1: there is a Timer class in java you can use with clojure functions via interop

16:47 pretty simple to use, shown here http://stackoverflow.com/questions/16385049/timers-in-clojure

16:49 SagiCZ1: justin_smith: i know that class.. ok thanks

16:58 ycouy: In core.match, is it possible to match on a variadic "middle" of a collection? So in some way ["foo" xs "qux"] would match ["foo" "bar" "baz" "qux"] and bind xs to ["bar" "baz"].

16:59 dnolen_: ycouy: not possible

17:00 ycouy: dnolen_: Do you know of any other language or pattern matching library that does this or something similar?

17:01 dnolen_: ycouy: maybe seqex can do this? https://github.com/jclaggett/seqex

17:02 ycouy: dnolen_: Cool, will look into it. Thanks!

17:15 SagiCZ1: ,(defn foo1 [{x :a y :b]}] (println x y))

17:15 clojurebot: #<RuntimeException java.lang.RuntimeException: Unmatched delimiter: ]>

17:16 SagiCZ1: ,(defn foo1 [{x :a y :b}] (println x y))

17:16 clojurebot: #'sandbox/foo1

17:16 SagiCZ1: (foo1 {:a 5 :b 6})

17:16 ,(foo1 {:a 5 :b 6})

17:16 clojurebot: 5 6\n

17:19 SagiCZ1: ,(defn foo1 [{x :a y :b :as a}] (println x y a))

17:19 clojurebot: #'sandbox/foo1

17:19 SagiCZ1: ,(foo1 {:a 5 :b 6})

17:19 clojurebot: 5 6 {:b 6, :a 5}\n

18:02 lavokad: hi, I don't find a place explaining why we can create a record using -> ?

18:02 llasram: lavokad: Example?

18:04 lavokad: (def algo (->MakeAlgo "lala" "huhu"))

18:05 llasram: lavokad: One thing `defrecord` does is define a var named `->RecordName`, which is a just a function which happens to start with the characters "->"

18:05 It has nothing to do with the `->` macro

18:05 It also defines `map->RecordName`

18:05 lavokad: ohh

18:08 llasram: thanks

18:10 llasram: where can I find this info? In docs nothing about this appears

18:14 all right I found this in the source code :)

18:15 llasram: lavokad: It's mentioned in the last paragraph of the `defrecord` docstring

18:16 gfredericks: ,(-> defrecord meta :doc (clojure.string/split #"\n\n") last)

18:16 clojurebot: #<CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/defrecord, compiling:(NO_SOURCE_PATH:0:0)>

18:17 gfredericks: ,(-> defrecord var meta :doc (clojure.string/split #"\n\n") last)

18:17 clojurebot: " Given (defrecord TypeName ...), two factory functions will be\n defined: ->TypeName, taking positional parameters for the fields,\n and map->TypeName, taking a map of keywords to field values."

18:17 llasram: gfredericks: Nice

18:17 (inc gfredericks)

18:17 lazybot: ⇒ 88

18:24 lavokad: (doc defrecord)

18:24 clojurebot: "([name [& fields] & opts+specs]); (defrecord name [fields*] options* specs*) Currently there are no options. Each spec consists of a protocol or interface name followed by zero or more method bodies: protocol-or-interface-or-Object (methodName [args*] body)* Dynamically generates compiled bytecode for class with the given name, in a package with the same name as the current namespace, the given fields, and, optionall

18:25 gfredericks: I love that the first sentence is "Currently there are no options."

18:26 lavokad: why does the same doc info of defrecord appear on the web?

18:27 gfredericks: why not?

18:28 lavokad: i mean doesnt, sorry

18:28 gfredericks: $google "Currently there are no options"

18:28 lazybot: [ClojureDocs - clojure.core/reify] http://clojuredocs.org/clojure_core/1.2.0/clojure.core/reify

18:28 gfredericks: haha

18:28 justin_smith: "You're viewing version 1.2.0 of reify. The latest stable version of Clojure Core is 1.3.0."

18:28 lol

18:29 lavokad: http://clojuredocs.org/clojure_core/clojure.core/defrecord is not equal to (doc defrecord) output

18:30 justin_smith: lavokad: that's the 1.3 version of the docs

18:30 &*clojure-version*

18:30 lazybot: ⇒ {:major 1, :minor 4, :incremental 0, :qualifier nil}

18:30 justin_smith: ,*clojure-version*

18:30 clojurebot: {:interim true, :major 1, :minor 7, :incremental 0, :qualifier "master"}

18:30 TheMonarc: what are the maiun reasons one might use clojure over other langs?

18:31 lavokad: goshh

18:31 sorry

18:31 thanks

18:31 :)

18:31 justin_smith: lavokad: it's sad that the clojuredocs site has so much google-juice, and is so out of date

18:33 llasram: TheMonarc: My reasons: it runs on the JVM and provides high developer productivity

18:33 gfredericks: TheMonarc: lets you write pure functions on generic data and then use them in real life

18:35 hyPiRion_: Efficient immutable data structures, and powerful functions to manipulate them.

18:36 justin_smith: a stable and predictable runtime that will be identical to your local development environment without needing all sorts of fashionable tooling

18:37 TheMonarc: example of "fashionable tooling" from another stack/lang?

18:38 justin_smith: docker, puppet, chef

18:38 various ways to try to automate the duplication of environments in production, that we typically just have no need for

18:38 TheMonarc: aren't those things orthogonal to language/VM choice

18:39 justin_smith: TheMonarc: I deploy servers that run if you have a jvm of 1.6 or newer

18:39 TheMonarc: BTW, i'm not a java developer either so excuse me if my questions are ignorant

18:39 what if you have project that requires java version X

18:39 and then another project that requires java version Y

18:39 justin_smith: TheMonarc: literally any machine meeting that spec suffices - you don't need much automation to make that work

18:39 TheMonarc: wouldn't someting like docker help w/ that?

18:39 llasram: justin_smith: I take issue with your terminology :-)

18:39 justin_smith: TheMonarc: java version x or newer is a trivial dep

18:40 TheMonarc: but X and Y are different

18:40 wouldn't docker help switch back and forth between an environment where X is met, and one where Y is met?

18:41 justin_smith: TheMonarc: you can use the newer one - it really works that way

18:41 TheMonarc: justin, are you saying that specifically with Clojure

18:41 amalloy: java very very very rarely breaks backwards compatibility

18:41 TheMonarc: or just for Java in general

18:41 llasram: TheMonarc: Yeah, I can't really reflect justin_smith here. In my experience it's about the same as deploying software in other languages

18:41 I do think that the Java/Maven packaging and dependency systems ends up being somewhat better than almost everything else

18:42 But AFAICT packaging is something no-one ever gets completely right :-(

18:43 justin_smith: llasram: we may be trying to do different things. I have never ended up needing a setup more complex than "jvm v. x or newer" *(plus a reverse proxy, which every language needs)

18:43 for a webapp that is

18:44 TheMonarc: any recommendations on a noob to get started with clojure?

18:45 like what should i do once I do "Hello World" in clojure?

18:45 justin_smith: ~books

18:45 clojurebot: books is http://clojurebook.com/ http://joyofclojure.com/

18:46 bounb: TheMonarc: i am a clojure novice working thru clojurebook.com and i recommend it

18:46 justin_smith: TheMonarc: I also like aphyr's clojure from the ground up series http://aphyr.com/posts/301-clojure-from-the-ground-up-welcome

18:46 bounb: it will answer your question "why clojure" at the start too

18:46 devn: out of curiosity, does anyone here use slime still?

18:47 justin_smith: iirc amalloy does

18:47 devn: is it usable anymore?

18:47 amalloy: devn: works fine

18:47 devn: because, and i seriously mean no offense here, i think i preferred it way more

18:47 llasram: justin_smith: Mine isn't that much more complicated, but I find having a version-controlled, executable, repeatable description of the full deployment utterly invaluable

18:47 devn: amalloy: do you by any chance have a gist of the relevant config laying around?

18:47 amalloy: devn: {:plugins [[lein-swank "1.4.5"]]}

18:48 devn: amalloy: yeah, was referring to emacs

18:48 justin_smith: devn: there were some really cool things about slime that I missed. The complaint I seem to remember was that the underlying slime was a fast moving and often breaking target, but I don't see any major improvement on that in cider.

18:48 amalloy: what relevant config?

18:49 justin_smith: lein-swank uses a four-year-old snapshot of slime, works fine. definitely not fast-moving

18:49 devn: amalloy: i remember back in the day having to set a bunch of things up to get everything working

18:50 amalloy: well

18:50 devn: amalloy: what do you have in your emacs config related to slime/swank? and you just mentioned the other question: what packages do you have? do you install slime from marmalade? slime-repl? slime-clj?

18:50 amalloy: you probably have to do some, but not actually that much. i don't really know; i've just copied around the files i installed four years ago

18:50 devn: im just looking for the: "this is the absolute minimum required to jump back to lein-swank" story

18:51 amalloy: lol yeah, that's basically what im asking for -- would you mind gisting what you're using?

18:51 amalloy: devn: clone git@github.com:amalloy/clojure-mode and add it to your load-path, and then (require 'clojure-mode). i think it gets a version of slime from lein-swank

18:52 devn: amalloy: oh, and the more recent version of clojure mode brings in nrepl or cider or something?

18:52 amalloy: maybe

18:52 justin_smith: devn: I think the newer clojure mode is agnostic to the repl integration

18:52 devn: for example I require both clojure-mode and nrepl

18:52 amalloy: (setq clojure-swank-command "lein with-profile +swank jack-in %s") is good too, so that you can have {:swank {:dependencies ...}} in your project.clj

18:52 devn: i have a brand new computer sitting in front of me. i was carrying around emacs config for years and i recently blew it all away

18:53 justin_smith: (I still have not made the cider plunge)

18:53 devn: otherwise i wouldn't bother you

18:53 TheMonarc: oh and tell me about repl

18:53 in a nutshell

18:53 i keep reading people mentioning REPL

18:53 in terms of haskell, scala, and clojure

18:53 devn: TheMonarc: yessir! the repl dude! it's awesome!

18:54 amalloy: devn: you can see my .emacs and .emacs.d at github.com/amalloy/dotfiles, but i don't promise that they're clean and easy to read

18:54 TheMonarc: but what exactly is it

18:54 and why do people rave about it so much

18:54 justin_smith: TheMonarc: clojure is designed such that everything you can do in clojure (with very few exceptions) can be done in the interactive interpreter (the repl)

18:54 devn: TheMonarc: REPL stands for Read Eval Print Loop.

18:54 amalloy: between that, my clojure-mode, and .lein/profiles.clj, that's all i *know* i have set up. there may be some old packages lying around, and if so sorry

18:54 devn: amalloy: thanks

18:54 TheMonarc: ok so kind of like the scheme interpreter we used in school

18:54 Dr. Scheme

18:54 devn: amalloy: that's no problem. thanks much

18:54 justin_smith: TheMonarc: right, that is also a repl

18:55 devn: TheMonarc: yeah, so im going to attempt to convey what i believe to be the "right" way to develop clojure

18:55 but some people don't do this

18:55 justin_smith: but clojure's repl is technically not an interpreter, it compiles code as it goes

18:55 TheMonarc: k, i'm all ears

18:55 devn: TheMonarc: let's say you're in your editor, and you're in a file: src/hello_world/core.clj

18:56 amalloy: justin_smith: IMO that's an implementation details: as far as a user can observe, it's an interpreter

18:56 devn: so inside of there you have (ns hello-world.core (:require [clojure.string :as str]))

18:56 and you have (defn hello [name] (println (format "Hello, %s" name)))

18:56 you "connect" or "jack in" to your project

18:57 and then you can evaluate (and re-evaluate) chunks inside of that file

18:57 so first you might want to evaluate the ns declaration at the top. so you do that, and it returns nil. cool. then you evaluate your hello function

18:57 but it turns out you didn't quite like it, so you change some stuff inside of it, and evaluate it again from your editor

18:58 TheMonarc: ok that sounds pretty cool

18:58 devn: it's very playgroundish

18:58 TheMonarc: one more question for now

18:58 any IDE's or editors recommended for use with Clojure?

18:58 devn: ive seen people doing clojure who dont really use the REPL to their advantage

18:58 instead they run the whole program every time

18:59 justin_smith: my development is more directly repl-centric, where I experiment with code in the user ns in the repl until I have the basic structure, then adapt that into my individual namespace

18:59 devn: that's backwards in clojure IMO

18:59 bounb: devn: how does one 'connect' or 'jack in'

18:59 devn: bounb: what editor are you using?

18:59 bounb: vim

18:59 TheMonarc: devn, is there an article that describes how you use the REPL?

18:59 squidz: devn: clojure or clojurescript?

18:59 justin_smith: bounb: you can use fireplace for connecting vim to a repl

18:59 devn: TheMonarc: no, but i could show you if you want to do a google hangout

18:59 squidz: clojure

19:00 TheMonarc: i'd like to get back to it and make sure i'm getting the most out of the REPL once i get through some hello world and other basic/intro stuff

19:00 bounb: justin_smith: nice, thx

19:00 TheMonarc: @devn, ah, i'm not at the point where i'm ready to do that yet

19:00 devn: clojurescript is harder

19:00 but you can stil use the REPL

19:00 bounb: https://github.com/tpope/vim-fireplace

19:00 bounb: tpope ✓

19:00 amalloy: TheMonarc: whatever editor you're using probably has reasonable clojure support. but you might just do the primitive copy/paste from your editor to your repl for a while; it's not critical to get editor support set up until you're familiar with the language and a repl

19:00 devn: "There's a REPL in fireplace, but you probably wouldn't have noticed if I hadn't told you. Such is the way with fireplace.vim. By the way, this plugin is for Clojure.

19:00 :)

19:00 justin_smith: TheMonarc: also, regarding your "what are good reasons to use clojure" survey question, now I am wondering what the bad reasons to use clojure are.

19:00 bounb: devn: thx

19:01 TheMonarc: because hipster

19:01 bounb: not at all

19:01 TheMonarc: what is your programming backgroun

19:01 d

19:02 TheMonarc: or do you mean what are the bad use cases for Clojure?

19:02 devn: lighttable has a really great setup by default

19:02 you should try it out

19:02 TheMonarc: i code in C#

19:02 i hate my current job

19:02 devn: TheMonarc: lol. it's going to be ok!

19:02 you're here. that's all that matters. :)

19:02 TheMonarc: hahah

19:02 yeah planning on branching out with various langs

19:03 right now exploring scala and clojure

19:03 devn: clojure is a good train to get on. scala is...

19:03 scala is...

19:03 TheMonarc: i figure i will touch on the JVM langs all together

19:03 devn: poorly designed.

19:03 bounb: it's not directly about clojure and the question "why clojure" is answered more succinctly in clojurebook.com but i think everyone (TheMonarc) should watch this great talk http://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey

19:03 devn: amen bounb

19:03 bounb: just watched it earlier and was pretty blown away

19:03 TheMonarc: thanks for that recommendation

19:03 adding it to my list

19:03 devn: that is THE talk. everyone needs to watch that talk. i think i watched it a dozen times when i first started getting into clojure

19:04 TheMonarc: spending this entire weekend watching programming vids and doing tutorials

19:04 devn: seriously TheMonarc -- sit down and watch it. it explains a lot of the Why?

19:04 bounb: <- starting to get into clojure ;)

19:04 yeah it's one of the best programming talks ive seen tbh, very... philosophically complete

19:05 devn: Rich's talks are all fantastic. The one post I ever wrote for the changelog: http://thechangelog.com/rich-hickeys-greatest-hits/

19:05 turned out to be the hottest post of the year and then i never wrote another

19:05 im a terrible blogger.

19:05 TheMonarc: me too

19:05 bounb: haha nice yeah i saw this list earlier ill check out the rest!

19:05 TheMonarc: i have more blog entries in my drafts folder

19:05 than i have actual publish posts

19:06 do you guys use clojure at work?

19:06 devn: yes

19:06 TheMonarc: one of the reasons i'm gravitating towards clojure/scala

19:07 and correct me if this impression si wrong

19:07 devn: almost 100% clojure, maybe 2% nodejs and ruby which will be rewritten soonish

19:07 TheMonarc: but ideally i'd get a job where those langs are being used in production apps

19:07 and i feel like the caliber of developer working with those langs

19:07 is going to be much higher than the C# dev's i interact with every day

19:07 (there are some really good C# developers out there, but none of them are in the network of people i come across in my day job)

19:07 devn: TheMonarc: i know that i dont need to say it, but the following is just my opinion: dont waste your time with scala

19:08 scala is a terrible language IMO

19:08 TheMonarc: haha

19:08 well for now i'm at least going to expose myself to it

19:08 i want to keep an open mind

19:08 devn: yeah, totaly fair

19:08 Wild_Cat: TheMonarc: it's kind of the same reasoning as that behind choosing to work in Python. In many cases, it's true

19:08 (although with Python it's becoming less so these days as it enters the mainstream)

19:09 devn: i dont know a ton about scala, but i know plenty to know that there's no way i'd ever want to seriously work with

19:09 TheMonarc: wait so what's so bad about scala?

19:09 devn: haha, oh gosh

19:09 Wild_Cat: because nobody just knows Clojure because it's what they learned at uni and/or their first job and couldn't be bothered to try something else

19:09 TheMonarc: even when i went onto #scala, i asked people if they used it at work and one guy went off on a rant about how much scala was an "illusion"

19:09 Wild_Cat: (whereas you just have to kick a trash can a couple times and J2EE/PHP developers fall out)

19:10 TheMonarc: which was ironic given that i was in the #scala channel

19:10 devn: TheMonarc: here's an example of the crazy shit they've done... i was talking with a JVM developer who told me that Scala's implementation of Value Classes causes 6^9 class files to be generated

19:10 and that the reason why SBT (build tool) is so slow is because of I/O

19:10 TheMonarc: wow

19:10 Wild_Cat: o.O

19:11 bounb: lol...

19:11 devn: and worse

19:11 their value class implementation still doesn't really solve the deeper problem on the JVM

19:11 it doesn't really add them

19:11 it's like a thin veneer of value classes

19:12 but anyway, more evidence that scala is a bummer: gah, trying to find the video

19:13 basically one of the co-founders of typesafe and a massive contributor to Scala. like 900+ closed issues. 500 issues filed.

19:13 Wild_Cat: the damning evidence against Scala is that I've heard *Haskell* developers complain that Scala's type system is scary.

19:13 devn: decided that scala is horribly broken

19:13 and he left typesafe

19:13 bounb: u guys fans of haskell?

19:14 ive started learning it... a few times haha

19:14 devn: sure, im a fan. there's tons to learn in haskell land.

19:14 i find the clojure crew a much more pragmatic bunch

19:14 TheMonarc: any of you tried F#?

19:15 devn: i also find the people in the clojure community to be a lot more helpful, friendly, nice overall, less prone to pissing contests

19:15 Wild_Cat: bounb: it's a fantastically elegant language, with tons of excellent ideas. No language I've ever touched has changed the way I think about programming in general as Haskell.

19:15 bounb: :)

19:15 Wild_Cat: nonetheless, I've never used it in a real project and probably never will.

19:15 bounb: i see yeah

19:15 TheMonarc: the guy that writes the Clojure Gazette worked in haskell for a couple of years

19:15 Wild_Cat: I find Clojure far more pragmatic, and on the "smart type system" side of the spectrum it's actually Rust I want to learn.

19:15 devn: yeah, same her

19:16 here*

19:16 TheMonarc: he didn't seem that thrilled by using Haskell

19:16 Wild_Cat: (as for my day job, Python all day every day with some C++ here and there)

19:16 devn: devops?

19:16 bounb: python is where i'm comfortable but it's boring

19:16 Wild_Cat: devn: no, backend for game development.

19:17 devn: python is a decent language. i like python. the `python -c "import this"` Zen of Python matches pretty well with Clojure's general philosophy

19:17 TheMonarc: do you have any personal strategies for learning new langs

19:17 Wild_Cat: (previously casual Facebook games in the 500K DAU range, now AAA)

19:17 TheMonarc: like do you just work on it when you get a chance and depend on your personal drive to get you to do it

19:17 amalloy: TheMonarc: one i've heard recommended is to have a "pet project", which you implement in each new language you want to learn

19:17 devn: TheMonarc: yeah, id do some problems on project euler and 4clojure

19:17 TheMonarc: or do you force yourself to work a certain # of hours per day or week or whatever

19:17 Wild_Cat: TheMonarc: find something you want to do, and implement it in the language you want to learn rather than in the one you know.

19:17 amalloy: then you're familiar with the problem space enough that you can focus on what's new about the language

19:18 TheMonarc: amalloy, interesting, i've been thinking of doing exactly that

19:18 Wild_Cat: even better if you can do it at work, but don't go too exotic in that case. People will hate you when they need to maintain your app written in Coq.

19:18 TheMonarc: in my head i call it my "Rosetta Stone Project"

19:18 that i would implement in each lang

19:18 devn: but also what Wild_Cat said -- after you do a couple of basic things, pick something that's more like a project

19:18 TheMonarc: wild_cat, lol, yeah

19:18 devn: like writing an IRC bot or building a static site generator or a blog or something

19:18 TheMonarc: i know better than to burden coworkers with exotic stuff

19:19 devn: TheMonarc: i dont want to tell you i know for a fact what you're going through, but i was in what sounds like a similar position about 7 years ago

19:19 Wild_Cat: for example, the current micro-project I'm working on at work is something I'm currently writing in Python with Gevent and Pyramid (and Redis, which makes me learn more Redis and Redis is awesome), but I'll probably try a Rust rewrite at some point.

19:19 devn: i finally just quit with no plans

19:19 amalloy: TheMonarc: when i was still newish to clojure, i was working in php; i found it useful to sketch out in clojure the new stuff i needed to write in php, because the repl speeds things up so much. it probably helped me learn both languages

19:19 Wild_Cat: (e.g. if performance becomes a true issue, which I doubt it will)

19:20 TheMonarc: so i'll just need to decide on a project

19:20 devn: amalloy: yeah, that's a good point. i was doing a lot of ruby around the time i picked up clojure. i found that building up a table of | clojure function | ruby method | was helpful

19:20 Wild_Cat: also, I find DBs are as important to learn as languages.

19:21 devn: i also found that it made my ruby code a lot better

19:21 Wild_Cat: learn Mongo, learn Redis, learn a SQL database.

19:21 TheMonarc: yup

19:21 i have a big ass list of stuff to learn

19:21 devn: booooo mongo :D

19:21 TheMonarc: rabbitmq is high up there

19:21 devn: postgres, rabbitmq

19:21 amalloy: TheMonarc: you could write a scheme interpreter. it's small enough, and i think you said you learned scheme at school

19:21 TheMonarc: i want to introduce it at work, which is stupid because we already have it one one project at work

19:21 amalloy: but of course if that doesn't interest you, do something else

19:21 TheMonarc: but the douchebag architect hides it from everyone

19:22 literally, won't let anyone use it, so it's just sitting there being used by a single process, which kind of defeats the point

19:22 devn: TheMonarc: one thing i found really interesting when i came to clojure was metadata, and there are some fun exploratory projects you can do there

19:22 gfredericks: clojurebot: rabbitmq is hidden from everyone by the douchebag architect

19:22 clojurebot: In Ordnung

19:22 devn: ,(map (comp meta second) (ns-publics 'clojure.core))

19:22 clojurebot: ({:ns #<Namespace clojure.core>, :name primitives-classnames, :file "clojure/core_print.clj", :column 1, :line 315} {:added "1.0", :ns #<Namespace clojure.core>, :name +', :file "clojure/core.clj", :inline-arities #<core$_GT_1_QMARK_ clojure.core$_GT_1_QMARK_@180023a>, ...} {:ns #<Namespace clojure.core>, :name decimal?, :added "1.0", :file "clojure/core.clj", :static true, ...} {:ns #<Namespace c...

19:22 Wild_Cat: devn: I really don't get the Mongo hate. It works.

19:23 devn: Wild_Cat: for small problems, yes

19:23 Wild_Cat: heck, I could spew way more hate on MySQL than on Mongo, because I've had real bad issues with the former.

19:23 TheMonarc: i prototyped a project in mongo

19:23 p_l: Wild_Cat: Well... you're comparing similar quality there

19:23 TheMonarc: and it was pretty easy and nice to use

19:23 Wild_Cat: devn: my previous company's biggest game uses Mongo and it's a breeze.

19:23 TheMonarc: but any documentDB would have been just as good in my case

19:24 p_l: TheMonarc: that's about main pros of Mongo I've ever seen have substance...

19:24 TheMonarc: a lot of the complaints about mongo i've seen have been people's own fault of using a documentdb when they really needed something else

19:24 devn: my experience has been: for quick things where i dont want to configure stuff and just start using a store, mongo is nice.

19:25 once you start getting to the point of having a mongo cluster

19:25 all hell begins to break loose

19:26 TheMonarc: yeah i'd be wary of any scenario that needed a cluster

19:26 sharded at least

19:26 if it was just replicated i guess that'd be fine

19:26 p_l: it's the same code and behaviour...

19:26 TheMonarc: i'd ha ve to do research before committing to mongo for something that needed a cluster though

19:26 devn: well, it's not a problem for other document stores

19:27 ive heard good things about couch

19:27 p_l: (and some people caught Mongo dropping writes at load, which lead to funny things)

19:28 TheMonarc: devn, you mentione dyou use clojure at work

19:28 what kind of stuff? web app(s)?

19:28 devn: yeah

19:29 services and apps

19:29 TheMonarc: cool

19:29 devn: lots of clojurescript too

19:29 TheMonarc: nice

19:29 do you do SOA/microservices?

19:29 Wild_Cat: fun fact, said game actually uses a Mongo cluster

19:30 it works trivially because players are essentially isolated from each other, which means we do massive numbers of extremely simple DB operations.

19:31 devn: TheMonarc: some "microservices" sure. i suppose it'd also be fair to just call them "appropriately sized services"

19:31 TheMonarc: haha

19:31 yeah i've been reading about it the past week, and there doesn't seem to be a real definition

19:31 devn: everything is a microservice when you compare them to the services of old

19:31 TheMonarc: other than that they are "small"

19:31 i never got into SOA, so i don't know if this distinction is correct

19:32 but it seems when people talk about microservices

19:32 there is also tendency to have all these services be called directly from an edge/front end system

19:32 Wild_Cat: TheMonarc: I think what people mean by "microservices" is actually "not SOAP. Anything but SOAP. Oh god, never again SOAP."

19:32 devn: TheMonarc: there are a lot of opinions, but just like anything else -- there are tradeoffs.

19:32 TheMonarc: i keep wondering how are you not running into latency issues

19:32 timeouts etc

19:33 was that also an issue with SOA?

19:33 devn: microservices are great until you need to start coordinating sweeping changes across 10s of them

19:33 but maybe you already thought that through ahead of time and so it's not a big deal

19:33 TheMonarc: @wild_cat LOL

19:34 devn: microservices make a lot of sense at first glance i think. they forcefully decouple code. they potentially allow you to scale out critical services cheaper because you can just get lots of small EC2 instances instead of needing monolithic server horsepower

19:35 but once you have 100 EC2 instances for some service, you need to coordinate them

19:35 TheMonarc: 100 EC2 instances...

19:35 Wild_Cat: microservices make a lot of sense architecturally when you decide to write your app as something that needs to easily scale up by spinning up new VMs in a cloud somewhere.

19:36 TheMonarc: seems like a lot

19:36 devn: im not being down on them. i think it's a great idea. it's not really a new idea either.

19:36 Wild_Cat: ...and once you start needing them to coordinate somehow, you need to involve a message queue or something similar.

19:36 devn: TheMonarc: heh, that's not much

19:36 Wild_Cat: because any other approach leads to madness.

19:36 TheMonarc: wildcat

19:37 give an example of when you need to "coordinate"

19:37 the instances

19:37 do you mean put a piece of async work into a queue

19:37 Wild_Cat: most of the time, yes

19:37 TheMonarc: for a separate service to process?

19:37 devn: "we're overloading another service. everyone who is a service like me, slow down!"

19:38 TheMonarc: ah ok

19:38 so a circuit breaker across all instances of Service A

19:38 so they don't overload service B

19:38 devn: it's a simple example sure

19:39 here's the thing. let's say you have 50 microservices. and some of those services talk to other services, who talk to other services

19:39 TheMonarc: i never had to implement something like that

19:39 devn: draw the graph

19:39 TheMonarc: but i imagined if i did, my naive approach would be to use a reddis cache or something to store state that Service A instances would use

19:39 devn: now tell me: do you think it will be more difficult to make changes?

19:39 TheMonarc: rather than a queue

19:40 devn, yeah it seems like it'd be difficult to make changes

19:40 devn: if you change service A, and service B uses service A through Service C, and Service C uses Service B, and Service D uses B, and so on...

19:40 you need to have that story figured out early on

19:40 TheMonarc: my thought on that

19:40 was you could version the services

19:40 so at the bottom of the graph (the nodes that everything else depends on), you deploy two versions side by side

19:41 keep doing that "up" the graph till new stuff is all deployed

19:41 then retire the old versions

19:41 devn: great, but now what does it take for you to do a release?

19:41 TheMonarc: probably a lot of problems with that approach though

19:41 devn: takes you forever now to get a deploy out

19:41 TheMonarc: so how do you sole that

19:42 devn: carefully ;)

19:42 there are lots of things you could do, right?

19:43 you could make logical groups of services which will depend on nothing but a single interface to another group of services

19:43 sort of like organs in the body

19:44 you could do as you're saying and actually keep legacy services online and transition them out

19:45 TheMonarc: and you should only have to do the side-by-side-and-then-transition-out thing when a service has a breaking change right?

19:45 devn: you could send your version over the wire to other services to tell them: "Hey! I'm newer than you!"

19:45 or "I'm older!" so you can get the response you expect

19:46 TheMonarc: well this is the thing, and this is why simulation testing is important

19:46 if you have a really complex graph of microservices

19:46 you need to be able to replay production traffic and simulate traffic so you can find out who talks to who

19:46 bcause it changes often

19:48 and make sure that everyone knows how to live in the "my microservice just got a tiny version bump and now everyone has to deal with it" world

19:48 joobus: does anyone here use the nginx-clojure module?

19:49 devn: i haven't

19:49 Wild_Cat: devn: as someone who's currently living in the "we refuse to upgrade from a 4-year-old version of MySQL that you can crash with a very simple query" world, that world you describe is tempting.

19:49 devn: Wild_Cat: it comes with its own set of problems though, yknow?

19:49 the grass is always greener.

19:49 Wild_Cat: indeed.

19:50 devn: RAPID DEPLOY! GO GO GO! ... Oh wait, we need to manage this now...

19:50 vs 4 years of QA

19:50 joobus: i've been reading the install tutorial but it's written in broken english...

19:50 devn: joobus: nginx is a product of russia after all :)

19:50 Wild_Cat: yeah, it's a tradeoff of "crap, it's broken!" vs "crap, it's still not fixed!"

19:50 devn: Wild_Cat: i prefer the middle

19:51 Wild_Cat: hence 'tradeoff' ;)

19:51 devn: "it's still not fixed because we will all have to coordinate" and "crap it's broken, but we knew about it when <1% of traffic was being passed through the new production environment"

19:52 justin_smith: devn: is there a SO like site for that kind of architecture / system design stuff (and better yet, also intersecting with the programming and implementation side)

19:52 TheMonarc: yeah i wish i had to deal with this kind of problem at work

19:52 joobus: you guys have time to do qa?!?! my company does QA if we have time...

19:52 devn: justin_smith: i dont really know much about the SO ecosystem

19:52 amalloy: justin_smith: probably serverfault

19:52 devn: joobus: QA has the word "assurance" in it, which makes it kind of a funny term to begin with

19:53 "intended to give confidence"

19:53 justin_smith: amalloy: I thought that was more for administrators than designers - but maybe that crosses over more than I thought

19:53 TheMonarc: yeah serverfault is for like "how do i configure IIS to enable gzip compression" type questions

19:53 devn: QA means a lot of different things to a lot of different people

19:54 amalloy: programmers and SO probably fit too; between the three of them you should be able to ask most any question about this kind of stuff. but i haven't really tried

19:54 devn: "it isn't on fire." vs "i noticed that when we give this 2x the load we normally have in production it falls over."

19:54 anyone have any experience with CQRS?

19:55 joobus: my comp uses python, so we don't see the error until someone hits that path.

19:55 TheMonarc: none of the microservices blog posts/articles i've read have really gone into any detail about how they handle the versioning scenarios that devn mentions

19:56 devn: that's because it's kind of buzzwordy IMO

19:56 TheMonarc: is that because the options are all messy/bad and no one wants to acknowledge it?

19:56 devn: i've seen a couple of posts (would have to dig them up from history)

19:56 about "well, we tried, and we sort of got it right... but..."

19:57 well some of it is kind of just...idk, trendy.

19:58 TheMonarc: currently have this article about CQRS in my open browser tabs: http://www.udidahan.com/2009/12/09/clarified-cqrs/

19:58 but i haven't done CQRS

20:03 devn_: go strmpnk___

20:03 whoops

20:03 joobus: who here uses clojure professionally?

20:04 justin_smith: I do

20:05 joobus: do you work for a startup?

20:05 just wondering how much penetration clojure is getting in the "real world"

20:05 devn: i use clojure at work

20:06 joobus: ive been around this community since pre 1.0 days and it is growing big time

20:06 justin_smith: joobus: not a startup - I have a contract with a digital agency supporting some sites I developed for them. Previously was salaried doing clojure for web site backends.

20:06 devn: i mean, the fact that wal mart labs and staples labs were at clojure west should tell you something

20:06 joobus: I've been tinkering for about a month now

20:07 devn: joobus: http://www.indeed.com/jobtrends?q=ruby%2Cjava%2Cscala%2Cclojure&relative=1&relative=1

20:08 TheMonarc: http://www.indeed.com/jobtrends?q=scala%2Cclojure&l=

20:09 devn: if you're just looking for a job with a different JVM language, Scala is a choice

20:09 if you want to be a happy human being who enjoys their work, clojure

20:09 ;)

20:10 TEttinger: joobus, clojure is very startup-friendly, since an experienced dev can get an app up and running with a good deal less code than, say, Java. but there's also the advantage of being able to interop with existing Java codebases which is great for established companies that use Java too. I'm speaking in generalities and of course every company will have different needs, but clojure's strengths are aimed at being a business-friendly lisp

20:10 TheMonarc: what do you do for web/service frameworks with clojre

20:10 devn: joobus: TheMonarc: https://github.com/Dobiasd/programming-language-subreddits-and-their-choice-of-words

20:10 TheMonarc: do people use clojure specific frameworks

20:11 joobus: I currently don't have a JVM language in my toolset, nor a functional lang. I began looking into clojure on the recommendation of a friend using clojure at a startup

20:11 devn: https://github.com/Dobiasd/programming-language-subreddits-and-their-choice-of-words/raw/master/img/happy.png

20:11 TheMonarc: or do you use Spring/Dropwizard etc

20:11 with clojure?

20:11 devn: TheMonarc: most people don't use "frameworks"

20:11 the idea in clojure is -- libraries > frameworks

20:11 compose your libraries and you can have your own framework

20:11 TheMonarc: @devn, nice

20:11 devn: there are some pretty common pieces in that stack though

20:12 compojure and ring are ubiquitous

20:12 justin_smith: that said, I did help develop a big old clojure framework, even comes with a built in cms where you can create new data models for the site, or add new data, in web forms

20:12 devn: yeah, there's room for both

20:12 but /historically/, the community has had an opinion on libraries instead of frameworks

20:13 justin_smith: definitely

20:13 joobus: what is everyone's opinion of datomic/ do most here stick to the SQLs with clojure?

20:13 devn: and like justin_smith: that said, ain't nothin wrong with a framework now and again

20:13 joobus: if you need datomic use it. if you dont know why you need it, figure that out first.

20:14 justin_smith: devn: and how does one know they need datomic?

20:14 devn: by understanding what it is :)

20:14 comparing it to relational DBs, document stores, k/v stores, etc.

20:15 objectiveous: Is there a simple way to inspect deftypes in order to understand what modifiers and annotations have been applied?

20:15 bbloom: ,09

20:16 clojurebot: #<NumberFormatException java.lang.NumberFormatException: Invalid number: 09>

20:16 bbloom: ,0644

20:16 clojurebot: 420

20:16 devn: ,08

20:16 clojurebot: #<NumberFormatException java.lang.NumberFormatException: Invalid number: 08>

20:16 devn: ,07

20:16 clojurebot: 7

20:16 justin_smith: objectiveous: aren't annotations a javac thing? deftype does not use javac

20:16 bbloom: weeee leading zeros equal octal

20:16 devn: bbloom: haha, something i learned doing a project euler problem many moons ago

20:16 did you just run into it?

20:17 bbloom: yeah, i was tuning a parameter, deleted a leading 1, and the results just seemed... wrong

20:17 devn: ,(Integer/parseInt "09")

20:17 clojurebot: 9

20:17 devn: bbloom: heh yeah

20:17 TheMonarc: "Never break their consumers. We agreed a standard early on to have a version number in resource paths (e.g. /1.x/products/12345/), such that if there is a need for a breaking change, a new version can be deployed side-by-side and get adopted by upstream consumers. Even though we still keep this capability, we haven’t needed to use it for years."

20:17 justin_smith: objectiveous: that said, you can look at the interfaces some obejct implements

20:17 TheMonarc: from here: http://dev.mixrad.io/blog/2014/08/22/MixRadio-Architecture-Overview/

20:17 justin_smith: ,(-> [] clojure.reflect/reflect :bases)

20:17 clojurebot: #<CompilerException java.lang.ClassNotFoundException: clojure.reflect, compiling:(NO_SOURCE_PATH:0:0)>

20:18 justin_smith: ,(require 'clojure.reflect)

20:18 clojurebot: nil

20:18 justin_smith: ,(-> [] clojure.reflect/reflect :bases)

20:18 clojurebot: #{clojure.lang.APersistentVector clojure.lang.IObj clojure.lang.IEditableCollection}

20:18 devn: clojure.reflect is so nice to have

20:18 justin_smith: indeed it is

20:18 objectiveous: justin_smith, I'm not sure to what degree they are supported but I did see an email on the list describing the feature. Let me check...

20:19 devn: ,(->> (clojure.reflect/reflect []) :members (map (comp str :name)) sort)

20:19 clojurebot: ("EMPTY" "EMPTY_NODE" "NOEDIT" "_meta" "access$000" ...)

20:20 justin_smith: objectiveous: annotations are not a thing that exists on the jvm - they are a concept in the javac compiler. Most Clojure code, and all deftypes, do not go through the javac compiler.

20:20 devn: objectiveous: like extenders?

20:22 objectiveous: justin_smith, this is what got headed down this train of thought. https://gist.github.com/richhickey/377213

20:22 justin_smith: objectiveous: oh I may have to eat my words here

20:22 my bad, sorry for the misinformation

20:23 that gist shows how to get the annotations, which is exactly what you were asking

20:23 objectiveous: justin_smith, ;-) But please don't stop helping me! I'm seriously in over my head. lol

20:23 devn: https://gist.github.com/richhickey/b5aefa622180681e1c81

20:24 objectiveous: justin_smith, basically I'm trying to work with a clojure library that wraps the orientdb client java library.

20:25 It does a load of javassit jazz and doesn't like my typedef as it's Final.

20:25 llasram: objectiveous: Do you have a link to documentation about what you're trying to do with annotations?

20:26 justin_smith: objectiveous: the class being final, or the fields on the object being final? I readily believe the latter, but that can be fixed with deftype

20:26 objectiveous: llasram, checking...

20:26 justin_smith: to the degree that making fields mutible is fixing anything

20:26 devn: heh, insane: https://github.com/ztellman/cambrian-collections/blob/master/generate/cambrian_collections/vector.clj

20:26 generate that java class with clojure!

20:27 llasram: objectiveous: My experience is that many Java systems which use annotations at runtime via reflection need other things which you can't do with deftype, like have zero-argument constructors with annotations on the constructor

20:27 objectiveous: justin_smith, I've already marked the fields so I believe the problem is with Class itself.

20:27 devn: you could proxy, no?

20:29 maybe im missing the point

20:29 but there's also this: https://github.com/clojure/clojure/blob/master/test/clojure/test_clojure/genclass/examples.clj#L32

20:29 objectiveous: llasram, I suspect you're right and wonder what the most clojuresque approach would be?

20:30 devn: bah nevermind, i see what you mean now

20:31 llasram: objectiveous: My experience is that Java is a pretty strong DSL for implementing Java classes

20:31 bbloom: llasram: heh.

20:32 llasram: objectiveous: You can implement a tiny veneer Java class with exactly the interface (in the abstract sense), which then uses the Clojure Java API to load and run Clojure code for the actual implementation

20:33 objectiveous: Here's a lightening talk rhickey gave describing the approach: https://skillsmatter.com/skillscasts/3864-impromptu-rich-hickey-lightning-talk

20:34 objectiveous: I think maybe I'm starting to see the light. I'm building up a rather large information model and orientdb allows me to interact with that model as Documents or Classes. I liked the idea of having types but maybe I should rethink this a little, if I want to live in clojure land.

20:34 llasram, cheers!

20:34 devn: hrm, llasram this looks like annotations on 0 argument constructors? https://github.com/pallet/clojure-maven

20:35 llasram: devn: Where?

20:35 devn: ugh, im tired or something. i think im leading you down the wrong path

20:35 llasram: objectiveous: Good luck!

20:35 devn: sorry dude

20:36 llasram: ~guards

20:36 clojurebot: SEIZE HIM!

20:36 devn: lol

20:37 objectiveous: Thanks, folks. It's great to know there's a group of friendlies around to help a brother out, as they say.

20:50 justin_smith: objectiveous: bonus, today I learned more about how annotations are actually implemented

20:57 lavokad: im geting file not exception when doing this

20:57 (GET "/" [] (println (slurp "/resources/html/header.html"))))

20:57 (GET "/" [] (println (slurp "/resources/html/header.html"))))

20:57 (GET "/" [] (println (slurp "/resources/html/header.html"))))

20:57 (GET "/" [] (println (slurp "/resources/html/header.html"))))

20:57 (GET "/" [] (println (slurp "/resources/html/header.html"))))

20:57 (GET "/" [] (println (slurp "/resources/html/header.html"))))

20:57 (GET "/" [] (println (slurp "/resources/html/header.html"))))

20:58 justin_smith: lavokad: resources is on your path

20:58 and /resources probably does not exist

20:59 also, if you want your code to work from an uberjar, change it to (slurp (io/resource "html/header.html"))

20:59 lavokad: im geting file not exception when doing this

20:59 clear

20:59 wtf

20:59 ?

20:59 justin_smith: lavokad: because /resources is not the same as resources

20:59 lavokad: damn it..

20:59 justin_smith: (slurp "resources/html/header.html")

20:59 but like I said, better to switch to io/resource and take out the resources/ part of the path, while you are at it

21:00 lavokad: sorry something broke and didnt see what i was writing

21:00 justin_smith: sorry, then in which dir am I when i do (GET "/" [] (println (slurp "/resources/html/header.html"))))

21:00 ?

21:01 justin_smith: lavokad: you are likely in your project dir

21:01 but as I said multiple times, /resources/html/header.html is not the same as resources/html/header.html

21:01 you want the latter

21:01 the extra / means "look for this on the top level of my filesystem, ignoring my current directory"

21:03 lavokad: oh no

21:03 i'm blind

21:03 :D

21:04 thank you!

21:30 xeqi: anyone have a library for watching a file for changes?

21:31 justin_smith: there are a few. You can also create a watcher object via interop with nio (jvm 7+)

21:31 https://github.com/ibdknox/watchtower this one looks straightforward

21:32 but it uses polling, nio can use much more efficient OS level notifications (push from the system when the file is changed)

21:33 this one uses the proper java 1.7+ watcher api https://github.com/derekchiang/Clojure-Watch

21:36 there is also nio.file, we have a unit test on that lib which shows a lower level interop. https://github.com/ToBeReplaced/nio.file/blob/master/test/org/tobereplaced/nio/file_test.clj#L111

21:36 xeqi: yeah, I was glancing at Clojure-Watch but don't see a stop-watch

21:36 but I can use it as a base

21:37 justin_smith: the nio.file one is based on a watch-service object you create, which you can turn off, more or less

21:37 also you can just cancel the thread that takes events from that watcher

21:38 (assuming you are doing the reasonable thing and putting watching in its own thread)

22:10 TheMonarc: anyone tried http://clojurekoans.com/ ?

22:14 joobus: trying it now :)

22:15 amalloy: TheMonarc: clojure koans is probably fine, but for a flavor of the same thing with less setup you could try 4clojure.com

22:24 joobus: koans seems ok, solved a few just now

22:24 then i got stuck

22:34 mynomoto: clojurescriptkoans.com are good too. I don't remember if there is anything clojurescript specific there.

22:37 joobus: does anyone here use vim-fireplace?

22:41 mynomoto: anyone?

22:41 clojurebot: anyone is anybody

22:42 jgdavey_: joobus: I do

22:44 joobus: i guess you would recommend it then?

22:44 i'm kind of a clojure noob at the moment

22:45 jgdavey_: If you're a vim user, definitely

22:45 joobus: i tried vim-fugitive (for git) but just use command line git instead

22:45 didn't know if it was worth it

22:46 jgdavey_: I put together a screencast on using vim-fireplace a couple months back. It may be useful for the basics: https://vimeo.com/98052766

22:46 mynomoto: joobus: http://clojure-doc.org/articles/tutorials/vim_fireplace.html is a good place to start.

22:47 joobus: thank you

22:47 jgdavey_: i think i've run across your name in other searches as well

22:48 were you at clojure west?

22:48 jgdavey_: I wasn't, unfortunately.

22:53 joobus: has anyone used lein fruit and lein droid? I'm wondering if it is possible to share common code between the two to deploy the same app to both platforms.

23:18 danielcompton: I just got a Kinesis advantage, man it's brutal on my typing

23:18 showing up 10 years of shoddy muscle

23:18 memory from typing badly

23:20 joobus: danielc: i looked at those but went with the microsoft natural whatver for $20

23:20 do you like the keyboard?

23:21 danielcompton: joobus: still undecided. I think it needs a while to really give it a good test. It feels 'natural' on my hands which is good I guess.

23:22 It uses thumbs way more so now i have sore thumbs instead of sore pinkies

23:22 joobus: what did you use before?

23:23 danielcompton: Apple wireless keyboard

23:23 I'm also keen to try technomancy 's

23:23 Atreus

23:23 joobus: i personally have a cast on my right hand at the moment so i use 1 hand and a "typing pencil" in my other. it sucks.

23:23 danielcompton: adyn ergodox, and a keyboard.io

23:23 joobus: i hate the apple keyboards

23:24 danielcompton: joobus: that would be dumb. Are there one handed keyboard layouts?

23:24 joobus: no, the cast hopefully comes off in a week

23:25 Jaood: joobus: the microsoft natural is great :)

23:25 * Jaood used to have one

23:25 joobus: Jaood: i agree, best bang for the buck

23:25 maravillas: the ms natural 4000 feels like mush

23:26 joobus: maravillas: are you a mechanical keyboard user? or what?

23:26 maravillas: keys, that is

23:26 Jaood: http://en.wikipedia.org/wiki/Microsoft_Natural_keyboard#mediaviewer/File:MS_Natural_Keyboard_Elite.png

23:26 had that one but black

23:26 maravillas: i'm an ms natural 4000 user :)

23:26 i haven't gotten around to replacing it

23:27 talios: danielcompton - keyboard.io looks nice

23:27 danielcompton: talios: not out yet though :(

23:27 maravillas: i also use an apple magic keyboard and don't mind it

23:28 Jaood: the 4000 is bigger because of the media buttons

23:28 talios: danielcompton - *sadface*

23:28 danielcompton: maravillas: I liked the apple keyboard until i started using emacs

23:28 joobus: i have bigger hands, the 4000 lets me stretch my hands out a little better. the apple keyboards are too cramped for me.

23:28 maravillas: it is a little awkward, but thankfully i've never had rsi issues with it, somehow

23:30 danielcompton: my favourite is still https://farm3.staticflickr.com/2787/4397554484_739ae62eee_b.jpg

23:30 from technomancy

23:30 joobus: danc, lol

23:30 did you use one of those?

23:31 talios: danielcompton - combine that with http://www.muldersworld.com/photo.asp?id=25864 and you're a winner

23:31 or just a sad loser :)

23:31 danielcompton: computering anywhere. Just add an Oculus Rift

23:39 joobus: does anyone here use the nginx-clojure module with nginx?

23:39 justin_smith: joobus: it's silly

23:39 just use nginx as a reverse proxy

23:39 joobus: to a ring server?

23:39 justin_smith: right

23:40 http-kit is a good choice

23:40 it can be helpful to run varnish too

23:41 joobus: nginx-clojure claims to be the fastest https://github.com/ptaoussanis/clojure-web-server-benchmarks

23:42 so i was curious how well it works

23:42 but the install tutorial was written in broken english and i kinda got lost

23:42 amalloy: joobus: i would not advise using nginx-clojure

Logging service provided by n01se.net