# #clojure log - Feb 16 2014

The Joy of Clojure
Main Clojure site
IRC
List of all logged dates

0:02 munderwo: hi all, so I have (map inc [1 2 3 4]) that I get a sequence out of (?), and I want to let each member of a sequence to a local var. How would I go about this?

0:04 uvtc: munderwo, if you know how many elements in the seq you're starting off with, you can use destructuring like so: `(let [[a b c d] (map inc [1 2 3 4])] (println a b c d))`

0:04 munderwo: uvtc: ahh! thats exactly what I want. I do know how many there will be.

0:14 bob2: if you don't, it doesn't make sense for them to be locals, anyway :)

0:18 TravisD: I've been reading through SICP and one of the exercises is to design an efficient procedure for counting the number of ways to make change for \$1.00 with coins valued at \$0.01, \$0.05, \$0.10, \$0.25, and \$0.50. I have come up with the following memoizing function that takes O(N*M) time, where N is the amount your calculating change for, and M is the number of denominations: http://cljbin.com/paste/530047a6e4b0e267ba6e2ab2. Please critique

0:20 uvtc: (Aside: didn't know there was another Clojure-based paste-bin!)

0:20 TravisD: uvtc: I'm just getting into clojure :) I found this one by googling "Clojure Pastebin" :P

0:21 In the running time bound I gave, N should really be M/c, where c is the smallest denomination

0:21 er, M should be N/c. sorry, lol

0:23 echosa: why is assoc-in sometimes fine with having the last argument be a string, and other times I get a String can't be can't to Character error?

0:23 amalloy: TravisD: the scheme idiom of putting defines inside defines is no good in clojure - you either want multiple top-level defs, or a let

0:23 ambrosebs: echosa: example?

0:23 TravisD: amalloy: Ah, good to know. What's bad about it in clojure?

0:24 amalloy: def and defn always create a top-level var

0:24 TravisD: ah

0:24 amalloy: if you do that while running some other function, lots of things go bad, eg race conditions if count-change is called from two threads at once

0:24 TravisD: yeah, that is pretty dangerous. Do you know the rationalle for not lexically scoping them?

0:25 echosa: ambrosebs: hang on.. might have figured something out...

0:25 amalloy: well like...we already have let for lexical scope. it's more clear if let is always lexical, and def is always global

0:26 i'm sure there are other reasons, but that's the one that seems most obvious to me

0:26 TravisD: yeah, that makes sense

0:27 so if you want to have helper procedures, is it idiomatic to have (let [helper (fn [...] ...)])?

0:27 amalloy: yes, or (letfn [(helper [...] ...)] ...)

0:28 echosa: assoc-in will give a String can't be cast to Character if you give it a generated vector like this: (assoc-in (vec (for [y (range 3)] (conj (vector-of :int) 1 2 3 4 5))) (list 1 1) "@")

0:28 yet this is fine: (assoc-in [[1 2 3][4 5 6]] '(1 1) "@")

0:29 rhg135: anyone have any timps on how to write a network-using gui app?

0:29 amalloy: uhh...you're trying to put a string into a vector-of :it, echosa?

0:29 of course that won't work

0:29 rhg135: normally i'd use web js, but cross-domain

0:29 echosa: why does it work in my second example?

0:29 amalloy: because [4 5 6] is a vector of Object

0:30 really (vector-of anything) is very very rarely used in clojure, and we use the boxed Object vectors all the time

0:30 echosa: ಠ_ಠ I suppose that makes sense

0:30 seancorfield: ,(vector-of :object)

0:30 clojurebot: #<NullPointerException java.lang.NullPointerException>

0:30 seancorfield: hmm, wasn't sure that was possible :)

0:30 ,(vector-of :int)

0:30 clojurebot: []

0:31 echosa: vector-of can only take :int :long :float :double :byte :short :char or :boolean

0:31 seancorfield: thanx. saves me looking it up :)

0:31 echosa: ok, then I'm going to for the direct "give me the answer" route since I'm failing at figuring it out myself.

0:32 seancorfield: ,(into (vector-of :int) "@")

0:32 clojurebot: [64]

0:32 seancorfield: ,(into [] "@")

0:32 clojurebot: [\@]

0:33 echosa: I want to create a grid (vector of vectors) with a given height and width and have each "item" in the grid set to a random number between 1 and 9 (I have this part working), but THEN I need to be able to set a random element in the grid to "@" (this doesn't work because of the case, but *does* work if I use a number like zero instead of "@")

0:34 I pretty much have everything working, but it makes use of the vector-of, which screws me when I try to change an element to "@"

0:35 seancorfield: Why use vector-of at all? What's wrong with just [ [ ... ] [ ... ] [ ... ] ... ] ?

0:35 echosa: if the function gets passed a height of 5, then I'll need five inner vectors, if it gets passed 20 I'll need 20...

0:35 that's the only part I haven't figured out yet at all

0:35 so I've been working with a static height to get the rest working first

0:36 seancorfield: ,(repeat 5 [])

0:36 clojurebot: ([] [] [] [] [])

0:36 TravisD: amalloy: Is this better? http://cljbin.com/paste/53004d06e4b0e267ba6e2ab4 Also, it runs fine on my machine but gives an error on the pastebin - any idea why?

0:36 echosa: hm.. I misspoke, its the width that I haven't gotten working (the number of things inside the inner vectors)

0:36 but maybe repeat will work

0:37 ,(repeat 5 (rand-int))

0:37 clojurebot: #<ArityException clojure.lang.ArityException: Wrong number of args (0) passed to: core/rand-int>

0:37 echosa: ,(repeat 5 (rand-int 9))

0:37 clojurebot: (0 0 0 0 0)

0:37 amalloy: looks pretty good, TravisD. i don't really like the cache'' name, is my main complaint

0:37 TravisD: echosa: That says "give me a random int, and then give me a list with 5 copies of it"

0:38 echosa: Ah.

0:38 seancorfield: ,(into [] (repeatedly 5 (fn [] (rand-int 9))))

0:38 clojurebot: [7 3 6 1 6]

0:38 amalloy: i'd just let [... (cache (-> cache (update-cache k1) (update-cache k2)))]

0:38 er... [..., cache (-> cache (update-cache k1) (update-cache k2)))]

0:38 rhg135: oh and i can run on nodejs with node-webkit, but i lose interactive development

0:38 TravisD: amalloy: Can you rebind names?

0:38 ah, yeah, I was looking at ->

0:38 that's a good use

0:38 amalloy: TravisD: yes

0:38 seancorfield: ,(into [] (repeatedly 5 (fn [] (into [] (repeatedly 8 (fn [] (rand-int)))))))

0:38 clojurebot: #<ArityException clojure.lang.ArityException: Wrong number of args (0) passed to: core/rand-int>

0:39 seancorfield: ,(into [] (repeatedly 5 (fn [] (into [] (repeatedly 8 (fn [] (rand-int 9)))))))

0:39 clojurebot: [[3 1 8 0 8 ...] [5 1 6 0 0 ...] [2 7 1 1 5 ...] [3 6 1 8 5 ...] [5 0 0 5 6 ...]]

0:39 amalloy: &(let [a 1, b #(+ a %), a 2] (b a))

0:39 lazybot: ⇒ 3

0:39 echosa: I've been trying to figure that out for far too long

0:39 amalloy: if you understand why 3 comes out there, you've got the mechanics of name-rebinding down

0:39 seancorfield: echosa: but if you're updating that array a lot, maybe immutable vectors aren't what you need... just a thouhgt

0:40 amalloy: oh, and if it hasn't come up yet, #(+ a %) is just shorthand for (fn [x] (+ a x))

0:40 TravisD: amalloy: that is directed at me?

0:41 amalloy: yeah

0:41 bbloom: ,(let [a 3, f (fn [%] (+ a %))] (f 5))

0:41 clojurebot: 8

0:41 TravisD: ah, yeah

0:41 bbloom: was just wondering if % was a valid symbol there, i assumed it was

0:41 heh

0:42 echosa: seancorfield: perhaps. Though with this I'm pretty closed to a "finished" releasable version of my first clojure program. Once I have it "done", I'll put it on github for code review and tips. :)

0:45 TravisD: amalloy: hmm, are variables pointers?

0:45 amalloy: welllll, that's a question with multiple correct answers

0:45 what behavior in particular are you thinking of?

0:47 TravisD: amalloy: Well, I was wondering if the free variables in a lambda expression get coppied from the environment. If the variables were pointers, that would explain why b's copy of a continues to have the value of 1, even after a has been rebound in the (let ...). Or something. lol

0:47 uvtc: TravisD, the Clojure language per se doesn't have "pointers" (that I know of). Typically, symbols are names that refer to a var which refers to a value. But when you type a symbol into the repl, it's automatically evaluated down to the value.

0:48 amalloy: uvtc: symbols very frequently don't refer to a var at all

0:48 they refer to a local quite often

0:48 uvtc: Right. Thank you. I'd actually asked about that very thing when I first began using Clojure.

0:50 TravisD, so, if you do `(def a (something...))`, then `a` refers to a var, but if you do `(let [a (something...)] ...` then `a` just refers directly to a value (within the `let` body).

0:51 TravisD: hmm, I don't know enough to know the difference between a var and a local

0:52 Is there an approachable language spec somewhere

0:52 ?

0:53 uvtc: TravisD, a "local" is just when you get a symbol bound to a value using a `let` binding (or similar).

0:54 TravisD: so the only difference is that a var is in the top level scope and a local is in the scope of the let that defines it?

0:54 uvtc: TravisD, a Var is something you get when using `def`, `defn`, or similar (where, again, the symbol you use for it is connected with the var, which is (usually) connected with a value).

0:54 amalloy: TravisD: well, a Var is actually an object that exists at runtime, which you can play around with

0:55 &(var clojure.core/inc)

0:55 lazybot: ⇒ #'clojure.core/inc

0:55 amalloy: whereas a local is just a compiler-bookkeeping mechanism to remember what means what

0:55 TravisD: ah

0:56 amalloy: anyway, in my example with a and b, b doesn't actually copy the value of a ever. but lambdas remember the environment they were created in. the later redefinition of a creates a new environment, but doesn't impact the lambda

0:57 if a's value were some mutable thing, like a java.util.ArrayList, we could mutate it and then b's behavior would change. but introducing a new thing named a is different

0:57 TravisD: ah, okay. And in the compiled code, all occurences of a will be translated to their numeric values or something?

0:58 like, the names there are just for our convenience?

1:00 echosa: Ok, folks. Before I sign off shortly, here's the fruit of my efforts for a few days. It's my first ever Clojure app, and this channel was instrumental in getting it done as quickly as I did. All comments and critiques are welcome. The idea is for me to become better at Clojure. https://github.com/echosa/clojure-greed

1:01 amalloy: TravisD: the names actually get compiled into the bytecode, i believe, but they get mangled somehow

1:02 TravisD: amalloy: Ah alright! Sorry for asking so many questions - I should probably read about it for myself

1:02 amalloy: no worries, these are great questions

1:03 echosa: updated the read me to actually have the controls listed

1:05 TravisD: amalloy: Good to hear :) I wont feel sheepish when I have more!

1:05 echosa: Looks pretty cool. Are you working up to a rogue clone or something?

1:05 echosa: No, it's a Clojure rewrite of greed, just like the readme says. ;-)

1:06 TravisD: ah, alright. I was just noticing some of the similarities :P @ representing your character and the controlls

1:07 echosa: Yeah, a lot of the old CLI games used the vim keybindings and @ for the player. ^_^

1:07 uvtc: echosa, I'm not familiar with the game "greed". Maybe provide more description of it, or a link to a desc in the readme?

1:07 echosa: I thought the readme explained it pretty well. I'll see if I can find an external link.

1:07 TravisD: echosa: Ah - they come from vim... lol

1:10 echosa: The best I can find are http://terasaur.org/item/show/greed-3-2/3049 and https://apps.ubuntu.com/cat/applications/natty/greed/

1:10 neither of which are helpful

1:21 uvtc: echosa, Ah, heh, I see. That's pretty neat. Would be nice if it (A) printed your score somewhere on the screen, and (B) told you "game over" at the end. :)

1:21 danielcompton: Hi all, is it bad form to put side effects into let bindings? I'm doing some dom manipulation with clojurescript and that seems like a good place to put it

1:22 echosa: It does tell you "game over" at the end.

1:22 The score is coming later.

1:23 readme updated with TODO list and a special thanks to #clojure ;-)

1:23 uvtc: echosa, Oh, right you are.

1:24 echosa: also, thanks for the compliments :-)

1:25 and now for some celebratory sleep... thanks for all the help, everyone!

1:25 danielcompton: Well done, that was neat!

1:25 Raynes: SLEEP. IT IS FOR THE WEAK.

1:25 echosa: Thanks!

1:26 Raynes: Then call me weak. I won't care. Because I'll be fast asleep. :-)

1:26 TravisD: next step, write a solver for the game :)

1:26 uvtc: Raynes, bah, it's still early for you west-coasters!

1:26 Raynes: This is true.

1:26 egghead: you kidding? it's almost 10:30!

1:26 Raynes: This is also true.

1:26 echosa: plus I'm meeting my boss at work in 7 1/2 hours to work on a side project.

1:27 Raynes: I'm actually staying up far later tonight than usual.

1:27 I've been old manning it to bed at like 10:30pm most nights.

1:27 insamniac: echosa: clojure side project i hope

1:27 echosa: so yeah, sleep. :-) Gotta make up for staying up late last night watching curling live.

1:27 insamniac: unfortunately, no. It's planning/working on a website for our office band/music group/jam nights

1:28 uvtc: Raynes, good for you. (inc healthy-sleeping-schedule).

1:28 insamniac: echosa: clojurescript!

1:28 heh

1:28 Raynes: uvtc: I need less sleep, more PARTY!

1:28 echosa: Raynes: my wife and I are usually in bed between 9 and 10. Old manning it, indeed.

1:28 Raynes: ;P

1:29 echosa: *9 or 10

1:29 see.. the lack of sleep is already affecting me...

1:29 :-D

1:29 Raynes: Clearly.

1:29 uvtc: echosa, give that mustache it's beauty sleep :)

1:30 echosa: uvtc: heh... the Internet is a wonderful tool, isn't it?

1:30 uvtc: s/it's/its/ bah. Yeah. You're braver than me though. Haven't put up a gravatar myself yet. :)

1:30 Raynes: uvtc: Goodness m8, you gonna ask his a/s/l next

1:30 echosa: I wish more sites made use of it

1:31 uvtc: hehehehe

1:31 Raynes: echosa: Hey, I like music and have fished before. We should be friends after you've slept.

1:31 * echosa sees "a/s/l" in chat text and wonders if he's travelled back in time to 1998

1:31 Raynes: <3

1:32 echosa: Well, you know where to find me... apparently... </internet-stalked>

1:32 Raynes: echosa: One note before you go

1:32 echosa: and I must be tired... that wouldn't even validate :-P

1:32 Raynes: echosa: Docstrings go before argument lists. The only reason this works is because the body of defns are evaluated inside of (do ..), so it evaluates the string and then moves on. If you try to use (doc ..) on any of your functions, it won't work.

1:33 No worries though, pretty much everyone gets the order mixed up at first!

1:33 echosa: Why is Clojure different for the sake of different? docstrings first... arguments are vectors instead of lists... :-P

1:33 Raynes: :P

1:34 Because it's Clojure, not Pyjure silly. (:

1:34 echosa: After 5 years of sbcl and elisp, I have habits formed, dammit.

1:34 Ah well, learning new things is half the fun.

1:34 uvtc: Weird that, at clojars, searching for "clojure-lanterna" turns up nothing, but searching for "lanterna" turns up clojure-lanterna...

1:34 echosa: Thanks for the notes.

1:34 lol@search fail

1:35 Raynes: echosa: This is an impressive first Clojure project.

1:35 echosa: Keep it up!

1:35 Now sleep before you fall out of your chair, good sir.

1:36 echosa: Thanks! Like I said, i'm not new to Lisp in general. I'm just new to Clojure, and, seriously, this room helped significantly. Thanks for that.

1:36 Also, the benefit of coding is a recliner: you don't fall out, you just fall asleep still typing. :-)

1:36 But seriously... BED TIME! Later, all.

1:36 uvtc: g'night, echosa

2:09 quizdr: when you return a syntax quoted list from a macro, and that list begins with defn, shouldn't it define the function auctomatically when the macro returns?

2:20 benkay: is it crazy to want to persist the state of my application between runs?

2:20 ivan: no

2:21 benkay: didn't think so. what's a good approach?

2:23 quizdr: benkay just print your atoms out to a text file (called edn when you do this), then read them back in later to return the state.

2:23 as simply as spit/slurp and pr/read

2:24 benkay: makes sense.

2:24 bbloom: ~spitslurp

2:24 clojurebot: Huh?

2:24 bbloom: ~spit

2:24 clojurebot: I don't understand.

2:24 bbloom: clojurebot: spit is http://www.brandonbloom.name/blog/2013/06/26/slurp-and-spit/

2:24 clojurebot: Ik begrijp

2:24 bbloom: ~spit

2:24 clojurebot: spit is http://www.brandonbloom.name/blog/2013/06/26/slurp-and-spit/

2:25 quizdr: guys i have a macro that does a defn and it works when i give it a specific key. but when I map this macro (wrapped in a fn) over a list of keys, it does not create any fns. so I added an 'eval' inside the map's fn, which still didn't do it. what am I missing about macros and defn?

2:26 bbloom: quizdr: post your macro

2:26 quizdr: bbloom ok one sec

2:28 then I map it here: https://www.refheap.com/39920

2:30 make-fn works fine on its own. it's mapping it over a bunch of keys that doesn't make the individual functions out of them.

2:30 bbloom: quizdr: think about what happens when you "map" a macro

2:30 macros see the syntax that was given to them, not the evaluated arguments

2:30 quizdr: well, it will create a list of lists of code, right?

2:30 bbloom: you're giving the symbol '% (or whatever clojure rewrites that to) to your macro

2:31 quizdr: oh... i see.

2:31 it is expanding the macro with the %, not with the actual variable the % represents.

2:32 bbloom: quizdr: you got the idea, just be careful with that word "variable"

2:32 the macro sees the syntax that's at the place where the macro is called. it doesn't resolve symbols or do any other evaluation at that point

2:32 quizdr: so i should make a separate named function with defn that calls the macro, and use this named function in my map?

2:33 i guess that wouldn't do it either.

2:34 perhaps i don't need macros for this, and instead use regular functions that return syntax quoted lists, then eval those lists? I had always heard that if you use eval, you probably are doing something unidiomatic

2:34 alew: is there an idomatic way to do something similar to mapcat, except lazily?

2:35 egghead: huh? is mapcat not lazy?

2:35 alew: it's not

2:35 clojurebot: "([f & colls]); Returns the result of applying concat to the result of applying map to f and colls. Thus function f should return a collection."

2:35 alew: it uses apply, which is not lazy

2:36 bbloom: quizdr: step back a second. what are you even trying to do?

2:37 alew: apply is lazy past the max number of arguments

2:37 alew: which means that it essentialy does chunking

2:37 alew: bbloom: you're right

2:37 quizdr: bbloom trying to dynamically generate a bunch of functions, where the names and arg lists for those functions are stored in a map. the functions are all similar, hence using a macro. since the macro works when used indivudally, it would be great to use it for the entire collection

2:38 bbloom: quizdr: you can trivially create functions without a macro... i assume you mean you want to create *vars* with functions in them.... now let's step back another layer: why do you want to do that?

2:39 alew: (inc bbloom)

2:39 lazybot: ⇒ 29

2:39 quizdr: bbloom: the functions if all individually defined as seperate vars gives me some conveniences with a DSL i'm writing

2:40 it's also nice to have them as separate vars for autocompletion and arity hints in the minibuffer

2:40 alew: bbloom: so when the max number of arguments is reached, what occurs? it passes the rest as a list to the function or something?

2:40 bbloom: alew: yeah, a lazy seq

2:42 alew: actually, if the number of required args is known, it's lazy up until that point

2:42 quizdr: i'm skeptical you really want that. i'm sure you *think* you want that, but there's likely a better way

2:42 uvtc: bbloom, thanks for the blog post (re. slurp/spit)!

2:43 bbloom: uvtc: my pleasure. glad you enjoyed it!

2:43 quizdr: what does your DSL do?

2:44 alew: bbloom: I really do hope they used code to generate that file

2:45 quizdr: bbloom ah so i have resolved the issue with two minor changes. The defmacro is now just defn, otherwise unchanged. the map function now evals the list returned from the defn, generating all the functions.

2:45 krakina: clojure rules

2:46 bbloom: alew: knowing that rich's primary IDE is a hammock with Omnigraffle installed, I wouldn't be surprised if he created that file with copy paste or some one-off script that has long since been lost

2:46 quizdr: yes, that works, but i was trying to save you from macrology hell :-)

2:48 quizdr: bbloom technically i suppose it is still a macro-like approach even though I am not actually using defmacro

2:50 bbloom: k well i'm way over due to go to bed

2:50 but much excellent code was written, so totally worth it

2:52 quizdr: cheers

3:21 logic_prog: anyone see http://www.twitch.tv/twitchplayspokemon/ ? I've never been so amused by such a silly idea in my life.

3:48 krakina: zdrast

5:36 clojure cool

5:40 certainty: ((constantly true))

5:54 krakina: sup clos'

6:16 snatchalope

7:01 quizdr: what is the best way to go from keyword to symbol? I can do (symbol (name :key)) but that seems verbose.

7:04 bob2: hm, what for?

7:05 quizdr: for getting a function name from a keyword

7:05 i have a map of keys that are function names and values that are arguments for those functions

7:06 ddellacosta: quizdr: not sure there is a better way, but you could use the threading operator to make it slightly more readable, I suppose.

7:06 ,(-> :key name symbol)

7:06 clojurebot: key

7:06 ddellacosta: arguable how much of an improvement that is

7:07 ,(map #(-> % name symbol) [:key1 :key2])

7:07 clojurebot: (key1 key2)

7:07 quizdr: nice, thanks

7:07 ddellacosta: ,(map #(comp symbol name) [:key1 :key2])

7:07 clojurebot: #<ArityException clojure.lang.ArityException: Wrong number of args (1) passed to: sandbox/eval76/fn--77>

7:07 ddellacosta: whoops

7:08 ,(map (comp symbol name) [:key1 :key2])

7:08 clojurebot: (key1 key2)

7:15 quizdr: ,(apply (symbol (name :println)) [6])

7:15 clojurebot: nil

7:15 quizdr: shouldn't that show 6?

7:15 ,(apply println [6])

7:15 clojurebot: 6\n

7:16 quizdr: is it possible to send a symbol to apply and have it be interpreted as a fn?

7:17 certainty: something like symbol-function in CL?

7:18 quizdr: perhaps

7:18 i was thinking that a symbol, regardless of whether it is literal or the result of an expression, would be interpreted as a function. should be, i'd think

7:18 certainty: maybe resolve

7:19 quizdr: ahh good one. resolve makes it work.

7:19 (inc certainty)

7:19 lazybot: ⇒ 1

7:19 quizdr: yeah man

7:19 btcNeverSleeps`: ,(inc certainty)

7:19 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: certainty in this context, compiling:(NO_SOURCE_PATH:0:0)>

7:21 btcNeverSleeps`: hey all... I've got a question regarding a "timing" behavior I'm seeing. I do bignum computation from Clojure, using Java's BigInteger class. When I do ten multiplication of two random BigInteger, the timing goes always like this:

7:21 From a REPL inside Emacs: 80 ms, 81 ms, 79 ms, 82 ms, 81 ms, 81 ms, 80 ms, 78 ms, 81 ms, 80 ms

7:22 From the command line, running a .jar created using "lein uberjar": 340 ms, 44 ms, 42 ms, 43 ms, 41 ms, 42 ms, 41 ms, 41 ms, 42 ms

7:22 I'm doing two computation in parallel, using a future, if that matters. What explains the timing difference?

7:23 I understand the first 340 ms from the command line is probably the JIT which didn't kick in yet, but why is it twice as fast for the other computation when not run from inside Emacs' REPL?

7:25 AimHere: Are you using a timer function that has some output? the clojure 'time' function does print out something about Elapsed time

7:42 btcNeverSleeps`: AimHere: I'm wrapping my computation inside the (time (...)) function

7:43 AimHere: It might be the difference in overhead between printing to stdio and printing to emacs then

7:44 btcNeverSleeps`: AimHere: but (time ... ()) surely doesn't take it's own time into account right?

7:44 AimHere: I don't know what time does.

7:44 btcNeverSleeps`: ,(source time)

7:45 AimHere: You could try doing 100 bignum multiplications all wrapped inside one (time ...) function so that it's all computation not much overhead

7:45 btcNeverSleeps`: Apparently 'time' as no overhead besides the 'str' creation.

7:46 not even the str creation I guess: I suppose the call to (. System (nanotime)) happens before calling str.

7:53 hyPiRion: time is a macro, so doesn't take itself into account. But there will be overhead for timing no matter what

7:53 use criterium for something bit more sophisticated than pure time

7:53 AimHere: Yeah, but the case is whether it will be different overhead for an emacs repl than for a jarfile

7:54 hyPiRion: why should it be?

7:54 AimHere: Well the one guess I could think of was the difference in printing stuff

7:55 hyPiRion: btcNeverSleeps`: it's likely because `lein` sets optimisation flags which increases startup time, but removes some optimisations

7:56 try to set `:jvm-opts []` in your project.clj and restart the emacs repl, if you need speed for development

8:01 btcNeverSleeps`: hyPiRion: oh I see

8:02 yup, I'm not into precise timing or anything, I'm just wondering what's the technical explanation behind the big difference in running time from inside the REPL and from the command line (curiosity killed the cat).

8:02 hyPiRion: /s/increases/improves/

8:02 btcNeverSleeps`: Say this:

8:02 ,(let [f (fn [] (apply str (take 50000 (repeatedly #(inc (rand-int 9))))))] (time (.multiply (BigInteger. (f)) (BigInteger. (f)))) 42)

8:03 clojurebot: "Elapsed time: 1394.718069 msecs"\n42

8:03 btcNeverSleeps`: takes consistently about 325 ms in my Emacs REPL and constantly only 230 ms from the command line

8:04 hyPiRion: btcNeverSleeps`: yeah, it's likely due to the jvm flags

8:04 btcNeverSleeps`: (once again, besides the first call from the command line, which isn't JIT'ed yet)... But I take it hyPirion is right about the REPL trade-off between startup time / execution time

8:04 hyPiRion: you could check it out

8:04 btcNeverSleeps`: that is very interesting : )

8:14 * btcNeverSleeps` will brb

8:18 btcNeverSleeps: indeed, I added ":jvm-opts []" to my defproject in project.clj and now the timing are identical

9:32 thesaskwatch: Mikalv: well, why the global dependency then?

9:32 Shouldn't ./node_modules/.bin/gulp just work?

10:31 btcNeverSleeps: ,(defn boo [x] {:pre [> x 3]} x)

10:31 clojurebot: #'sandbox/boo

10:31 btcNeverSleeps: ,(boo 1)

10:31 clojurebot: 1

10:32 btcNeverSleeps: ,(boo 7)

10:32 clojurebot: 7

10:32 btcNeverSleeps: ,(true? *assert*)

10:32 clojurebot: true

10:32 btcNeverSleeps: Why is is no exception raised because of pre-condition failure? *assert* is true

10:35 qbg: ,(defn boo [x] {:pre [(> x 3)]} x)

10:35 clojurebot: #'sandbox/boo

10:35 qbg: ,(boo 1)

10:35 clojurebot: #<AssertionError java.lang.AssertionError: Assert failed: (> x 3)>

10:36 qbg: Does that help btcNeverSleeps?

10:36 btcNeverSleeps: qbg: Lisp! Forgot parentheses! What problem cannot be solved with more (or less) parentheses ^ ^

10:37 qbg: using brackets instead of parentheses :p

10:37 btcNeverSleeps: :)

10:45 speckle: wow, this channel is bigger than ##java

10:45 AimHere: ##java has registration demands to keep out the riff raff. Clojure actively welcomes riff-raff

10:47 speckle: Ah, now it all makes sense

10:49 btcNeverSleeps: ouch

10:49 ,(defn ok [] {:pre [(true? false)]} 42)

10:49 clojurebot: #'sandbox/ok

10:49 btcNeverSleeps: ,(ok) ; so far so good

10:49 clojurebot: #<AssertionError java.lang.AssertionError: Assert failed: (true? false)>

10:49 btcNeverSleeps: ,(defn nok [] "" {:pre [(true? false)]} 42)

10:49 clojurebot: #'sandbox/nok

10:49 btcNeverSleeps: ,(nok)

10:49 clojurebot: 42

10:50 btcNeverSleeps: Putting the comment / doc using "" before the {:pre ...} makes the precondition silently being not executed !?

10:50 qbg: ,(defn nok "" [] {:pre [(true? false)]} 42)

10:50 clojurebot: #'sandbox/nok

10:50 qbg: ,(nok)

10:50 clojurebot: #<AssertionError java.lang.AssertionError: Assert failed: (true? false)>

10:50 qbg: doc string always comes before the arguments vector

10:50 btcNeverSleeps: I kinda get it but... What did my "nok" do?

10:51 qbg: It is a function with three body forms

10:51 "", {:pre [(true? false)]}, and 42

10:51 btcNeverSleeps: oh right, because a map is a fn

10:51 that's a bit tricky :)

10:52 qbg: doc strings always come before argument vectors because you can have a function with different arities

10:52 btcNeverSleeps: qbg: thx a lot for the help with my riff-raff'ing : )

10:52 qbg: and there is a shared doc string for all of them

10:52 btcNeverSleeps: qbg: I see

10:53 qbg: ,(defn foo "Hello, world!" ([] 0) ([x] x))

10:53 clojurebot: #'sandbox/foo

10:53 qbg: ,(foo)

10:53 clojurebot: 0

10:53 qbg: ,(foo 5)

10:53 clojurebot: 5

10:55 qbg: ,(doc foo)

10:55 clojurebot: "([] [x]); Hello, world!"

11:02 gtrak: tpope: got jump-to-def working, still waiting on patches to piggieback/cljs itself, but you can try it.

11:24 nickik: {:op :vector,

11:24 :env {:ns {:name cljs.user}, :locals {}},

11:24 :form [1],

11:24 :items

11:24 [{:tag number,

11:24 :op :constant,

11:24 :env {:context :expr, :ns {:name cljs.user}, :locals {}},

11:25 :form 1}],

11:25 :children

11:25 [{:tag number,

11:25 :op :constant,

11:25 :env {:context :expr, :ns {:name cljs.user}, :locals {}},

11:25 :form 1}],

11:25 :tag cljs.core/IVector}

11:25 Who does it have :items and :chidren is this not always the same?

11:31 voldyman: nickik: protip: https://www.refheap.com

11:41 mzdravkov: How can I get the first element from an infinite seq that satisfies some condition?

11:42 ,(doc some)

11:42 bbloom: nickik: all AST nodes have :children even if they aren't collections that also have :items. look at the analyzer output of an 'if form for example

11:42 clojurebot: "([pred coll]); Returns the first logical true value of (pred x) for any x in coll, else nil. One common idiom is to use a set as pred, for example this will return :fred if :fred is in the sequence, otherwise nil: (some #{:fred} coll)"

11:43 nickik: @bbloom I see that. But why, is the question. If for example has all elements allready saved in other keys :test and so on.

11:44 Most seam to do that.

11:44 qbg: mzdravkov: If you need to be able to find false or nil, you can use a combination of first and filter

11:47 mzdravkov: the problem is that some returns true or false (or the searched element if used with set), but I don't know what the searched element is. I want to take the first rand-int that is even for example.

11:47 bbloom: nickik: the goal, which i don't think we've succeeded in accomplishing, is to support generic traversals over unknown node types. ie future proofing analyzer output consumesr

11:47 nickik: there's a far bit of discussion about it on the mailing list and here in irc between myself and dnolen among others, if you search the logs

11:47 mzdravkov: qbg: filter on infinite seq? am I missing something? :)

11:47 qbg: filter returns a lazy seq

11:48 egghead: mzdravkov: if you ask for the first that satisfied a condition you are asking to exhaust the list until that condition is met

11:48 nickik: @bbloom Ok, I see. This are on clojure-dev? I will have to look for them.

11:48 mzdravkov: ok, first and filter did the wokr, thanks a lot :)

11:48 qbg: ,(first (filter even? (repeatedly #(rand-int 10))))

11:48 clojurebot: 6

11:48 bbloom: nickik: start here: http://dev.clojure.org/display/design/AST+children

11:49 nickik: I am plaing to compile the ast to a bytecode (witch I design) and I will then write a interpreter for that bytecode.

11:49 Thank you

11:49 bbloom: nickik: cool. may i ask what your goal with the byte code is?

11:50 nickik: @bbloom the main goal is to learn how to write a tracing jit compiler

11:50 bbloom: nickik: sounds like a fun project :-) feel free to stop by here for help, there are a number of clj & cljs analyzer & codegenerator experts that hang out here

11:51 borkdude: what is riff-raff?

11:51 nickik: So the first state of the project is designing a bytecode, second a ast to bytecode compiler, third writing a interpreter

11:51 then trace compiler :)

11:51 qbg: borkdude: disreputable or undesirable people.

11:52 bbloom: nickik: won't be easy, but should be pretty straightforward. good luck!

11:52 nickik: @bbloom Maybe you can answer me this, is the tools.analyzer used in cljc?

11:52 or are those diffrent projects

11:53 bbloom: nickik: i don't know anything about cljc, but tools.analyzer is part of Bronsa's ongoing effort to write clojure-in-clojure

11:53 nickik: This project (or a version of it) has been in the back of my head for 5 years and now I started.

11:53 bbloom: nickik: tools.emitter.jvm is also a good place to look

11:53 nickik: it generates jvm bytecode

11:55 nickik: I am still at the stage of just getting tools.analyzer to work for me but I will defently talk a closer look at tools.analyzer.jsm and emitter.

11:55 bbloom: nickik: have you written a byte code interpreter before?

11:56 nickik: @bbloom No. Not really.

11:56 bbloom: nickik: then you may want to start smaller: you can create your own lisp with fewer special forms and tricky edge cases

11:57 nickik: Me and a friend worked on another bytecode interpreter for a short time but we did not finish the project for other reasons

11:57 bbloom: My goal is not to have full clojure. If something is to hard I will just cut it out.

11:58 bbloom: nickik: that's a good mentality for learning: forward progress at all costs :-)

11:58 nickik: Also I work with a friend wo allready wrote compilers and is smarter then me.

11:58 bbloom: nickik: that always helps too

11:58 nickik: If you have comments see: https://github.com/nickik/clojit/blob/master/Bytecode%20Spec.md

11:59 qbg: luckily interpreters aren't that hard unless you make them that way :)

11:59 And a trivial non-optimizing compiler isn't much harder than an interpreter

12:00 nickik: I prefer the model of LuaJit to V8. Interpreter first then one jit instead of 2 jits.

12:00 I will however not write the interpreter in assembly :)

12:01 bbloom: nickik: i haven't written a jit myself (yet) but i've written lots of interpreters and a few small compiler thinggies

12:01 qbg: What language are you doing to do the interpreter in?

12:01 bbloom: right1: but i agree, having an interpreter on hand is just a good idea in general

12:01 whoos tha twas for nickik ^^

12:01 right1: :(

12:01 nickik: We wanted something low level enougth but not C. So we are currently thinking of using Rust

12:02 To get some more safty and GC

12:02 What are you going to JIT down to?

12:02 assembly?

12:03 nickik: Im just afraid of using C, because getting the general logic right will be hard enougth I dont want to also run into to many memory issues.

12:03 Yes that is the plan.

12:03 qbg: Are you going to write your own gc too then?

12:03 nickik: Maybe LLVM but Im not sure how well this works. This is something we have to learn more aobut.

12:04 At first everything will be rust GC pointers, I dont want to write a GC.

12:04 Maybe in the future.

12:04 There are some GC one could use MPS or Boehm

12:05 bbloom: nickik: may i suggest simply writing your own "GC" where the GC basically allocates linearly and never collects?

12:05 nickik: turns out you can do a surprising amount of real work with the null garbage collector :-P

12:05 nickik: Instead of using Rust GC pointers?

12:06 bbloom: yeah

12:06 nickik: I will keep it in mind.

12:06 We are yet far away from that beeing a factor.

12:06 bbloom: you might find that interop with another system is harder than just writing a naive GC yourself... and you write the ULTIMATE naive GC, whose collection strategy is exit(1)

12:07 qbg: Just write crash tolerant programs and crash when you run out of memory :)

12:09 nickik: qbg, maybe writing a collecting gc is easier then writing crash tolerant programs :)

12:10 gko: Hello, I'm "proxy"-ing some class, but when I call one of its (Java) methods, I have a "No matching method found: " exception...

12:11 The methods should be available, right?

12:15 qbg: Are you calling the method from within the proxy?

12:15 or outside of it?

12:18 gko: Inside

12:19 Here is the class: http://i1.dk/JavaDiameter/doc/ -> NodeManager

12:19 I proxied NodeManager

12:19 Bronsa: gko: can you nopaste the proxy?

12:20 gko: and within a Clojure-defined handleRequest, I call answer with (.answer this msg connkey)...

12:20 Bronsa too big

12:20 Here's the top:

12:20 (defn new-node-manager [node_settings]

12:20 (proxy [NodeManager] [node_settings]

12:20 ....

12:20 nopaste url?

12:21 Bronsa: gko: use https://www.refheap.com/

12:21 gko: O

12:24 Is it because of "protected" ?

12:26 wei__: anyone have a more elegant way of writing this? (defn take-only [n coll] (let [c (take n coll)] (when (= (count c) n) c)))

12:27 basically take N only if the collection has enough elements, nil otherwise

12:27 qbg: Note that while method fns can

12:27 be provided to override protected methods, they have no other access

12:27 to protected members, nor to super, as these capabilities cannot be

12:27 proxied.

12:27 gko: there is your answer from the doc string of proxy

12:29 AmnesiousFunes: Is there a paredit command to move the cursor up to the top level? I can't seem to find one

12:33 Ah, nevermind; found it.

12:35 gko: qbg Thanks. It seems that if I override it (answer), it doesn't work too... So, I can't call it (Clojure's .answer) from Clojure.

12:36 Fortunately, original "answer" is just node.sendMessage(msg, connkey) :)

13:06 andyf: Perhaps the new Clojure 1.6 vars should be named bikeshed? if-bikeshed when-bikeshed (this is just blowing off steam -- I do care about names, just not so much as the people talking about this)

13:08 r0b1: andyf: how many bikes can u fit in this shed

13:34 srruby: Anyone have discount codes/tickets for ClojureWest ? (I'm paying out of my own pocket FYI).

13:56 qbg: Om question for anyone that can answer it

13:57 Shouldn't (om/update! cursor v) be the same as (reset! app-state v) if the cursor points at app-state?

13:58 * qbg wonders if dnolen_ is around

14:00 mp: hi. is it ok to ask seesaw questions here?

14:03 r0b1: yeehaw

14:17 ambrosebs: first version of typed clojure mode for emacs https://github.com/typedclojure/typed-clojure-mode

14:21 mdeboard: ambrosebs: Huh, nice

14:27 DomKM: Does anyone here have experience using JRuby from Clojure? I'm working on Clojure library that wraps a JRuby-compatible gem and I'm looking for some guidance.

14:44 unsymbol: DomKM: only a super small amount of experience because it was incredibly easy. what you got in mind?

14:46 borkdude: ambrosebs what am I doing wrong? https://gist.github.com/borkdude/e97c0cfc8644529053ac

14:49 DomKM: unsymbol: I'm wrapping the ruby whois library (ruby-whois.org) since there don't seem to be any good whois libs for Java. It's a pure ruby lib, compatible with jruby, and has no dependencies. I'm wondering whether I should try to figure out how to precompile it to class files (and if so how?) or use it from zweikopf (https://github.com/ifesdjeen/zweikopf)?

14:49 I don't actually know if those two approaches are mutually exclusive. Anyway, if the latter (which is what I'm currently doing), I can't figure out how to extend the Clojureize protocol to a custom ruby class since its java class is always org.jruby.RubyObject.

14:49 sorry for the wall of text, everyone

14:54 TravisD: Does anyone here have experience with the Incanter library for scientific computing?

14:55 amalloy: ~anyone

14:55 clojurebot: Just a heads up, you're more likely to get some help if you ask the question you really want the answer to, instead of "does anyone ..."

14:57 borkdude: TravisD There is a book that goes into depth with this

14:58 TravisD Clojure Data Analysis Cookbook

14:58 TravisD: Ah, hehe, I guess that makes sense. I was going to ask if it is the best choice

14:59 borkdude: TravisD it is Incanter-focussed as far as I can see. I think the only one?

14:59 TravisD: There are some other libraries like clojure-numerics and HipHip

15:01 borkdude: TravisD yes, but you asked for incanter specifically, so ;)

15:01 TravisD: Hehe, yeah, I was wondering if it was the best choice for doing numerical computing in clojure. Sorry, I was pretty unclear

15:03 amalloy: i know nothing about the field, but i would pick incanter

15:03 TravisD: yeah, seems to be pretty well polished

15:04 amalloy: core.matrix is probably worth a glance at

15:08 AeroNotix: Does clojure have any "easy-pickings" tickets I can get my feet wet with contributing?

15:10 jro_: why (doseq [i .. j .. large ranges] do side effecting stuff with i j) much decades slower than (loop [i.. (loop j.. -construct?

15:10 is there higher level constructs to manipulate arrays, that does not suffer performance hit.

15:11 qbg: jro_: Try (nested) dotimes

15:11 jro_: ok, thanks.

15:11 AeroNotix: qbg: congratulations on understanding that sentence

15:12 qbg: seq creation is not free, so doseq will have a perf hit

15:12 jro_: sorry about the language

15:13 should be "is about ten-time slower".

15:13 jro_: hrm. Just a mistake.

15:14 AeroNotix: Oh, ok

15:18 paulswilliamsesq: ambrosebs: hi - remember my question about java.awt.Frame yesterday - well, here's an update: http://stackoverflow.com/questions/21803419/clojure-let-frame-java-awt-frame-within-un-invoked-function-causes-awt-to

15:26 pcn: hey, is there a common practice to save performance metrics w/ clojure? I want to receive a lot of messages, then write them out, and then maintain counters for them that are periodically collected, and reported on.

15:28 AeroNotix: pcn: graphite?

16:12 seangrove: I'm looking for a clean way to have a default catch-all for a defmulti without the defmulti knowing about what's implemented and what isn't

16:12 I would like to be able to lazily implement specific behaviors and have them called if available, really

16:42 AmnesiousFunes: Is there any common case where a top form would be formatted to start at a non-zero column, i.e. already indented?

16:53 amalloy: no

17:56 TravisD: Is there better support for clojure in emacs than clojure-mode?

17:58 llasram: TravisD: cider?

17:59 bob2: TravisD, what do you want to be better?

17:59 cider works with clojure-mode

17:59 TravisD: mostly I was hoping for some code completion and automatic error checking

18:00 bob2: code completion you get with https://github.com/alexander-yakushev/ac-cider-compliment

18:00 what do you mean by 'automatic error checking'?

18:00 flymake?

18:00 TravisD: yeah

18:01 bob2: haven't been able to find a thing for that yet, but C-c C-l will underline errors

18:01 TravisD: ah, alright, thanks :)

18:01 (in cider that underlines errors?)

18:03 bob2: it's related to cider

18:32 akurilin: Random question: do any of you guys have experience implementing caches in web applications? So say you're backed by a SQL store, but you have pretty large tables and now you want to speed it up. Do you just manually implement "paging" against redis, kind of like what your OS would do for disk?

18:34 qbg: I've implemented in memory caching of domain level queries before

18:39 Correctness is the hardest part

18:41 akurilin: So we're talking about: write and read as much as possible from cache, write-back to disk every x seconds, evict pages that are not as popular as the other ones?

18:41 qbg: w.r.t. the world changing behind your back that is

18:41 akurilin: Oh yeah, what I said would assume that you only ever touch the cache, but yes, if you change what's in the store that's bad :(

18:41 qbg: The data I was caching was query only

18:42 but was in the store would change periodically

18:42 Luckily I was in control of the process that changed the data in the store too

18:42 So I could make it obvious to the application that the data changed

18:43 and dump the caches appropriately

18:44 How many instances of your app are you going to have running at once against the same store?

18:46 akurilin: Right now one, but that's probably not going to last for too long, might need to add a second / third ones soon as the load goes up.

18:46 Right now I was doing some caching locally with atoms under the assumption there'd be one instance, but it sounds like once you have 2+ you need a shared redis instance or something like that

18:48 Talking to redis over the network in EC2 should still be faster than having Postgres query against a large table.

18:48 aphyr: (protip: you can probably cache more in a multithreaded JVM heap than in a singlethreaded redis node on the other side of a flaky network connection)

18:48 akurilin: Although I could be 100% wrong without actual test numbers.

18:48 qbg: Have you made sure that your SQL design is good?

18:48 akurilin: qbg: No.

18:49 qbg: If you can get that to be fast enough, then your job becomes easier

18:49 aphyr: (additional protip: avoid caching layers if users will later write cached data back to the DB)

18:49 (begging for race conditions and data inconsistency)

18:50 akurilin: aphyr: makes sense, I'm just starting to dip my toes into this.

18:50 qbg: my problem is that I know basic SQL to get away with small-sized projects, but I've definitely not had to work with SQL once its tables start to hit billions of rows

18:50 So I'm learning as I go.

18:50 Damage controlling :)

18:51 qbg: How frequent are writes?

18:52 akurilin: Well, during the schoolday our kids dump maybe 30 rows every 3 mins. We have 10k of these kids, soon 100k..

18:52 This is during the hot hours, it's pretty much a wasteland in the evening.

18:52 qbg: 30 rows per kid, or total?

18:53 akurilin: At the same time teachers/admins run a bunch of analytics math against the data set and want to get stats/visualizations.

18:53 30/kid/3mins

18:53 aphyr: akurilin: use indexes; use real hardware; use foreign key constraints; avoid redundant indices; use secondary spares for offline analytics; hire a DBA or take a course.

18:54 Definitely easier to improve mysql or postgres performance than to try and reason about distributed cache safety.

18:54 akurilin: aphyr: it's like bitemyapp is whispering that in your ear :P

18:54 What's offline analytics out of curiosity? Pre-computing results?

18:55 aphyr: "teachers/admins run a bunch of analytics"

18:55 If that's expensive, run it on a separate node with a copy of the data.

18:55 Use async replication from the primary node if consistency isn't critical.

18:56 akurilin: aphyr: got it, makes sense. How far can I take this?

18:56 aphyr: millions of ops/sec should be readily achievable, depending on transaction contention/complexity.

18:57 akurilin: I guess the big boys eventually start shelving the old data into separate storages, right?

18:57 Most indices are tree-structured; costs go up logarithmically with data volume.

18:57 But there are some linear costs.

18:57 (disclaimer: I am not a database expert)

18:58 akurilin: I think PG's btrees were log32, so it should go a long way.

18:59 qbg: but yes what you were saying is probably my biggest concern: that my schema is deeply inefficient and I could be having a much easier time.

18:59 qbg: correct

18:59 akurilin: Back at my previous gig we got really screwed over by giant joins and it was a disaster until we brought over a real DB person.

19:00 aphyr: Yep. Probably easier to learn a bit of DB theory and tuning than to write your own distributed caching system.

19:00 qbg: no need to reinvent the wheel

19:00 especially when the current one is battle tested

19:00 akurilin: aphyr: well there's DB theory and there's "giant DB tables theory", which I can't seem to find anywhere

19:00 I guess there's "use the index luke" which I really need to finish going through.

19:00 but it felt pretty entry-level.

19:01 Also I powered through High Performance Postgres 9 a few months ago, but that's mostly about tuning for your hardware, which I did

19:01 even though ironically I'm on EC2, so it sucks balls anyways.

19:02 aphyr: do you have a favorite bare metal provider? I hear good things about softlayer

19:02 qbg: do you have any real hardware?

19:02 qbg: we got 15 grand of AWS credits through our incubator/coworking space so we're burning through that for now.

19:02 aphyr: Softlayter's good.

19:02 Yeah, get the heck off EC2.

19:03 Expect a 10x speedup just for using real hardware.

19:03 akurilin: qbg: but I'm not actually hard-wiring myself against anything AWS-specific, everything's portable thanks to ansible.

19:03 aphyr: I've been benching various DBs on EC2 for the last few months; bottom line is they're all terrible until you start spending about 15 grand/mo, and even then they're not great.

19:04 The i2 instances are the only ones even beginning to approach what I'd call "acceptable" IO perf.

19:04 akurilin: aphyr: in your experience, is the fact that we're pretty much only at full capacity during the day and totally dead the rest of the time, deserving of an "auto-scaling" solution?

19:04 aphyr: I mean, you gotta do the math

19:05 but if you're running machines half the day, and you can get 2x perf/price somewhere else, it's equivalent.

19:05 akurilin: aphyr: I remember reading a Parse.com report where they mentioned having to move to the SSD instances with reserved throughput and the 2nd IO channel for EBS and getting the largest RAM machines.

19:05 So I can see them blowing through a TON of cash on AWS.

19:05 aphyr: EBS with provisioned IOPS: expensive, also terrible.

19:05 Pretty much the only decent IO I've gotten has been with insane raid0 setups across piops ebs, or with SSD instance storage.

19:05 Either way you'll pay about 10x more than the HW itself on a 3-year cycle.

19:06 akurilin: We like perf, we like money, and we like not having to overengineer to make it happen.

19:06 aphyr: You can build a 128-GB 48-core 10TB SSD box for ~12K.

19:06 Or you could rent those boxes for ~4k/mo

19:07 also the virtualization imposes some pretty gross hits on app performance

19:07 HVM is definitely better than paravirt, but it's still noticeable.

19:08 Yeah, just set up a softlayer acct. They run specials; use 'em.

19:08 akurilin: Hmm what am I going to miss from AWS?

19:08 aphyr: A horrible web UI?

19:08 akurilin: I like their VPC

19:08 aphyr: (I jest)

19:08 akurilin: :P

19:09 aphyr: Naw, they're totally different beasts.

19:09 But IMO it's less work ordering HW through SL than trying to fight the AWS APIs.

19:09 If you get to larger scale, AWS automation becomes more efficient, but the costs become proportionately larger.

19:10 akurilin: aphyr: so this is pretty much 100% "you don't use CM to check-out boxes and deploy on them". As in: you have boxes pre-allocated for you that might take days to get set up and you just deploy to them.

19:10 aphyr: Yeah, I mean, capacity planning is a thing

19:10 monitor your latencies, disks, etc.

19:10 akurilin: Heh.

19:10 aphyr: same as you do on EC2.

19:10 Just plan on 6 hours to 3 days of lead time.

19:11 Since the boxes are so much less expensive, just buy better HW and let it sit idle.

19:11 akurilin: And you can't go "oops one instance died, I'll spin another one up in 15 mins"

19:11 aphyr: Yeah, EC2 is definitely less reliable.

19:11 SL boxes do go bad, but at a significantly reduced rate in my experience.

19:11 I usually see ~30% of my EC2 nodes fuck up in some way.

19:12 SL, I think we had to cycle maybe 4 boxes out of 50 over a couple years?

19:12 YMMV; I use a lot more IO than most people.

19:13 Seriously though, may be cheapest just to hire a DBA for a few days to look over your schema.

19:14 1000x perf improvements are not unheard of, haha

19:14 "Oh, this table has no primary key", that sort of thing.

19:14 akurilin: Interesting. Well I do enjoy me a good EXPLAIN ANALYZE so I can certain optimize based on that, and I have logging in place for when certain queries go over xms

19:15 But that's a great idea for once we actually have money to pay experts for advice :)

19:15 So that's a point well-taken.

19:16 aphyr: books are also available.

19:16 though mysql optimization is out of my depth so I can't give you much specific feedback there. :(

19:16 akurilin: If you know of good ones I'm all ears.

19:16 bob2: are you using percona

19:17 akurilin: I've been looking for books on web app architecture for a while and I can't find anything good

19:17 everything's based on folklore

19:17 bob2: what's that?

19:17 bob2: a fork of mysql that's significantly less crap

19:18 akurilin: bob2: I've been pretty happy with PG so far, no complaints. I do hear that replication is hard though.

19:18 gtrak: technomancy: is there a way to load a lein-plugin at command-line time?

19:19 bob2: oh, I thought aphyr said you were using mysql

19:20 gtrak: ah, I see the 'lein plugin' command is dead. Would be convenient for cider :-)

19:23 muhoo: bob2 btw, you wouldn't happen to be the bob2 from #debian?

19:24 bob2: long ago

19:24 muhoo: aye

19:26 pcn: AeroNotix: sorry, I was afk for a bit.

19:28 Sure, graphite is an answer for "how do I display the metrics" the e.g. using codahale/metrics in plain java lets me annotate functions and have the info about the # of invocations, time taken, etc. recorded and quantized etc. in the program

19:28 Much more scalable

19:29 OK, it looks like there are a few wrappers for codahale/metrics

19:29 bob2: take that, disks

19:29 aphyr: pcn: https://github.com/aphyr/interval-metrics might be oof interest

19:37 pcn: aphyr: thanks, that may be more than what I was asking about, which is very cool. What led you to this set of features?

19:44 aphyr: http://riemann.io

19:48 muhoo: btw, timbre is awesome

20:01 pcn: timbre does look useful

20:01 gtrak: aphyr: I hope it's no big deal I'm slacking on merging the no.disassemble PR :-) been sidetracked.

20:03 just thought about it now b/c I've been working in cider, considering a 'disassemble' nrepl op :-).

20:04 because why not

20:07 aphyr: cool!

20:33 muhoo: hmm i'm trying to load some data in -main, running from lein with :injections, and i'm getting the most bizarre error: java.lang.IllegalArgumentException: Parameter declaration log/info should be a vector

20:34 log/info is the first call inside -main

20:34 um, and it doesn't seem to matter what function, the first function in -main fails with "Parameter declaration foo should be a vector"

20:35 TravisD: Is there a good book that introduces clojure? I'm thinking of picking up a copy of "The Joy of Clojure", but I'd like to see if there's a better buy first

20:35 bob2: muhoo, did you forget an arg list for -main

20:35 muhoo: TravisD: joy is good, also clojure programming (oreilly) if you're looking for more practical

20:35 bob2: DOH thanks

20:35 bob2: TravisD, joy of clojure is not an intro, aside from a very fast tutorial in chapt 2

20:36 "clojure programming" (the o'reilly one) is quite good

20:36 TravisD: bob2: Ah. I'm a bit familiar with scheme and FP in general. Do you think joy of clojure is not appropriate to read first?

20:36 AmnesiousFunes: TravisD: I agree with bob2. Clojure Programming is quite good.

20:36 bob2: don't know

20:37 I have both

20:44 AmnesiousFunes: TravisD: As a concise introduction, Programming Clojure is also good. I'd suggest to at least check out a free chapter; Clojure is a bit quirky as far as LISP goes, and there are a few things you might know from elsewhere (e.g. STM)

20:45 *not know from elsewhere

20:45 TravisD: AmnesiousFunes: Ah, thanks I'll take a look :)

20:49 AmnesiousFunes: TravisD: There's also a free book at http://www.braveclojure.com/, but I'm not familiar with it

20:50 TravisD: cool, thanks :)

20:50 AmnesiousFunes: and the Clojure Koans as a sequence of exercises: http://clojurekoans.com/

21:06 gfredericks: is it weird that clojure.core/not doesn't have an inline version?

21:06 bob2: inline?

21:11 gfredericks: ,(source +)

21:11 gfredericks: &(source +)

21:11 lazybot: java.lang.RuntimeException: Unable to resolve symbol: source in this context

21:11 gfredericks: &(clojure.repl/source +)

21:18 amalloy: ~def +

22:07 Tolstoy: (d/create-database "datomic:mem//my-db") => ClassCastException clojure.lang.PersistentArrayMap cannot be cast to datomic.db.IndexSet datomic.db.Db (db.clj:1733)

22:09 Maybe it's the 1.6 beta.

22:16 Yep. Dataomic is broken for clojure 1.6.0-beta1.

22:16 gtrak: sounds like an AOT compilation issue

22:17 did it work for the alphas?

22:17 Tolstoy: No idea. Just tried it.

22:17 I'm just using a repl: no AOT compilation that I know of.

22:17 gtrak: datomic itself would be aot compiled

22:18 Tolstoy: Ah.

22:19 Is there a Jira (or something) for Datomic?

22:20 gtrak: there's a mailing list

22:21 Tolstoy: Alas, no one else seems to have had the problem.

22:47 pcn: I'm looking for a way to make input validation less painful. Has anyone used https://github.com/leonardoborges/bouncer for this sort of thing?

22:48 buffer graphite

22:48 whoops, switching fail

23:27 xensky: can anyone advise me on using multimethods to dispatch over multiple values? i'm having trouble with it

23:29 bob2: you mean on functions taking different numbers of arguments?

23:30 xensky: no, not arity specifically

23:30 i have a multimethod that i want to dispatch over two values

23:30 i tried to dispatch over an array [val1 val2] and that dispatches fine

23:31 bob2: so, on types?

23:31 xensky: but i can't figure out how to dispatch over defaults, to fall back when a method only matches one of the vals

23:31 in my case it won't be dispatched on the types of the values, they'll be constants like keywords or strings

23:46 dsrx: huh, are java strings interned

23:46 ,(identical? "foo" "foo")

23:46 clojurebot: true

23:46 amalloy: dsrx: some of them

23:46 string literals in java source code are guaranteed to be interned, and you can intern others if you want

23:47 i don't know if clojure guarantees to intern literals

23:47 dsrx: ah, guaranteeing it for literals makes sense

23:47 amalloy: probably does, though, since i think they go into the constant pool

23:47 Wild_Cat: that's an implementation detail, really

23:47 you shouldn't rely on it

23:47 dsrx: I'm not planning to rely on this

23:48 Wild_Cat: but yeah, it makes sense to intern literals of immutable object types

23:52 amalloy: Wild_Cat: i mean, clojure probably does guarantee it

23:53 Wild_Cat: actually, is there a Clojure language spec?

23:58 xensky: i found a work-around for my defaulting problem. revised question: can i dispatch a multimethod on variable arity?

Logging service provided by n01se.net