#clojure log - Jan 10 2014

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

0:05 amalloy: ##

0:05 or a single & at the start of the message

0:05 rplaca: amalloy: why not write a macro to flip the let around? I don't think that would be too hard and it would be way more obvious to the reader what you were trying to do

0:05 amalloy: rplaca: i'm not excited about actually using this where construct, with the ->> trick or with a real macro

0:06 just surprised to note that clojure could easily fake where "out of the box"

0:06 rplaca: amalloy: there's always that. It does seem nice in Haskell, but I'm not sure it would work (mentally) in Clojure

0:07 amalloy: rplaca: the problem with a where macro in clojure is that syntactically it can't come in the same place it does in haskell

0:07 you have to write (with-where (+ x y) (where [x 1 y 2])) or something equally horrific

0:07 Wild_Cat: Haskell's where is a very postfix-ish contruct

0:07 rplaca: true, since you need a toket in the function position

0:07 *token

0:07 amalloy: and ->> neatly fills that role

0:07 arrdem: damnit. Do "we" have any details on Clojure/west yet?

0:08 Wild_Cat: I think Clojure's standard "let" form is far cleaner.

0:08 amalloy: of course

0:08 rplaca: arrdem: last I heard, Alex was finalizing arrangements

0:08 amalloy: although haskell's works well in haskell

0:08 rplaca: amalloy: +1

0:08 arrdem: rplaca: awesome. we have a place and date.

0:08 (inc rplaca)

0:08 lazybot: ⇒ 1

0:08 Wild_Cat: in Haskell though, where feels more natural than let.

0:09 rplaca: arrdem: I think it's going to be SF. That's what ALex told me last I asked him about it, but that was back around the conj

0:09 dunno the dates

0:09 arrdem: rplaca: yep.

0:09 March 24->26

0:09 rplaca: ahh, cool

0:10 arrdem: which means that I can apply to get funding from the Department to come out :D

0:10 rplaca: I was hoping we'd do Portland again, but I guess I can't complain too much about SF

0:17 bitemyapp: Wild_Cat: partly because it lets you say upfront what you're going to return, overall, then where lets you describe how that got put together.

0:19 seancorfield: The Palace Hotel is really nice - MongoSF was there in 2013

0:22 logic_prog: dnolen: someone needs to write a core.async cookbook

0:22 dnolen: of all the pattenrns that (1) are hell with callbacks and (2) have really neat core.async solutions via csp

0:24 bbloom: amalloy: thanks! that msg is more for dnolen

0:24 amalloy: bbloom: i sent it to you because you're the one who committed the code

0:24 but hey, if it's for him, let him know

0:24 bbloom: amalloy: really? i did?

0:25 amalloy: bbloom: https://github.com/clojure/clojurescript/commit/af4ab91754d30f082b117b40c07ea94d0063c0d6

0:25 bbloom: amalloy: oh hey, i did.

0:25 look at that, lol

0:26 amalloy: is there a ticket?

0:26 amalloy: not as far as i know

0:26 bbloom: i've been drinking & am gonna wonder away from my desk now, but i don't want your bug report to go missing :-P

0:26 amalloy: seangrove just pasted a stacktrace of breakage, and i tracked it down to this code for him

0:27 bbloom: amalloy: thanks

0:27 amalloy: if you or seangrove can open a ticket, that would be awesome. sorry i can't be more help now. thanks!

0:28 seangrove: bbloom: Enjoy your drinking!

0:55 ddellacosta: really confused by this exception: Exception in thread "main" java.lang.IllegalAccessError: get-header does not exist, compiling:(not_modified.clj:1:1) <-- seems to be referring to ring.middleware.not-modified, which refers to ring.util.response/get-header. What could be causing this? Full exception: https://www.refheap.com/22750

0:58 rplaca: seancorfield: is ClojureWest going to be at the Palace or are you just saying it would be good there?

1:01 TEttinger: ddellacosta, that's odd https://github.com/ring-clojure/ring/blob/master/ring-core/src/ring/util/response.clj it is defined right?

1:02 seancorfield: rplaca: look at the clojurewest.org website

1:02 it lists the hotel and dates

1:02 ddellacosta: TEttinger: yeah. I'm poking around lein reps now...think it's probably something in a specific profile that's conflicting...older version of ring maybe?

1:02 seancorfield: oh, actually the website doesn't say... but alex's announcement on the mailing list did

1:02 TEttinger: https://github.com/ring-clojure/ring/commit/52c11854f6050a2a4a9261c6e77acf265b0b194e#diff-84b6775eb77642c1afe9b5745af47a2f

1:03 ddellacosta, that commit, 10 months ago, added it

1:03 ddellacosta: TEttinger: huh, surprised it was even that recent

1:04 TEttinger: it's present in 1.2.0

1:05 (and everything newer)

1:05 ddellacosta: TEttinger: pooh, I figured it out...include from another private project of ours. Nevermind :-p

1:05 pooh -> ooh

1:05 seancorfield: rplaca: here you go: https://groups.google.com/forum/#!topic/clojure/HaZVWRiDEAM ;; Clojure/West announcement

1:05 ddellacosta: damn spellcheck

1:06 rplaca: arrdem: did you see that post from seancorfield - that's the pointer you were looking for

1:07 seancorfield: you're on the bleding edge there - I'm not keeing up with the list that well these days :)

1:07 *bleeding, keeping

1:07 thanks!

1:07 I like that choice, cause I can walk to it from my house.

1:08 seancorfield: I can walk to BART and ride that to SF :)

1:08 And it is a *lovely* venue!

1:09 I'd submit a topic proposal but I'm already committed to creating two new presos for conferences in May / June :(

1:10 rplaca: seancorfield: I'll have to think about whether I've got something worth submitting

1:12 xpika: The function read-string reads a single form. Is there a core clojure function that reads multiple forms like those in a .clj file?

1:28 sm0ke: how does one writes a recursive macro?

1:29 i am trying to write on with top level form as 1()

1:29 `() *

1:32 ,(defmacro weird-macro [&body] `(~@body (weird-macro)))

1:32 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: body in this context, compiling:(NO_SOURCE_PATH:0:0)>

1:32 sm0ke: ,(defmacro weird-macro [& body] `(~@body (weird-macro)))

1:32 clojurebot: #'sandbox/weird-macro

1:32 sm0ke: ,(weird-macro (inc 1))

1:32 clojurebot: #<CompilerException java.lang.StackOverflowError, compiling:(NO_SOURCE_PATH:0:0)>

1:33 sm0ke: oh did that worked!

1:46 arrdem: rplaca: thanks to insomnia I just did :D

2:52 andyf: bitemyapp: I saw in the logs a mention of a desire for eastwood to complain about :use

2:58 bitemyapp: andyf: yes

2:59 andyf: I am guessing no warnings are desired for a use with :only, only for a use that sucks in the whole namespace?

3:06 arrdem: andyf: personally I would object to any use of (use) over (requrire), but silencing a linter with :only is I suppose reasonable.

3:07 andyf: arrdem: I'd prefer to warn about the most dangerous uses only, in hopes that people will avoid just turning off those warnings.

3:08 arrdem: You don't even do (;use clojure.test) in your test namespaces?

3:08 arrdem: andyf: nope. I actually sumitted a patch to the lein template which replaces that (use) :P

3:09 only useful patch I've got live anywhere but so be it.

3:09 andyf: arrdem: So you :require :refer [is] ?

3:09 arrdem: andyf: yep.

3:09 andyf: occasionally I'll do a :refer :all if I know what I'm doing, but it's something I try to avoid.

3:14 mark_oz: hey guys, I'm having a bit of a problem with pulling a symbol from a map https://gist.github.com/markgandolfo/5adf492f5ad12d8af322

3:15 can anyone lend some experience?

3:16 arrdem: mark_oz: that's not a map, that's a list containing a map.

3:16 andyf: Try (:title (first post)) ? Looks like post is a sequence of one map, from the parens around it

3:16 arrdem: ^^ this

3:17 mark_oz: thanks guys, that worked

3:58 bitemyapp: andyf: just suggest rewriting use with :only to require.

3:58 andyf: because?

3:59 bitemyapp: andyf: the safe thing is to expect use to get deprecate.d

3:59 it's not orthogonal and people should phase it out of their code.

3:59 it sets a very bad default.

3:59 I'd do the same to Haskell's import if I had my druthers.

3:59 sadly, they get away with it because they have an exceptional type system and compiler.

4:01 andyf: I'll consider it. Just working through the surprisingly-many cases of a use without :only right now. Trying to recognize them all.

4:02 Although I should simplify my life by assuming Clojure itself hasn't complained about it.

4:02 arrdem: bitemyapp: well... all done. ish. http://arrdem.com/2014/01/10/Batbridge.html

4:02 * arrdem crawls off towards bed

4:25 noncom: when using tools.namespace, i cannot predict its behavior. i have a project in "checkouts" of lein, and tools.namespace seem to fail finding the namespaces of the referred project in an arbitrary manner

4:26 if i manually load the ns that cannot be found, it then works

4:27 how do i make the tools.namespace/refresh to find all the files?

4:45 rurumate: ,"hi"

4:45 clojurebot: "hi"

4:47 arcatan: "hi"

4:59 mullr: :salutations

5:06 ddellacosta: mullr: hello.

5:11 sveri: hi, i am trying to use the c2 (http://keminglabs.com/c2/) library and like to draw a polyline, however, i have not found an example or something similiar, how would i do that with c2? any ideas?

6:00 Arafangion: it isn't that hard to learn most languages though.

6:00 if i needed to work in a project, i would learn the language - might not be elegant at first but it isnt a big deal.

6:24 AeroNotix: has anyone used Authorize.Net from clojure and/or is there already a library for it?

6:25 fizruk: hello guys! what's the easiest way (with clj-time) to check whether to dates are separated by midnight (e.g. 31 Dec 2013 23:59:59 and 01 Jan 2014 00:00:01)?

6:29 augustl: AeroNotix: my first action would be to google for a Java lib for that

6:29 AeroNotix: augustl: there is. They provide it.

6:29 augustl: AeroNotix: and possibly just write that part in Java if that for some reason is less work

6:29 AeroNotix: augustl: no, java is never Less Work

6:29 augustl: perhaps they have a finished servlet you can just tack on to your exiting servlet, for handling the callbacks and such

6:30 AeroNotix: I've been looking at the docs. It's just classes which map to their SOAP API

6:30 I just wanted to know if there was a better way.

6:31 augustl: fizruk: as in if they represent different days in a given time zone?

6:31 fizruk: or that they are adjacent days in a given time zone?

6:32 fizruk: augustl: different days in a given time zone, not always adjacent

6:36 augustl: I wish I could truncate datetime to date, can I do that?

7:36 jtoy: is it possible to do this: from ns A include ns B , then if other namespaces use A, they can use the methods from ns B ?

7:38 jballanc_: jtoy: should be able to do that with anything you "use" or ":refer"

7:40 otfrom: Does anyone have an example of integrating friend and liberator?

7:40 I know sritchie has been working on some stuff

8:00 sveri: hi, i am trying to use the c2 (http://keminglabs.com/c2/) library and like to draw a polyline, however, i have not found an example or something similiar, how would i do that with c2? any ideas?

8:25 rurumate: I want to write this with swiss-arrows but it fails: (-<> 2 (+ 4 (inc <>)))

8:25 this works: (-<> 2 (+ 4 <>))

8:26 Why can only use <> in the top level of expressions? Is there an alternative macro where the diamond can appear in nested forms?

8:26 fredyr: holy threading batman

8:27 mdrogalis: Looked at this before I had my coffee. Brain broken.

8:27 fredyr: haven't seen swiss-arrows before

8:31 the doc string says top-level insertion of x in place of single

8:31 positional '<>' symbol

8:36 edbond: fizruk, try (to-date) and compare

8:37 fizruk: edbond: thanks!

8:45 edbond: fizruk, I was wrong, you need to extract year, month, date and compare them

8:45 (year (fmt/parse (fmt/formatter "yyyy-MM-dd HH:mm:ss") "2013-12-31 23:59:59")) ;; 2013

8:47 ((juxt year month day) d1) ;; [2013 12 31]

8:48 fizruk: fortunately, one of two dates I deal with is (now), so I just used (after? (today-at-midnight) dt)

8:48 nevertheless, it seems that clj-time lacks date truncation functions

8:51 DerGuteMoritz: ohai edbond :-)

8:51 edbond: DerGuteMoritz, hello :)

8:52 DerGuteMoritz: long time no see :-)

9:02 ro_st: dnolen: what could prevent cljsbuild :none incremental builds? we're getting 10s a build even with a single change to a single ns

9:02 what's the best way to dig into why it's so slow?

9:03 cljs "0.0-2138" / cljsbuild "1.0.1"

9:05 jcromartie: in Light Table, where can I see errors related to connections?

9:05 i.e. I am trying to connect to a project but it fails silently

9:08 CookedGryphon: jcromartie: there's a little red box near the bottom of the screen with a number in it (the number of errors*

9:08 click that to bring up the console

9:12 john2x: hello. is there a leiningen plugin for colored input/output for the repl?

9:12 jcromartie: the console doesn't show anything when I add a connection to a project.clj

9:13 it is just silent, like it isn't even trying

9:13 does it just not work?

9:13 or do I misunderstand what "add connection" does?

9:13 I'd expect it to open a REPL

9:15 CookedGryphon: jcromartie: try pressing ctrl + enter in a file

9:15 i've not played with it much myself, but i remember being a little confused by that, but evaluating something in a file loaded it automatically

9:15 jcromartie: hm, so it doesn't connect until you Ctrl + Enter

9:17 but, yeah, it's working for my app! yay

9:17 I am still a fan of Emacs with Cider

9:18 just because it's familiar

9:18 CookedGryphon: i haven't even taken the time to move from nrepl yet

9:18 ro_st: i'm happy to wait 6 months for the community to build LT up

9:18 CookedGryphon: too much work to do to be faffing around with my setu

9:18 setup*

9:18 ro_st: losing magit is going to be hard to deal with

9:19 CookedGryphon: LT does look promising though

9:19 ro_st: very!

9:19 CookedGryphon: being able to write plugins in clojure rather than elisp opens up a *lot* of avenues

9:19 jcromartie: :P

9:19 CookedGryphon: so many things I've wanted my editor to do but got fed up of elisp

9:19 jcromartie: I see that there's a paredit plugin and commands, but no default keybindings?

9:19 ro_st: i feel like i've paid my school fees for emacs now

9:20 did the trial-by-fire of learning the paredits binds

9:20 CookedGryphon: ro_st: you can move those all over to light table!

9:20 in theory, I haven't managed to get the emacs bindings to work yet

9:20 ro_st: the paredit in LT is not the paredit that's in emacs

9:20 jcromartie: no

9:21 ro_st: some stuff is there, but no ways is there all of it

9:21 CookedGryphon: ro_st: so make them match, the keybinding action stuff is so so easy compared to emacs

9:21 you can just add stuff as you miss it

9:21 ro_st: like you, i have far too much work to do

9:21 CookedGryphon: but yeah, I'm going to give it another release or two

9:21 ro_st: heck, we only just moved to cljsbuild 1.0.1 this week

9:23 i experienced the warm glow that is working cljs sourcemaps today. stepping breakpoints in cljs in the browser. man. so awesome

9:23 AeroNotix: How do I use -> macros on mutable java objects?

9:23 I.e. a (.Method Object) -> nil

9:23 ro_st: AeroNotix: (.. thing .call .call)

9:23 AeroNotix: trying

9:23 hyPiRion: AeroNotix: usually you'd use doto instead

9:23 AeroNotix: I tried this

9:23 oh I will look at doto, as well.

9:23 ro_st: clojure.org/java_interop

9:23 AeroNotix: Cheers!

9:23 hyPiRion: ,(doto (java.util.ArrayList.) (.add 1) (.add 2))

9:23 clojurebot: [1 2]

9:24 rukor: ro_st: i had that when i had local macros. When i moved the macros to a library in checkouts i got back sub second compilation. Not saying it's it but just sharing my experience

9:25 AeroNotix: ,(doto (Calendar/getInstance) (.add Calendar/DAY_OF_YEAR -10) (.getTime))

9:25 clojurebot: #<CompilerException java.lang.RuntimeException: No such namespace: Calendar, compiling:(NO_SOURCE_PATH:0:0)>

9:25 AeroNotix: dero

9:25 ro_st: rukor: we only have macros in our checkouts

9:26 pure cljs in the main project

9:26 rukor: ro_st: interesting then

9:26 ro_st: weird thing is, on 1.7.0_45 on mac it's fine - 0.5s. i have ubuntu users on 1.7.0_25 getting 10s

9:26 curiouser and curiouser

9:27 they're not getting incremental, basically

9:28 rukor: would seem so.

9:28 clean, then start over?

9:29 ro_st: that was our first port of call :-) lein clean, lein cljsbuild clean

9:55 expez: After doing reloading code and running tests with clojure-test-mode the tests starts to get duplicated instead of updated, why does this happen?

10:08 ro_st: rukor, dnolen: the issue has been found and resolved https://github.com/emezeske/lein-cljsbuild/issues/281

10:19 rukor: ro_st: thanks

10:40 CookedGryphon: I think I'm getting weird bugs trying to combine core.match with core.async

10:40 gfredericks: expez: did you rename a test?

10:41 CookedGryphon: if i do a match inside a go block, I always seem to end up with only the first match working and everything else falling through to the else

10:41 take it out of the go block and it works as expected

10:42 fizruk: is there a map-like function for persistent Maps which returns new persistent Map? e.g. (my-map + {1 2 3 4}) => {1 3 3 7}

10:42 I'd like to map values (but use key when mapping)

10:43 sw1nn: sritchie: I'm looking at friend + liberator integration and I found your PR on liberator, Where is friend/unauthorized! - is that your function?

10:45 DerGuteMoritz: fizruk: (into {} (map (fn [[k v]] [k (+ k v)]) {1 2 3 4})) is how you'd usually do it

10:45 hyPiRion: fizruk: just ##(into {} (for [[k v] {1 2 3 4}] [k (+ k v)]))

10:45 lazybot: clojure.lang.ArityException: Wrong number of args (3) passed to: core$for

10:45 sritchie: sw1nn: yeah, I was writing up a post - let me push the example repo I'm making

10:45 DerGuteMoritz: hmhm, for

10:46 fizruk: ,(#(zipmap (keys %) (map (partial apply +) %)) {1 2 3 4})

10:46 clojurebot: {3 7, 1 3}

10:46 sw1nn: sritchie: great, thanks

10:46 DerGuteMoritz: ugh :-)

10:46 sritchie: https://github.com/sritchie/liberator-friend/blob/master/src/liberator_friend/core.clj

10:47 so, the routes + stuff for hte post aren't in place yet,

10:47 sw1nn: but here's the applied friend middleware with basic auth,

10:47 https://github.com/sritchie/liberator-friend/blob/master/src/liberator_friend/middleware/auth.clj

10:47 fizruk: DerGuteMoritz: hyPiRion: thanks!

10:47 sritchie: and here are the resource helpers:

10:47 sw1nn: https://github.com/sritchie/liberator-friend/blob/master/src/liberator_friend/resources.clj

10:47 DerGuteMoritz: fizruk: yw!

10:47 reduce-kv could also be worth trying

10:48 ,(reduce-kv (fn [r k v] (assoc r k (+ k v))) {} {1 2 3 4})

10:48 clojurebot: {3 7, 1 3}

10:49 sw1nn: sritchie: Thats fantastic, just what I was looking for, thanks again.

10:49 sritchie: sw1nn: so making a resource with :base authenticated-base will get you going

10:49 I think there's a bug or two in here with pass the context vs request...

10:49 I have a busted level of unwrapping at one spot

10:50 sw1nn: lmk how it goes! Comments on the proj would be great if you have suggestions

10:50 more coming on that soon

10:54 zerokarmaleft: sritchie: nice, I'm working on a project with liberator+friend too...I may have some questions/comments for you later

10:55 sritchie: for sure

10:55 I'm traveling today, so if you guys want to make issues on that project that'd be great

10:55 I'll get that post out sunday or monday, probably

10:56 gfredericks: is there an option in recent cheshire to turn off the top-level-lazy-seq thing?

10:57 dakrone: gfredericks: yes, there's a parse-strict option

10:57 TimMc: gfredericks: something somethign strict

10:57 jcromartie: so while clojure.tools.namespace is nice, I've just decided to add a call to a custom (unmap-all) at the top of my namespaces

10:57 yes it breaks defonce

10:58 gfredericks: dakrone: gotcha looks like 5.3; will upgrade

11:16 boblarrick: Is there a way to do something like `(map #(apply * 400 %) [1 [2 (/ 9 8)]])` that would return (400 900) ?

11:19 jcromartie: boblarrick: wat...

11:20 hyPiRion: ,(map #(apply * 400 (cond-> % (not (sequential? %)) vector)) [1 [2 (/ 9 8)]])

11:20 clojurebot: (400 900N)

11:21 hyPiRion: probably not the best one though

11:21 justin_smith: ,(map #(apply * 400 %) [[1] [2 (/ 9 8)]])

11:21 clojurebot: (400 900N)

11:21 jcromartie: I see

11:22 justin_smith: jcromartie: do you really need the input to be sometimes number sometimes sequential?

11:22 jcromartie: jcromartie: boblarrick was asking

11:23 justin_smith: oh, oops

11:23 boblarrick: do you really need the input to sometimes be a number and sometimes sequential?

11:24 boblarrick1: justin_smith: Yeah I was hoping for a way that didn't use cond, and that could handle sometimes number, sometimes seq

11:25 gfredericks: oh I didn't just want strict, I wanted a vector

11:26 hmm

11:26 justin_smith: ,(map #(apply * 400 (flatten %&)) [1 [2 (/ 9 8)]]) ; I hate myself for this, but it works

11:26 clojurebot: (400 900N)

11:27 justin_smith: that code tastes like sawdust :(

11:27 clgv: does leiningen's :global-var also work for non clojure.core variables?

11:38 zerokarmaleft: boblarrick1: I'd take that as a code smell...perhaps whatever is generating the sequence to map over can supply a seq that's uniform

11:39 i.e. a single number is wrapped in a vector

11:40 then you get something clean like what justin_smith first suggested

11:40 ,(map #(apply * 400 %) [[1] [2 (/ 9 8)]])

11:40 clojurebot: (400 900N)

11:43 justin_smith: zerokarmaleft: notice that was exactly my first suggestion

11:43 and noting flatten makes it do what he wants: ~flatten

11:43 err

11:43 ~flatten

11:43 clojurebot: flatten is rarely the right answer. Suppose you need to use a list as your "base type", for example. Usually you only want to flatten a single level, and in that case you're better off with concat. Or, better still, use mapcat to produce a sequence that's shaped right to begin with.

11:44 ddima_: smart bot

11:44 stuartsierra: ~botsnack

11:44 clojurebot: Thanks, but I prefer chocolate

11:44 stuartsierra: :)

11:44 gfredericks: has anybody seen some nrepl middleware that wraps everything in (time ...)?

11:44 or know of a similarly structured middleware I could blindly mimick?

11:46 stuartsierra: xeqi: Pushed fix for DJSON-13, if you want to give it a try.

11:46 zerokarmaleft: justin_smith: yes, I see that...just wanted to reinforce that "flatten" is usually a bad idea :)

11:48 boblarrick1: Thanks al

11:48 *all

11:49 justin_smith: zerokarmaleft: but that is why I suggested flatten - the root problem is a design problem, the same design problem that leads to using flatten

11:50 flatten being a symptom of that problem, not solution, mind you

11:52 boblarrick1: /shrug. Who knows where data comes from, and how much control one has over it.

12:00 justin_smith: boblarrick1: would you a) write a version of multiply that checked if args were strings and parsed them as numbers before multiplying, or b) write a preprocessor that validated and coerced input when received? No need to complect handling input with processing it.

12:05 jcromartie: can anybody help me understand why this works the way it does, and how to avoid it? https://gist.github.com/jcromartie/b63a93e0845603636f9e

12:06 sorry, updated

12:06 boblarrick1: justin_smith: Of course I'd us a preprocessor, unless I was getting data from somewhere else and playing around with overtone in a repl and just wanted a oneliner ;)

12:07 justin_smith: jcromartie: my hunch is that defn creates a var, or resets it if it exists

12:07 jcromartie: and g does not get f as a name of a var, but the var f resolves to

12:08 jcromartie: so if the initial var exists, it picks up the new value, but after the remapping, f is a different var (just happening to have the same name) so it does not affect g when you set its value

12:08 just guessing though

12:08 Bronsa: jcromartie: http://sprunge.us/GYMF

12:09 justin_smith: that's almost right

12:09 jcromartie: Bronsa, justin_smith, seems to be the case

12:09 thanks

12:09 justin_smith: Bronsa: cool, that seems to back up my hunch

12:09 Bronsa: about the almost, please enlighten me

12:09 jcromartie: so, is there a way to remove stale vars while avoiding this issue?

12:09 Bronsa: justin_smith: it's not defn that creates||resets, it's def

12:10 justin_smith: Bronsa: right, because defn is just a macro over def, right?

12:10 Bronsa: sure

12:11 justin_smith: well, clearly not *just*, now that I see the source

12:11 stuartsierra: data.json 0.2.4 is in the can now.

12:12 Bronsa: jcromartie: not really, the closest you can get is to unbind the var (.unbindRoot #'the-var) instead of ns-unmapping it

12:12 jcromartie: so if I do this: (doseq [sym (keys (ns-interns *ns*))] (ns-unmap *ns* sym))

12:13 I want to specifically avoid the issues where renaming a function during interactive development leads to floating references hanging around

12:13 and I'd love to use clojure.tools.namespace but it blows up on my with my AOT needs

12:13 I guess the answer is "be careful"

12:14 justin_smith: jcromartie: I wonder about maybe a function that parses a namespace file as edn, and also looks at the ns-publics of the same namespace, and returns the ns-publics not reflected by the forms in said edn?

12:15 stuartsierra: jcromartie: Don't know if this is an option for your use case, but if you can separate your AOT-compiled code into another project, tools.namespace will work.

12:15 justin_smith: which more or less would give you the floating stuff (unless you were using higher level trickery to create vars)

12:16 jcromartie: maybe I could redefine def :)

12:16 to update a counter

12:16 oh god what have I done

12:17 technomancy: gen-class inside a fedonce

12:17 defonce

12:18 pandeiro: where does stdout end up going when using lein repl :headless ...?

12:19 technomancy: pandeiro: "stdout" is ambigious

12:19 pandeiro: technomancy: i'm using pedestal and when i do `lein run`, services log requests to the terminal's stdout; when i do `lein repl :headless` etc, they don't

12:19 technomancy: System/out will go wherever the process is started

12:19 justin_smith: technomancy: yeah, I have been tempted to use defonce for side effects like that, maybe it calls for a "do-once" macro

12:20 technomancy: the root binding of *out* will be the same

12:20 out of th ebox at least

12:20 stuartsierra: `gen-class` has no effect when not AOT-compiling.

12:20 technomancy: pedestal might change it

12:20 the thread-local binding of *out* could be anything the client wants it to be

12:20 pandeiro: technomancy: i am using foreman to start a bunch of services in one terminal, maybe that is at play... but when i use foreman with lein run, i see output

12:21 technomancy: remove variables until the problem can be isolated

12:21 pandeiro: yeah ok

12:24 hansel-han: any library name that includes a substring of "clojure" is an instant classic imo. can't really go wrong with that.

12:25 i'm lovin "Cloact", React for Clojurescript

12:25 michaniskin: clojacked

12:25 disregard that came out wrong :)

12:25 i mean clojact

12:25 hansel-han: oh, nice

12:26 the impromptu brilliance of this community keeps me coming back

12:26 michaniskin: i guess probably not good to have "jacked" in the name, at least in the US

12:26 hansel-han: nah, dude. i always tell people at the gym how jacked i am

12:27 michaniskin: my barber shaves jacks every day

12:27 dude is a hacker extraordinaire

12:27 andyf: Bronsa: Any thoughts on alpha releases of tools.analyzer(.jvm) libs? :-)

12:28 tbaldridge: Bronsa: I'll also be asking for this sometime in the next few months, I'm re-writing core.async to use tools.analyzer as we speak

12:29 Bronsa: ok, I guess a 0.1.0-alpha1 is in the way then

12:30 hyPiRion: yay

12:30 stuartsierra: java.classpath 0.2.2 is on the way.

12:30 hyPiRion: I need to use tools.analyzer for some project of mine, but really want a stable release. So this is good

12:31 andyf: Bronsa: excellent. Eastwood still has some sharp edges, and I'm sure there are problems I don't know about yet, but it seems about ready to have a few more people besides us run it through the grinder

12:32 jcromartie: woah… Chrome's view-source gives some serious nondeterministic results

12:32 weird

12:32 Bronsa: right, I guess having people actually use it will probably help us find/fix more bugs :)

12:32 bbloom: Bronsa: i apologize in advance for asking this question, but ... how hard would it be to add XML literals to the reader?

12:33 Bronsa: b/c apparently "looks like HTML" is an important requirement for some people, lol

12:33 Bronsa: stuartsierra: t.a.j depends on t.a, does hudson automatically update the t.a version in t.a.j pom.xml or sohuld I do it manually myself?

12:33 jonasen: bbloom: :)

12:33 stuartsierra: Bronsa: No, dependency version numbers are not updated automatically.

12:33 Bronsa: bbloom: ugh. there's the issue of < > and friends being clojure.core functions

12:33 stuartsierra: ok, thanks

12:34 stuartsierra: Bronsa: you're welcome

12:34 Bronsa: bbloom: I can try and give you a patch if you're *really* sure you mean it

12:35 bbloom: Bronsa: lol i don't want it

12:35 jonasen: bbloom: you could do a JSX transformation and translate <foo></foo> into (foo) or [:foo]

12:35 bbloom: Bronsa: i'm not personally interested in such silliness, since HTML is an abomination for UI components anyway

12:35 Bronsa: *phew*

12:35 bbloom: jonasen: yeah, that's basically the idea

12:35 if it was just hilariously easy, i'd want it for the sake of a joke tho :-P

12:36 if it was like "i can hack that out in ~20 min w/ low quality w/ some shitty regexes" i'd enjoy that, but that's the extent of my request

12:39 andyf: Bronsa: Oh, one question on top level do forms. Does Clojure treat a do *inside* of a top level do the same as the top level do, i.e. analyze and evaluate its forms one at a time?

12:40 technomancy: pretty sure it's just one level

12:40 Bronsa: andyf: I'm not really sure about that, let me check

12:40 S11001001: I think it's recursive

12:41 Bronsa: it *is* one level, but I think clojure transforms (do (do foo bar)) into (do foo bar) somewhere

12:41 apetresc: What's the most mature parser-generator for Clojure? Like, to generate a parser for some CFG/PEG?

12:42 tbaldridge: apetresc: I've heard instaparse is good

12:42 apetresc: I'm aware of fnparse but it doesn't look like it's seen any activity for ~3 years

12:42 tbaldridge, instaparse, thanks, I'll look into it :)

12:43 Oh neat, it looks perfect. Thanks again, tbaldridge!

12:43 jcromartie: "Can't change/establish root binding of: *print-length* with set" ??? like hell I can't

12:43 hyPiRion: apetresc: yeah, instaparse is the best

12:43 justin_smith: jcromartie: maybe you need binding or alter-var-root ?

12:44 jcromartie: ,(set! *print-length* 100)

12:44 clojurebot: 100

12:44 jcromartie: I can have this in a file when I recompile it with C-k, but not when it's loaded when starting up the project

12:44 tbaldridge: jcromartie: the var doesn't have a root. set it with alter-var-root

12:45 jcromartie: why does it work after the facT?

12:45 after the REPL starts up, that is

12:45 technomancy: the repl binds it

12:45 tbaldridge: jcromartie: stuart just talked me through that one the other day. You can't do set! on a var that is unbound. The REPL goes and sets roots for a ton of stuff. That doesn't happen when you app is run outside of the repl.

12:46 jcromartie: ah ha

12:46 tbaldridge: I dug into Var.java for awhile at it does make sense, but yeah, it's a pain.

12:46 jcromartie: is there any kind of hook for after the REPL starts up, particularly in a user.clj namespace?

12:46 tbaldridge: *and it

12:47 amalloy: $google lein sample project.clj

12:47 lazybot: [Leiningen's sample project.clj - GitHub] https://github.com/technomancy/leiningen/blob/master/sample.project.clj

12:47 amalloy: jcromartie: iirc it's called something like :repl-init

12:47 tbaldridge: I'd just wrap your app entry point in a (binding[])

12:48 jcromartie: thanks amalloy

12:49 Bronsa: bbloom: http://sprunge.us/GbOX?diff

12:49 bbloom: Bronsa: ha! awesome. does that really work?

12:50 Bronsa: wait, it has a bug.

12:50 bbloom: Bronsa: too bad the #< dispatch macro is already used for "unreadable"

12:50 which i guess is accurate, since XML is unreadable... ZING!

12:50 andyf: Bronsa: I test eval form seems to confirm that a do inside of a top level do somehow causes its subforms to be analyzed and evaluated before the next subform

12:51 Bronsa: bbloom: http://sprunge.us/HIKX?clj here

12:51 s/clj/diff

12:53 andyf: yeah, looks like so (line 5733 of Compiler.java)

12:54 so it does (do (do 1 2) 3 4) => (do 1 2 3 4)

12:59 amalloy: andyf: a top-level (do a b) is treated as if it were the two top-level forms a and b. naturally if a or b is a do, the same thing happens "recursively"

12:59 andyf: Bronsa: amalloy: technomany: I can't navigate Clojure compiler source as fast as Bronsa, but this REPL interaction confirms his findings https://gist.github.com/jafingerhut/8359201

13:01 amalloy: andyf: you've doubtless already written code many times that would break if things didn't work this way

13:02 andyf: amalloy: If I did, I wasn't aware of it :-)

13:02 amalloy: well, i was thinking of stuff that macroexpands to (do (do (do (defn ...)))) or whatever, but i guess if there aren't any "backreferences" in there it would work either way

13:03 bbloom: Bronsa: ok now dnolen needs to write a blog post to be like "what? you want HTML? fine. you bastards"

13:03 andyf: OK, well now I know. Looks like I need to go remove the max-1-deep limitation I coded into the part of Eastwood that handles this case.

13:03 bacon1989: Hi, I was wondering how easy it would be to jump into clojure with clojurescript? I have very little lisp experience other than emacslisp

13:05 dnolen: bbloom: Bronsa: heh that is pretty cool, but I really am glad to remain clear of such trivial decisions

13:05 justin_smith: bacon1989: the toolchain with clojurescript is still a little janky in my experience - it works but the dev environment / workflow is weird (to me at least)

13:05 that said, clojurescript is great once you have it compiling / running in the browser

13:06 seancribbs: dnolen: ohai, you going to stick around?

13:06 dnolen: seancribbs: yep

13:06 justin_smith: bacon1989: the jvm version is much easier to fire up and experiment with and learn in

13:06 seancribbs: dnolen: cool, midday meetings and things then I'll ask you about Om stuff

13:07 S11001001: bacon1989: there's a little more setup than emacs lisp, unless you're non-FP and are going to hold onto anti-FP biases. I can't say about clojurescript, though. First tip: ignore clojure install, go to https://github.com/technomancy/leiningen#installation and https://github.com/clojure-emacs/cider#installation , that's what you need to start.

13:07 bacon1989: as you mentioned elisp I assume your editor of choice is emacs.

13:08 dnolen: bacon1989: I think worth learning Clojure first, ClojureScript is not significantly different and the tooling is admittedly not as nice.

13:08 bacon1989: doing ClojureScript in Light Table is the best experience I've seen so far

13:11 rasmusto: bacon1989: doing clojure in lighttable is easy too

13:12 bacon1989: that's a lot of info, thanks a lot

13:12 I already have clojure running cider on emacs with leinigen

13:12 The only web development i've done though, is PHP and Python

13:13 i'm kind of wondering how long it could take for someone like myself to pick up clojure and write meaningful application?

13:13 I guess it would also depend on my dedication, maybe I shouldn't jump into it and use it in my next project 'just yet'

13:13 rasmusto: depends on your definition of "meaningful"

13:14 bacon1989: I'd definitely recommend playing around with 4clojure and project euler before you try to build something with it, just to get language familiarity

13:15 also, clojure programming (o'reilly) and the joy of clojure are good references

13:26 justin_smith: bacon1989: yeah, seconding rasmusto, common mistake for people coming from an algol-family language is to just jump in not really understanding clojure syntax/semantics, and 4clojure / clojure koans / euler will help prevent the tiny newbie mistakes from turning into a frustrating mess in a real project

13:26 Bronsa: andyf: hiredman tbaldridge t.a/t.a.j 0.1.0-alpha1 on their way to maven

13:26 hiredman: neato

13:27 andyf: Bronsa: If you are at Clojure/West, I owe you a beer :-)

13:28 Bronsa: andyf: eh, I could only wish I was. Italy is somewhat far :)

13:29 duh. s/hiredman/hyPiRion

13:30 hiredman: hey, I care

13:31 hyPiRion: Bronsa: yay

13:32 muhoo: why is alter not alter!, or why isn't swap! swap ?

13:32 technomancy: muhoo: ! kind of half-heartedly means "unsafe in a transaction"

13:33 justin_smith: and alter only works in a transaction

13:36 muhoo: makes sense, thanks

13:38 TimMc: technomancy: I'm going to start referring to Java! instead of Java

13:38 technomancy: hehe

13:38 TimMc: Downside: People will think I am excited about Java.

13:38 technomancy: or a yahoo! employee?

13:38 TimMc: ha

13:39 amalloy: dangit technomancy, too fast for me

13:39 * technomancy pets his ergodox

13:40 TimMc: technomancy: Wait, is that that keyboard you have to solder together?

13:40 technomancy: yeah

13:41 it is The Best

13:41 https://secure.flickr.com/photos/technomancy/11437911574/

13:41 amalloy: TimMc: technomancy's POV is that every keyboard is the one you have to solder together, but people just aren't as aware of it

13:42 technomancy: I'm not hard-core like thisg uy though: https://secure.flickr.com/photos/obra/8197649629/

13:43 TimMc: amalloy: Yeah, yeah. :-P

13:43 I meant "you", not "you".

13:43 technomancy: he couldn't even wait for the circuit board

13:44 TimMc: technomancy: That first picture is one of the most hipster things I have ever seen. (Note: "Hipster" not used in a derogatory fashion here.)

13:45 rasmusto: I think its the scarf that really brings the picture together

13:45 hiredman: I dunno, technomancy often wears a scarf, that is pretty hipster

13:45 rasmusto: (inc hiredman)

13:45 lazybot: ⇒ 33

13:46 bacon1989: thank you rasmusto and justin_smith, I got lost in some code

13:46 I think I might pick up the oreilly book and just practise with it at first

13:46 rasmusto: bacon1989: http://www.4clojure.com/ until you have the book :)

13:47 justin_smith: bacon1989: try some of 4clojure in the browser too - but note that numeric order is not difficulty/knowledge order

13:47 jynx

13:47 technomancy: TimMc: someone referred to it as "fashioning my very own majestic hand chariots" which is maybe my new favourite phrase

13:47 TEttinger: hey I had a beard before it was hip. I'm a neckbeard grognard, not a hipster!

13:48 seubert: is there a way to reset my 4clojure account

13:48 i did a bunch of exercises a year or so ago and was just going to restart

13:48 TEttinger: seubert, did you submit a password as an answer? haha

13:48 seubert: no haha

13:48 justin_smith: you could just make a new one?

13:49 hansel-han: if you started a website today, would yall use example.com or www.example.com?

13:49 seubert: justin_smith: gotta dig up an email to use then i guess :V

13:49 haha both of my usual emails are already used

13:49 i must have gone through this process before

13:49 technomancy: hansel-han: www-less looks nicer, but it's a lot less flexible if you need to make changes due to a ddos

13:50 hansel-han: every once in a while, i read a discussion where `www` provides benefits, but i can't tell how esoteric or useful the benefits are

13:50 technomancy: hansel-han: https://devcenter.heroku.com/articles/apex-domains

13:50 hansel-han: technomancy: if the extent of my response to handling a ddos was to utilize cloudflare, would i care?

13:50 i'll read that, thanks

13:51 justin_smith: hansel-han: if you own foo.com, you also control www.foo.com automatically

13:52 hansel-han: justin_smith: right. half the sites i own redirect www->naked, the other half naked->www. i'm launching a fresh website and trying to be deliberate about it for once

13:58 * nDuff strongly suggests naked->www

13:59 nDuff: ...there are some fairly common practices that violate the letter of the RFC when done with naked domains

13:59 though why we're having this discussion in #clojure...

14:00 stompyj: does anyone have any experience with deploying clojure apps to vagrant?

14:03 jcromartie: stompyj: a little

14:03 generally with "lein run"

14:03 and a good main

14:04 stompyj: jcromartie: but the step before that, do you just check out master from git? etc?

14:04 TimMc: technomancy: That is a fantastic phrase.

14:05 stompyj: currently I'm using chef+capistrano

14:05 wondering if I should just move to ansible

14:07 jcromartie: … why would ansible beat chef + capistrano

14:07 when you can just push an uberjar and run it?

14:08 either check out source and lein run, or package the uberjar and push that

14:08 actually I prefer the uberjar for most cases

14:08 stompyj: hmmmm, actually, pushing the uberjar is extremely interesting

14:08 I just don't want to use capistrano, and ansible (supposedly) can handle deploys

14:09 deploying to production is so easy with beanstalk or heroku

14:09 when I went to deploy to vagrant I wasn't sure what the idiomatic-esque solution was

14:09 technomancy: are you talking about vagrant in production or what?

14:11 stompyj: no, we use vagrant as a staging like environment

14:12 that was any developer can just "vagrant up" a service

14:12 instead of having to worry about dependencies on their local box

14:12 technomancy: yeah, the uberjar is a great way to do that

14:12 stompyj: yeah

14:12 that sounds like the move

14:13 I keep forgetting that its all java under the hood, so .jar and .war files are in play

14:13 mdrogalis: Stu Halloway is on the Youtube's live right now

14:13 tbaldridge: https://www.youtube.com/watch?v=VD9UCfQohQE

14:13 technomancy: you'll need to figure out $JVM_OPTS yourself from wherever the rest of your config is coming from

14:14 stompyj: technomancy: makes sense, thanks!

14:14 I saw Rich give a talk on datomic here in NY a couple of months ago, itching to use it in a project

14:15 randomenduser: I'm having troubles getting https://github.com/cemerick/austin up and running. Is that the recommended way to get a browser repl these days?

14:16 TimMc: stompyj: So if you have a bunch of services you need to develop against, do you load the vagrant instances locally, or on a remote machine?

14:16 seancribbs: dnolen: ping

14:17 stompyj: TimMc: right now, locally. as I'm sure you're thinking, this is problematic if you have a ton of services. this project I'm doing now only has 3

14:17 so it's not so bad

14:17 cemerick: randomenduser: I certainly believe so. If you follow the readme and/or the browser-connected application sample that it links to, you should be good. If not, file an issue.

14:18 randomenduser: cemerick, I'll close everything and go slow then report back :)

14:19 stompyj: TimMc: so far the upside has been well worth the downside for us. and eventually, I"m sure we'll be able to use docker to spin up a single vm instance, and use docker slices to add services on top

14:19 dnolen: seancribbs: pong

14:23 jcromartie: is it bad practice to use assertions for business logic checks?

14:24 mdrogalis: jcromartie: It depends :P

14:24 I think it depends mostly on how you want to react to failure.

14:24 randomenduser: cemerick, my fault! (cemerick.piggieback/cljs-repl :repl-env (cemerick.austin/exec-env)) was exactly what I was looking for. Very slick

14:25 cemerick: randomenduser: (cemerick.austin.repls/exec) is even shorter if you really just want a REPL w/o any ceremony :-)

14:25 randomenduser: cheers :)

14:25 jcromartie: comparing (assert x "Invalid x") to (when-not x (throw (IllegalArgumentException. "Invalid x")))

14:25 I certainly prefer to write the former

14:26 mdrogalis: jcromartie: There's a little more to consider than that. Where do the assertions go? Complected with the business logic? Where does the failure reaction go?

14:27 jcromartie: unfortunately it's in a messy routine that executes a bunch of outside API calls

14:28 mdrogalis: tbaldridge: Hector sounds sleepy lol

14:29 jcromartie: it's a command pattern, and performing the command returns events that are then applied to the read model and stored, or else an exception is thrown and the whole thing is abandoned

14:29 seancribbs: dnolen: wow, my RTT sucks :D

14:29 hahah

14:30 jcromartie: if I thought I could provide some useful feedback then I'd use ex-info

14:30 seancribbs: dnolen: i think what I'm struggling right now is app structure/organization, and what 'owner' is in the functions in your todomvc example.

14:30 mdrogalis: jcromartie: Maybe this might work? https://github.com/MichaelDrogalis/dire#preconditions

14:30 dnolen: seancribbs: it's the backing React component

14:30 seancribbs: ok, so like the "parent" in the DOM sense?

14:31 oh wait, i see now

14:31 n/m

14:31 dnolen: seancribbs: I wanted to remove the React-isms and make it a bit more Clojure-like, in React you would typically define a new React class per component, with React.createClass

14:31 jcromartie: interesting

14:32 dnolen: seancribbs: in Om we have a single component which allows to present a much more functional and immutable value oriented API

14:33 TimMc: stompyj: Good to hear, because I'm currently running like 10 other services on my laptop and not thrilled about it. :-P

14:33 dnolen: a single React component I mean, called Pure

14:34 Jarda: dnolen: how does http://holmsand.github.io/cloact/ compare to OM?

14:34 dnolen: Jarda: it doesn't enforce a component design which makes app-state snapshottable

14:34 stompyj: TimMc: yeah, for us, half our team is osx, and the other half is linux, and we had issues with people struggling to install dependencies, etc

14:34 and the vagrant environment cleaned all that up

14:35 TimMc: Jarda: "cloact" sounds like a part of bird anatomy :-(

14:35 dnolen: Jarda: Om does, and I have some things planned around that

14:35 Jarda: TimMc: also cloact seems to be a drug of some kind (according to google results)

14:35 dnolen: ok

14:36 TimMc: Jarda: Probably something for constipated chickens.

14:37 hyPiRion: I think calling it "Cloak'd" would've fixed some naming issues

14:37 Jarda: it's not my project

14:37 something I catched up on the internets

14:37 TimMc: stompyj: My dream: Press a button to spin up all the dependencies of a service, configured to point to each other, built from the branches I specify.

14:38 Yes, it would be server-expensive and possibly slow, but imagine how much less frustrating it could be.

14:38 stompyj: TimMc: yeah, so if you have a box that can handle multiple vms, then vagrant can do that for you today (this is how we're doing things)

14:39 TimMc: Once docker integration happens, then you should be able to do all that from one vm, so it would be even more lightweight

14:39 TimMc: stompyj: This would require projects to know/report their dependencies in a way that a VM manager could use.

14:40 noonian: i tried something like that using pallet but i didn't finish it

14:41 hiredman: pallet is such a yak shave

14:42 mercwithamouth: what's the best way to start up a compojure app from lighttables instarepl?

14:42 in emacs i can just jump right into the project.repl namespace and start server...not so with light table.

14:42 mikerod: Are there any certain things to look out for that would hurt compilation performance in Clojure on JVM?

14:43 tbaldridge: mikerod: don't query a server on the moon from inside a macro?

14:43 mikerod: Such as, does compilation slow down when there are a lot of reflection warnings/lack of type hints vs many type hints

14:43 hyPiRion: I would avoid doing (while true) outside defns and defmacros

14:43 mikerod: tbaldridge: well, that is certainly one good piece of advice :P

14:43 stompyj: TimMc: did you mean with docker? or just with vagrant? with pure vagrant we just use chef to configure each box as needed. it's the same chef scripts we use to build production boxes on ec2

14:43 seancribbs: dnolen: but i can still create components that have their own state, right? like, for instance i need a dropdown in this one place that will have some local/transient state

14:44 mikerod: ok, so slow macros

14:44 and infinite looping top-level forms

14:44 dnolen: seancribbs: yes, om/get-state om/set-state! take the owner and allow this.

14:44 tbaldridge: mikerod: seriously though, I've only seen slower compilation when doing really heavy code transformations. The core compiler is super fast

14:45 seancribbs: ok, maybe I'm more confused now than before, hah. i just need to poke at it

14:45 mikerod: tbaldridge: I see. The reason I ask, is currently we have an jar artifact being distributed over a MapReduce cluster that is not compiled.

14:45 dnolen: seancribbs: the Om separates app-state (kind of like your DB/model in traditional design) from component local state (transient stuff)

14:45 hiredman: our big app at work takes a minute or two to load and compile

14:45 mikerod: so this will be compiled dynamically on each of the nodes. we are probably goign to move to AOT compiling it

14:46 seancribbs: so om/set-state! changes the props on the local component

14:46 ?

14:46 mikerod: I've experienced a few minute build times by changing a project to AOT-compiled

14:46 dnolen: seancribbs: no the component local state

14:46 mikerod: few minute build-time increases

14:46 dnolen: seancribbs: props come from the app state, only way to change that is via transact!

14:47 seancribbs: so, if i want to say "show this dropdown", i have to put something in the app state

14:47 TimMc: stompyj: Yeah, first we'll have to get a uniform build system for all these services.

14:47 seancribbs: that seems like mixing concerns

14:47 TimMc: build/deployment

14:47 dnolen: seancribbs: no, you can do that with component local state

14:47 seancribbs: they are intentional separated for this reason

14:47 seancribbs: ok, then we're on the same page

14:47 i think

14:48 stompyj: Yeah, that's definitely the trick. Getting buy in can be hard, because it's hard to quantity this stuff. But once you get it working, you wonder what the hell you were thinking beforehand

14:48 dnolen: seancribbs: we actually don't venture too far from the high level React model

14:48 stompyj: Just like working with mutable data structures :)

14:48 dnolen: seancribbs: components get their basic data (props) from app state, just like reading that stuff of out of a DB

14:48 seancribbs: if you a component needs to change something in the app state (DB) you need to transact!

14:49 seancribbs: sure, like the items i want to put in that dropdown will be app state

14:49 dnolen: seancribbs: for transient stuff, local component state is enough, om/set-state!

14:49 seancribbs: exactly

14:49 seancribbs: cool, now i think i have the separation

14:50 i like the idea of the UI being a set of functions over the app state

14:50 so much easier to reason about

14:50 just hard to break myself out of the MVC junk

14:50 bbloom: ibdknox: you there?

14:51 dnolen: seancribbs: yes I much prefer this. Not yet set on the names for the functions so I haven't committed to documenting what's there yet in a more visible fashion.

14:51 seancribbs: also as people use it getting a clearer picture of what's needed

14:51 seancribbs: cool. hopefully this experiment of mine can result in some feedback

14:51 TimMc: dnolen: So this is like data state vs. ui state?

14:52 dnolen: TimMc: precisely

14:52 TimMc: Sweet!

14:52 I have to take a look at this, that problem has been bothering me for a while.

14:52 dnolen: TimMc: and the separation is even more important in Om because we render on request animation frame. So in transact! you need to be careful.

14:52 TimMc: you need to check your assumptions

14:53 TimMc: boy do I ever

14:53 dnolen: TimMc: but even om/set-state! is better than what you normally get

14:53 TimMc: every component can see it's current local state and what it will become

14:53 mutation that doesn't suck

14:54 same as React here

14:54 TimMc: like the Kwisatz Haderach

14:54 seancribbs: lol

14:56 the nice thing about the app I'm doing is that all data that is loaded from the server is immutable anyway. you can only add new things

14:57 by "you" i mean some external process

14:57 dnolen: seancribbs: fwiw, the main advantage in the Om model over React is faster defaults and simple model for access to app state history - if you don't really need/want this then plain React works great.

14:58 seancribbs: dnolen: well, redraws are a real problem in this app, mostly because of medium-sized (read thousands) of data items

14:58 dnolen: seancribbs: like 10,000? is this in a giant list?

14:59 seancribbs: it's somewhat tree-like

14:59 the main drag is taking ~1000 items, slicing it into a N-level index and then displaying that as a table

15:00 dnolen: seancribbs: tree-like will be better, React does not yet provide the hooks required for truly fast rendering of very large lists

15:00 and thus nor do we

15:00 "truly fast re-rendering"

15:00 seancribbs: yeah, well i need to compute the matrix, heh

15:00 but Ember drags with that many bindings

15:00 where it's really not necessary

15:02 dnolen: seancribbs: so does the server give the client a delta or something?

15:02 seancribbs: eventually we'll probably hook up EventSource

15:02 but that is turned off for right now

15:02 so yeah, potentially new information can be added

15:03 dnolen: seancribbs: then what exactly are you re-rendering? Are you just sending down all the new data?

15:03 seancribbs: different subsets of the data

15:03 dnolen: seancribbs: and you just mutate the part of the data that changed?

15:03 seancribbs: err, sub-"trees"

15:04 better if i just show you, hah

15:04 http://giddyup.basho.com (click riak_ee, then one of the dropdowns under 2.0.0)

15:06 dnolen: seancribbs: wow ouch, locked up my browser had to restart

15:07 seancribbs: yep

15:07 ETOOMANYBINDINGS

15:07 Safari is quite snappy on it actually

15:08 dnolen: seancribbs: yeah Safari seems significantly faster when it comes to DOM ops than Chrome it seems.

15:09 seancribbs: so my guess is, tell me if i'm off base here... Ember is delaying those DOM updates to the end of the run loop, but not doing them in one batch

15:09 and it's a complicated tree of templates there

15:12 dnolen: seancribbs: hrm I really can't say, I don't know Ember, but the UI doesn't seem very complicated to me and that seems crazy slow.

15:12 seancribbs: yeah

15:12 easy vs. simple

15:12 Ember was easy, but is complex

15:13 and honestly its latest incarnation is grating me, as much as I like Tom and Yehuda it's just too hard to debug

15:14 dnolen: seancribbs: I suspect you could solve most of your issues w/ just React, nothing here much warrants Om unless you really want to use ClojureScript :)

15:15 seancribbs: cool, I might just start with that, but perhaps come back for the core.async

15:15 :D

15:24 bitemyapp: seancribbs: Ember wasn't even easy anyway.

15:25 unless you'd spent a fair amount of time immersed in it.

15:25 seancribbs: bitemyapp: fair. "easy" if you're used to railsy things

15:27 * bitemyapp gags

15:27 seancribbs: never said "easy" was good

15:27 :-p

15:27 bitemyapp: seancribbs: I mostly went CL -> Python -> Clojure -> hs, not much interest in Rails/Ruby except when I was forced to dive into it periodically.

15:28 seancribbs: yeah it was more like, we knew some Ember already when we did this app, it was quick to get going

15:28 we were on a deadline

15:28 now it's just tech debt

15:28 and it's not our core thing, just a tool we use

15:28 so it doesn't get updated that often

15:34 bitemyapp: always regrettable.

15:34 seancribbs: the only times I've been happy with that sort of stuff in recent memory has been when I was using cljs or fay with the vanilla DOM API, or Angular.

15:35 seancribbs: bitemyapp: *shrug*. going to try plain react.js and see if i can't speed this sucker up

15:36 bitemyapp: seancribbs: sure, I haven't tried React myself yet.

15:40 arrdem: $mail ambrosebs thinking about giving a c.c.t talk at c/w?

15:40 lazybot: Message saved.

15:41 bitemyapp: arrdem: that would incentivize me to go to c/w.

15:41 arrdem: bitemyapp: if I can prove that either ambrose or bronsa will be at c/w I can get the department to pay for flying me out :P

15:42 bitemyapp: so I'm not entirely unbiased.

15:43 bitemyapp: Makes sense.

15:48 arrdem: having looked at LightTable's code, beyond the fact that c.c.t isn't really JS ready, I can see why it isn't likely to be used.

15:48 a lot of the editor is uni-typed objects stored globally with some metadata tags and the like.

15:49 primary irritation is non-hackability at runtime.

15:51 saint_cypher: I have a friend question https://gist.github.com/rjspotter/8362283

15:52 * saint_cypher is new to clojure

16:05 noonian: saint_cypher: for one thing, ::users/user should just be :users/user

16:06 bitemyapp: ,::user

16:06 clojurebot: :sandbox/user

16:06 noonian: using two colons with a keyword expands out to the namespace qualified one, so ::user (in the users ns) would expand to :users/user

16:06 bitemyapp: ,:user

16:06 clojurebot: :user

16:07 noonian: ,::sandbox/user

16:07 clojurebot: :sandbox/user

16:07 noonian: ,::users/user

16:07 clojurebot: #<RuntimeException java.lang.RuntimeException: Invalid token: ::users/user>

16:10 kristof: Here's a heretical question.

16:10 Is the STM system an actor?

16:10 Or rather, would it be useful to think of it as one?

16:11 tbaldridge: kristof: no, it's more like a managed lock system

16:12 kristof: tbaldridge: Oh, you're the core.async guy. I've watched all the videos I can (that you've released), and I think it's all great stuff :)

16:12 tbaldridge: kristof: thanks!

16:12 kristof: Goroutines in general seem like magic, ha

16:12 stuartsierra: [org.clojure/data.json "0.2.4"] and [org.clojure/java.classpath "0.2.2"] are in the Maven Central repo now.

16:13 kristof: I'm just mostly impressed with the way the go macro deep walks a bunch of code and sets up a state machine accordingly

16:13 tbaldridge: Question, is there only one STM per running clojure process?

16:13 stompyj: bitemyapp: you're saying you think light table isn't likely to be used? (sorry, only read half the convo)

16:15 tbaldridge: kristof: not really. The way STM works is a lot like locks are used in any Java program. But in STM threads can "barge" locks. So one thread locks the refs it needs, does its work, and then only commits if someone else hasn't barged the locks. If there's a barge then the thread drops all its work and retries.

16:17 saint_cypher: noonian: thanks.

16:18 noonian: saint_cypher: np, other than that i'm not shure whats going on, you might need to make sure you are calling authenticate in your middleware

16:18 kristof: tbaldridge: Oh, I think I understand now. So you can concurrently access two refs and commit to both of those at the same time if they're not the same ref, right?

16:18 tbaldridge: kristof: *if they're not in the same transaction

16:20 kristof: Ok, that makes sense.

16:20 tbaldridge: kristof: but yes, that's the general idea. Although I was surprised to find how little I need STM. Actually I can't think of a single time I've used it and didn't refactor it out later

16:20 kristof: it's often much easier to put a hashmap in a single atom, or something like that.

16:20 mrhanky: i need some hints, i have a clojure script which calls (read-line) to read user input (the script realises a repl). i know want to port this to clojurescriot, so i defined a read-line myself. i use a javascript terminal (jq-console) to handle input/output. my (read-line) starts a new input prompt of jq-console, but my read-line returns a nil immediately and the script failes. how can i "block" the execution of my ported script until a

16:20 input is made?

16:20 kristof: tbaldridge: Under what circumstances do you find that you really need to coordinate and synchronize state changes?

16:21 I mean, I suppose you just answered that, but can you think of anything?

16:23 tbaldridge: that's the problem, I don't really use it much at all. And have rarely (never?) seen it in production code. Normally things are either async, and so core.async or agents are used. Or people just an atom with a hashmap. I think you might want refs if you have a number of refs, and enough threads that they are tripping over themselves during swap!

16:23 technomancy: I feel like refs would be a lot more useful outside the server-side context

16:23 tbaldridge: Although even then I'd be tempted to throw all the updates into a core.async channel and serialize them. So yeah, I wonder sometimes if refs aren't superseded by core.async.

16:24 technomancy: because you're more likely to be able to fit everything in one process

16:24 arohner: tbaldridge: I find refs are superseded by my DB more than core.async

16:24 I almost never want to transact on something that I don't want written to disk

16:25 amalloy: mrhanky: javascript is single-threaded, so a blocking approach won't work. you have to switch to a callback mechanism, either by hand or using core.async

16:25 tbaldridge: arohner: yeah, that too. Esp if you use Datomic.

16:25 arohner: yup

16:25 mrhanky: amackera, yeah, i just came accross core.async

16:25 * amalloy

16:25 kristof: arohner: the point of datomic was to really run in memory and only commit to disk occasionally, wasn't it?

16:25 stcredzero: What would be the best way to do server push from clojure to a clojurescript client? (Could also be js client)

16:25 arohner: kristof: I don't think I'm qualified to comment on that, given other people in the channel, but IMO no

16:25 tbaldridge: kristof: no in server mode all data is always written to disk.

16:26 kristof: ok.

16:26 tbaldridge: kristof: there is a memory only mode for Datomic however.

16:26 hansel-han: is there any reason to use a default location like /var/www/example.com/public_html instead of just ~/public_html?

16:26 kristof: tbaldridge: Hand-wavey question. Is Cognitect an exciting place to be at? :)

16:27 ToBeReplaced: stcredzero: you have a ton of options... i would decide which web technology you want first (SSE, websockets, other)

16:28 tbaldridge: kristof: no. it's horrible. They make us work on open source projects sometimes, and I have to program in Clojure all day.

16:28 arohner: :-)

16:28 stcredzero: ToBeReplaced: I'm writing a game with as thin a client as possible, but still needs to be responsive. It's a roguelike, so all it does is pass keypresses to the server and displays a 80x24 ascii grid.

16:28 tbaldridge: kristof: ofcourse! I love it.

16:29 kristof: :)

16:29 wink: > Chinese spy manages to steal last 50MB of Lisp program governing U.S. missile launches. Fortunately, it was all closing parentheses.

16:29 best lisp joke I heard in months :D

16:29 stcredzero: ToBeReplaced: I also would de-prioritize browser compatibility.

16:30 ToBeReplaced: tbaldridge: core.async eliminated the clojure concurrency primitives altogether for us -- we store application states in "system" variables with control channels and go loops -- feels great

16:30 bitemyapp: tbaldridge: I'm with arohner on refs/core.async/dbs

16:31 tbaldridge: refs are superseded by Datomic :)

16:31 locks: has anyone implemented a card game? I only got to https://github.com/locks/sueca/blob/master/src/sueca/core.clj before getting coder’s block. my brain has a hard time thinking clojure still

16:31 bitemyapp: arohner: how have you been?

16:31 arohner: good. busy

16:31 bbloom: locks: stuartsierra has a good talk about a poker game in clj

16:31 arohner: still not on datomic yet

16:31 :-P

16:31 bbloom: locks: well, it's more about working with data, but he uses a poker example

16:31 ToBeReplaced: stcredzero: since you have back and forth, i would consider something like https://github.com/lynaghk/jetty7-websockets-async

16:32 tbaldridge: ToBeReplaced: bud don't you loose instant deref with that?

16:32 arohner: it's amazing how many things there are to do, that aren't the things you want to work on

16:32 bbloom: locks: http://www.infoq.com/presentations/Thinking-in-Data

16:32 bitemyapp: arohner: I didn't figure you were. I've assumed that when you were ready to test a migration, you'd do something with berossus first.

16:32 arohner: sorry, brambling.

16:32 tbaldridge: *but

16:32 bitemyapp: I keep naming all my projects with the letter b and it's causing me to scramble them a bit.

16:32 ToBeReplaced: tbaldridge: explain?

16:32 arohner: bitemyapp: is the story on datomic migrations any better yet?

16:32 locks: bbloom: yeah, I even tweeted at him thanking, but it’s pretty thin on the main “run loop” and code

16:33 bitemyapp: arohner: I'm still the only show in town.

16:33 arohner: might be a good post to the newsgroup

16:33 locks: bbloom: I did learn some useful things from his talk

16:33 bitemyapp: arohner: and I'm still open to incremental/differential migrations.

16:33 arohner: but, my workplace hasn't needed it yet, so I haven't implemented it yet because my at-home projects are Haskell right now.

16:33 tbaldridge: ToBeReplaced: you said you're storing app state as locals inside gos. How does one go get access to the data inside another go?

16:33 arrdem: bitemyapp: I think that the lack of cljx support is important, but I think that there are major usability concerns that need to come first.

16:33 arohner: bitemyapp: Circle has never had planned downtime, so I don't plan on starting now :-)

16:34 bbloom: locks: just takes some practice. start by trying to figure out what operations you need & what the data structures need to look like to support those operations

16:34 bitemyapp: arohner: part of the reason I am holding off on incremental migrations is that I want a second pair of eyes on Brambling.

16:34 ToBeReplaced: tbaldridge: control channels -- the go loops alt and look for requests of "where am i at?"

16:34 arrdem: bitemyapp: and yes. writing programs in top type isn't condusive to using a more restrictive system.

16:34 ToBeReplaced: tbaldridge: might be a bit clunky... first forays into CSP

16:35 bitemyapp: arrdem: but it was a clever way to defeat static analysis.

16:35 arrdem: if that was ibdknox's intent :)

16:35 locks: bbloom: I’ll keep at it, thanks

16:35 arrdem: bitemyapp: :/ on an open project? doubtful, but possible.

16:35 bitemyapp: arohner: I don't want to implement incremental migrations myself and then tell startups/businesses, "ya sure, trust this with your data" unless at least one other reasonably competent person has given it a look over.

16:35 arohner: I was being facetious.

16:35 errr

16:35 arrdem: I was being facetious.

16:36 arohner: if the ROI on switching to Datomic isn't worth poking at a migration tool then it's probably not yet time to make the switch anyway.

16:37 stcredzero: ToBeReplaced: Thanks! That looks just beautiful!

16:37 arohner: bitemyapp: it's time, but I haven't heard a strategy, even in theory, to get schema migrations yet

16:37 also, it's been time for a while, but we can never find the bandwidth

16:38 bitemyapp: arohner: there already is a way to do arbitrary schema migrations with Brambling, do you mean in-place

16:39 add a ? to the end of that.

16:39 arohner: in-place isn't a strict requirement, but zero downtime and no races is

16:39 so migrate into a second DB, but then you need to handle the switchover

16:39 bitemyapp: I'm not sure where a data race with Brambling would happen.

16:40 arohner: the only Datomic support schema changes that are likely to be supported in the near future are the adding (removal?) of indexes and possibly uni-directional cardinality promotion.

16:40 arohner: (I don't mean brambling needs to handle this, I mean I need to understand how my code would work)

16:40 bitemyapp: zero downtime depends on how abstracted your applications are from Datomic.

16:40 arohner: bitemyapp: at time t1, all peers are on database d1. you migrate to d2. Then you need to switch all peers over to d2, and make sure all in-flight writes appear on d2

16:40 bitemyapp: it goes back to whether or not you can down a clean hand-off with a query queue.

16:41 that's how you avoid races and downtime, at least as a first pass.

16:41 can do*

16:41 arohner: also, duplicating the data size just to do a migration :-(

16:42 bitemyapp: arohner: if your applications are calling your database directly, that's not good. You need a middleware layer / queue like larger services.

16:42 the middleware layer / queue makes the hand-off safe and prevents any lost transactions.

16:42 arohner: it still sounds like there's a race there

16:42 ToBeReplaced: tbaldridge: i'd also appreciate critique if there's something clearly funky with that approach -- it's true that we don't get instant deref b/c you have to wait for the go block to alt again. It might make more sense to just have each block update an atom to deref against. however, we need (or think we need) the control channels anyway so it didn't seem awful

16:42 bitemyapp: arohner: I don't think so, the queue/middleware layer is pausing for the length of the final migration.

16:43 arohner: but the reason for incremental migrations is to make that final migration VERY short

16:43 like, not detectable by your users.

16:43 I thought I'd explained all this before.

16:43 arohner: sorry, it's been a while

16:43 where the final migration is incremental, over the time since the 'full' migration finished?

16:43 bitemyapp: the only real source of delay would be long running transactions/queries.

16:44 arohner: it's zeno's paradox type thing.

16:44 tbaldridge: ToBeReplaced: yeah, it depends on the app. But as a whole that's one of the issues with actor systems. The actor can get backed up, and then it can't be deref'd. But YMMV.

16:44 bitemyapp: arohner: you're incrementally catching up the destination to the origin over and over until the differential is so small that a final migration should take no time at all.

16:44 arohner: right

16:44 bitemyapp: arohner: then for that final migration, you bring the hammer down in your middleware/queue to hold the boat, let things wrap up, then flip over.

16:45 my only real complaint is the data duplication, but I don't think it's expensive at your scale, especially if you're using EC2.

16:46 ToBeReplaced: tbaldridge: was your comment earlier that you're finding that you're not shipping refs anymore, only atoms (and agents?)

16:46 arohner: tbaldridge: any hope on this stuff (zero downtime schema migrations w/ datomic) getting easier? :-)

16:46 bitemyapp: from there you can do a differential archive of the contents of the origin/old database against some archival instance and then kill 'em off.

16:46 arohner: bitemyapp: I worry more about the pain-in-the-ass factor than the cost

16:46 (though cost does matter some)

16:46 bitemyapp: arohner: I've been bugging Cognitect about it, what I mentioned earlier is the only thing they've explicitly said they'd be comfortable doing.

16:47 arohner: I don't worry about the cost arising from the data duplication, just the operational ick.

16:47 tbaldridge: arohner: I'd ask bobby or stuart in #datomic. They are more qualified (and authorized) to speak to that.

16:48 arohner: tbaldridge: thanks. Which stuart? :-)

16:48 bitemyapp: arohner: probably the dude with the rock star hair.

16:48 tbaldridge: arohner: stuart h works full time on Datomic. Bobby specializes in customer relations for datomic.

16:49 bitemyapp: Bobby's almost always the one answering my questions.

16:49 Halloway's accidentally responded once I think.

16:49 tbaldridge: neither seem to be in the channel though.

16:50 and I'm loathe to file a ticket for something I'd already asked them about in the past.

16:57 logic_prog: why are nested #( ... % ... ) 's not allowed?

16:57 why not have % bound to the nearest # ?

16:57 tbaldridge: logic_prog: that would be super easy to get wrong

16:58 and #(%) is just gross anyways (imo)

16:58 ucb: bitemyapp: !

16:59 amalloy: (map #(map #(map #(+ % %) %) %) xs) doesn't read super-well

16:59 TimMc: tbaldridge: Nonsense, where would swearjure even be without it?

17:00 bitemyapp: ucb: I sent you a lot of music.

17:00 ucb: bitemyapp: I saw my name highlighted but lost the backlog :'(

17:00 bitemyapp: muh lord.

17:01 ucb: http://kasperrosa.bandcamp.com/track/coronal-mass-ejection http://dumbsaint.bandcamp.com/album/something-that-you-feel-will-find-its-own-form

17:01 ucb: muh limechat.

17:01 bitemyapp: this is why I am civilized and use a persistent IRC session.

17:02 ucb: thanks!

17:02 bitemyapp: ucb: and https://soundcloud.com/you-are-not-cat/tangled-up-in-clouds https://www.youtube.com/watch?v=YQ1wsf7tAE0

17:02 ucb: me too, but limechat is a piece of gunk

17:02 bitemyapp: ucb: last one comes by way of akurilin. post-punk'ish hardcorey stuff. good.

17:02 ucb: cool!

17:03 TimMc: bitemyapp: Do you have somethign set up that collects all your highlights in another file?

17:03 If I forget to /away, it's really annoying to figure out where a highlight came from when I get back.

17:03 rasmusto: hilite for irssi is kewl

17:03 bitemyapp: TimMc: I just have logs.

17:03 TimMc: and /lastlog

17:03 TimMc: Fair.

17:04 bitemyapp: TimMc: arrdem's setup is even better, he gets a phone jingle.

17:04 TimMc: I highlight on more than just my nick, though.

17:04 bitemyapp: TimMc: be sure to use this knowledge for evil liek I do.

17:04 like*

17:04 I don't highlight on anything but my name. Nobody talks about my libraries.

17:04 except occasionally on the mailing lists.

17:04 s/occasionally/rarely/g

17:05 ucb: https://www.youtube.com/watch?v=hzMeU8tuvNE

17:05 mikerod: Why is the type hierarchy of Clojure functions so... big?

17:06 bitemyapp: mikerod: I mean, it's not Spring Framework.

17:06 mikerod: AFunction, AFn, IFn, Fn

17:06 wat

17:06 bitemyapp: mikerod: have you ever tried to make something nice in Java?

17:07 mikerod: bitemyapp: haha, ok I guess that is a fair enough explanation

17:07 bitemyapp: mikerod: Clojure's implementation is pretty solid at the ground floor, IMHO.

17:08 locks: what about clojure on CLR :P

17:08 bbloom: mikerod: IFn is for things that can be called like functions. AFn is used internally to deal with some ugly java crap about variadics via implementation inheritence, Fn is a marker interface for saying "this is a real function", and AFunction is the implementation of Fn

17:08 bitemyapp: mikerod: you don't want to roll all this stuff into a single class.

17:10 rasmusto: everything is a class, a class is everything

17:10 mikerod: bbloom: that is a good explanation of these things that I certainly haven't heard befor

17:11 before*

17:11 bbloom: mikerod: all you really need to know as a user is that there is clojure.core/ifn? and clojure.core/fn?

17:11 mikerod: bitemyapp: I know that smaller, composable interfaces (abstractions) are favorable to monolithic ones; especially in the Clojure core

17:11 bbloom: mikerod: implementation wise, you've also overlooked RestFn and a few other things

17:12 that's the point of AFn and Fn. AFn lets all the concrete impls share stuff and Fn lets you do fast testing against an interface for clojure.core/fn?

17:12 but maps and vectors and things are not functions, they can only be called LIKE functions, hence ifn?

17:15 bitemyapp: ucb: https://www.youtube.com/watch?v=efsUakRY2IQ

17:16 ucb: bitemyapp: http://www.youtube.com/watch?v=_G3UsM0D6aA

17:16 bitemyapp: bbloom: do you listen to music while coding?

17:17 Raynes: Who doesn't?

17:18 ucb: +1

17:18 Raynes: bbloom jams out to Grimes while he codes.

17:18 Not the band, podcasts featuring me.

17:18 bitemyapp: ucb: surf doom?

17:18 Raynes: that chick is spooky yo/

17:18 ucb: bitemyapp: never heard of it

17:18 egghead: lol

17:18 grimes while devvin

17:18 bitemyapp: ucb: that's how I'm describing what you sent me.

17:18 egghead: I've been listening to lee bannons new album while devvin

17:18 ucb: bitemyapp: oh! heh. Never had somebody refer to The Coral as surf doom :)

17:19 bitemyapp: ucb: s'what it sounds like.

17:19 I should write a thesis on genre bucketing.

17:19 Raynes: I listen to recordings of bitemyapp played at 0.5x speed

17:19 egghead: is anthony grimes a member of the band grimes???

17:19 lazybot: egghead: Yes, 100% for sure.

17:19 egghead: ty lazybot

17:19 Raynes: egghead: I wish :(

17:19 bitemyapp: that would be hella cool if it was true.

17:19 Raynes: Screw programming, music is my passion.

17:19 That's not true, but I am a wannabe singer. <3

17:20 egghead: we can start a band Raynes

17:20 we'll use overtone and livecode

17:20 Raynes: I'm down.

17:20 bitemyapp: I need to learn to play keyboard.

17:21 egghead: oh nice do you play keyboard? nah I play emacs

17:21 i'm sure we could get a gig at the echoplex those guys let anyone

17:23 mikerod: Looks like I lost my connection, thanks for the IFn and Fn family explanations

17:23 I feel a little more at ease on it now

17:26 stuartsierra: mikerod: I made a little utility to help visualize those class hierarchies https://github.com/stuartsierra/class-diagram

17:26 And somewhere on the web is a giant diagram of all the Clojure classes/interfaces.

17:27 mikerod: stuartsierra: Oh, I forgot I came across this I think a while back. This is definitely useful.

17:27 dnolen: https://raw2.github.com/Chouser/clojure-classes/master/graph-w-legend.png

17:28 stuartsierra: that's it

17:28 mikerod: awesome to both

17:33 locks: wait, Clojure has classes?

17:33 I’ve been lied to

17:33 :P

17:37 hyPiRion: :gen-class man

17:37 logic_prog: in core.async, is there a way to say : create a new channel by (1) taking everything from chan1, then (2) take everything from chan2?

17:37 basically, I want a way to concat two chans

17:46 AeroNotix: is there anything like `doto' which returns the value of the last form?

17:47 bbloom: AeroNotix: not precisely, but there is .. which is for chaining style, like if you have a "fluent" builder or something from java land

17:47 (doc ..)

17:47 clojurebot: "([x form] [x form & more]); form => fieldName-symbol or (instanceMethodName-symbol args*) Expands into a member access (.) of the first member on the first argument, followed by the next member on the result, etc. For instance: (.. System (getProperties) (get \"os.name\")) expands to: (. (. System (getProperties)) (get \"os.name\")) but is easier to write, read, and understand."

17:48 AeroNotix: bbloom: that's different

17:48 bbloom: AeroNotix: i'm aware. hence i said "not precisely"

17:48 AeroNotix: oke doke

17:49 bbloom: was just guessing, since that's a popular thing in java libs for functions that always return "this"

17:49 AeroNotix: I can write a macro for this (most likely just copying the majority of doto)

17:49 any reasoning why doto returns the original value?

17:49 (doc doto)

17:49 clojurebot: "([x & forms]); Evaluates x then calls all of the methods and functions with the value of x supplied at the front of the given arguments. The forms are evaluated in order. Returns x. (doto (new java.util.HashMap) (.put \"a\" 1) (.put \"b\" 2))"

17:49 AeroNotix: returns x

17:49 L

17:50 bbloom: AeroNotix: it returns the original b/c you're presumably mutating it and then want it

17:50 AeroNotix: i wouldn't copy doto, i'd delegate to it

17:50 AeroNotix: hmm, indeed. Could be a reason

17:50 justin_smith: if you want the last result, you can use -> or ->> instead of doto, which assume functinoal rather than mutational chaining

17:50 AeroNotix: justin_smith: but it doesn't work if the functions are mutating a java object, instead of returning values

17:50 noonian: just make sure your calls return compatible values

17:51 AeroNotix: It's not my Java code

17:51 nhjk: noob question, but is it worth it to learn some java because clojure is based on the jvm?

17:51 AeroNotix: nhjk: somewhat, I've found

17:51 stuartsierra: logic_prog: maybe something like this (totally untested) https://gist.github.com/stuartsierra/8364220

17:51 AeroNotix: you'll be exposed to it. Namely things like how java organizes code

17:51 and a lot of useful stuff is in the java stdlib

17:51 technomancy: nhjk: you need to learn to read it eventually, but learning to write it is a waste of time

17:52 justin_smith: learning java is meh I think, but knowing enough so you can read javadoc and do interop? definitely

17:52 AeroNotix: exactly

17:52 logic_prog: staurtsierra: noted, thanks!

17:52 AeroNotix: Just enough so you can read function signatures would be nice.

17:52 stuartsierra: logic_prog: just fixed to return `out`

17:53 AeroNotix: haha, I love going away from Clojure to Go, and then coming back to Clojuer

17:53 Clojure*

17:53 justin_smith: the three java skills needed in clojure: jvm config / tuning / classpath; reading javadoc; reading stack traces

17:53 AeroNotix: Clojure stack traces are fugly, jus' sayin'

17:54 justin_smith: they are, but knowing how to read them is a must, for now

17:54 rasmusto: IFugly

17:54 stuartsierra: Whenever I hear that, I think "Compared to what?"

17:54 noonian: lol

17:54 AeroNotix: stuartsierra: some languages which don't include internal machinary

17:54 in their stack traces

17:54 nhjk: alright thanks, I'm already familiar with the syntax because of an algorithms class, but I'll dive a little deeper!

17:54 stuartsierra: What language does that?

17:54 AeroNotix: There's references to things like `apply' interspersed with all my stuff.

17:54 nDuff: AeroNotix: ...and you can use available tools and libraries in Clojure to strip them out here.

17:54 technomancy: compared to nearly everything

17:54 nDuff: AeroNotix: ...if you're so inclined.

17:54 AeroNotix: nDuff: such as?

17:55 I use emacs, probably cannot switch at this point.

17:55 nDuff: AeroNotix: clj-stracktrace, f'rinstance

17:55 technomancy: racket actually has different stack trace styles for its beginner languages vs its expert ones, which is brilliant

17:55 AeroNotix: stack traces to 11

17:55 mikerod: I don't really care if the stacktrace shows the Clojure internal functions being called. I don't see what is hard about finding the relevant code that causes the issue in that.

17:55 The harder things are when it is a compiler-time error

17:55 technomancy: nDuff: clj-stacktrace doesn't actually remove any gunk

17:55 hiredman: what a pain it must be to debug things when the runtime is actively trying to hide things from you

17:55 nDuff: Ahh. I've seen stuff that did, but not paid much attention.

17:56 AeroNotix: nDuff: clj-stacktrace still includes crap in the trace

17:56 mikerod: The worst is when it is no-source-file eval-fns

17:56 nDuff: AeroNotix: As I said above, I've not paid much attention to those tools.

17:56 stuartsierra: ^ What hiredman said.

17:56 AeroNotix: clojure.lang.RestFn.invoke, like what the hell does that need to be in the stack trace for

17:56 technomancy: hiredman: actively hiding stuff from you is what abstraction is all about

17:56 mikerod: ^ to not hiding details of the stack

17:56 stuartsierra: I dunno, maybe because it was on the stack?

17:57 nDuff: AeroNotix: ...ahh, https://github.com/AvisoNovate/pretty was the more recent one

17:57 AeroNotix: stuartsierra: sure, but it's not anything that's to do with me, really. If you need that, it should be configurable

17:57 stuartsierra: as in, some variable which you can set for stack trace verboseness

17:57 dnolen: AeroNotix: *sigh* it is configurable today, no one uses it

17:57 stuartsierra: What's next, configurable core dumps? Configurable segfaults?

17:57 Configurable BSOD?

17:58 nDuff: AeroNotix: ...it's not filtering things, but it is using highlighting to distinguish

17:58 locks: I’d configure segfaults to —never

17:58 AeroNotix: nDuff: it's better

17:58 dnolen: any docs?

17:58 dnolen: AeroNotix: you can get pretty stack traces since 1.3

17:58 AeroNotix: > any docs?

17:58 dnolen: AeroNotix: it the default behaior of clojure.repl/pst

17:58 AeroNotix: pst has been doc forever

17:59 doc'ed

17:59 technomancy: that's a pretty low bar for "pretty"

17:59 dnolen: technomancy: we've already discussed this like a million times :)

17:59 clj-stacktrace is an abomination

17:59 stuartsierra: `psh` also conveniently hides the cause chain, breaking any attempt by a library designer to provide a useful error message.

17:59 `pst`

17:59 dnolen: stuartsierra: I'm not condoning it by any means

17:59 technomancy: dnolen: everything is terrible; I agree there

18:00 bitemyapp: the complaining is partly why I stopped trying to improve clj-stacktrace.

18:00 stuartsierra: Just this week I had to hunt for an exception that clj-stacktrace swallowed.

18:00 bitemyapp: I went back to banging rocks together.

18:00 dnolen: but if people want to find out about stuff they'll eventually abandon, who am I to get in the way :D

18:00 technomancy: "Everything is great the way it is" just means we've lowered our standards

18:01 mikerod: what is clj-stacktrace, never heard of this one

18:01 AeroNotix: I guess eventually I'll just tune out the noise

18:01 stuartsierra: a pretty stacktrace is like a pretty autopsy.

18:01 mikerod: ohhh, yes I have

18:01 bitemyapp: mikerod: you are...so lucky I've sworn off lgtfy.

18:01 AeroNotix: stuartsierra: that's a terrible opinion :)

18:01 kristof: Especially with java stacktraces, hah.

18:01 kzar: dnolen: Going to have a look at om hopefully this weekend, is it ready for production stuff in your opinion?

18:01 stuartsierra: i.e. if it's pretty you're going to hide lots of important details

18:01 bitemyapp: stuartsierra: I think stacktraces can get cleaned up and bracketed without dropping information.

18:01 AeroNotix: stuartsierra: it's a post mortem on a sometimes critical part of your system. You need that information to contain what you need exactly.

18:01 bitemyapp: stacktraces wouldn't be so damn critical if we had sensible types.

18:01 stuartsierra: Yes, which is why it shouldn't hide anything.

18:01 mikerod: bitemyapp: hah I looked it up, stupid question

18:02 dnolen: technomancy: I think anyone who has done CLJ long enough likes verbose stack traces, as long as it's not deep in the compiler or the reader

18:02 kristof: bitemyapp: Oh? Why?

18:02 bitemyapp: logging/tracing is usually more valuable and semantically relevant than stacktraces.

18:02 technomancy: stuartsierra: so do you turn on GC logging too?

18:02 mikerod: I was thinking the discussion was of clojure.stacktrace

18:02 bitemyapp: kristof: source/sink distance on errors.

18:02 technomancy: wouldn't want to miss anything important

18:02 bitemyapp: kristof: if the compiler is catching 90% or more of the common-case stuff, then it's less often that you need to pick through a stacktrace.

18:02 dnolen: kzar: it's pre-alpha, things are going to change

18:03 kzar: it's worth assessing, not building critical stuff on. Though that doesn't appear to be stopping anyone.

18:03 hyPiRion: There are some pretty good ideas and concepts in Racket, CLisp and Erlang on how to read stack traces and issues in programs.

18:03 technomancy: dnolen: so anyone who doesn't like it just hasn't been using clojure long enough? interesting.

18:03 bitemyapp: kristof: in the rare occasion when I need to look at a stacktrace in, say, Haskell it's because I had an unintentionally non-total pattern match.

18:03 hyPiRion: Even gdb/lldb would be good/valuable.

18:03 bitemyapp: kristof: it then tells me what value I failed to match, then I add the match.

18:03 dnolen: technomancy: I don't think that's all that weird

18:03 bitemyapp: kristof: source->sink distance: 0

18:03 kzar: OK good to know, still am intrigued enough to want to spend my weekend looking at it. Curious if it could replace AngularJS

18:03 technomancy: how many years does it take?

18:04 dnolen: technomancy: I once thought not being able to set locals was stupid

18:04 bitemyapp: kristof: source->sink distance of my average Clojure stacktrace? ohgod.jpg

18:04 technomancy: maybe two or three more years and the beauty will sink in

18:04 and I'll stop being such a noob

18:04 bitemyapp: kristof: I would be willing to bet OCaml users have a similar experience.

18:04 stuartsierra: No one ever said they were beautiful.

18:04 dnolen: technomancy: it's not about pretty / not pretty

18:04 bitemyapp: there are ways to make stacktraces more readable/usable without dropping info.

18:04 mrcheeks: dnolen: 'completeness' of the stacktrace then?

18:05 dnolen: mrcheeks: not missing critical information

18:05 bitemyapp: If everybody agrees on that point then we can just discuss what those improvements could be.

18:06 I'm pretty sure everybody understands stack-trace elision is a bad idea.

18:06 mikerod: mrcheeks: we want them the stacktrace to be both complete and sound

18:06 dnolen: what makes me laugh about all of this is that the main reason that CLJ stack traces are so noisy are precisely the same reasons that CLJS stack traces aren't

18:06 mikerod: :P

18:06 dnolen: decomplected compile/runtime

18:06 stuartsierra: I believe .printStackTrace is good enough, and every attempt I have seen to "improve" it ends up having subtle bugs that lose the original exception.

18:07 s/subtle/edge case/

18:07 technomancy: stuartsierra: the only lib that's even attempted is a 3-year-old abandoned hack

18:07 whose author ran off to write Google go code

18:08 justin_smith: locks: I once wrote a c program for win98, no segfaults is not a bonus

18:08 technomancy: hardly compelling

18:08 stuartsierra: There are 2 stack-trace printers in Clojure alone, `pst` and clojure.test.

18:08 justin_smith: the alternative to segfault is worse

18:08 bitemyapp: justin_smith: mmmm data corruption

18:08 stuartsierra: Regrettably I wrote one of them. I've learned my lesson.

18:08 technomancy: part of the reason no one tried picking that up is that chouser said he was going to do it

18:08 stuartsierra: And then decided it wasn't worth it.

18:10 technomancy: clojurebot: usability is not a big deal

18:10 clojurebot: You don't have to tell me twice.

18:10 Bronsa: arrdem: I'm afraid there's no way I'll be at clojure/west, San Francisco is a long way from Italy

18:13 supersym: facebook does their whole operation in mysql? ... those nr's kinda blow my mind

18:14 bitemyapp: supersym: no. It's not that simple.

18:14 arrdem: Bronsa: this doesn't especially surprise me :P

18:14 supersym: well they partition the whole thing ofc but still

18:14 arrdem: Bronsa: wish you could make it tho

18:14 bitemyapp: supersym: the messaging backend persistence layer is HBase (they hired a ton of ex-Yahoo! people). Some of their core persistence layer is MySQL.

18:14 supersym: yeah

18:14 bitemyapp: supersym: it's an inaccurate statement, there are many data stores at Facebook.

18:14 supersym: ok... I read that 90% doesn't scratch the db layer

18:15 caching mostly

18:15 bitemyapp: MySQL is their "primary" one in some sense, but sharded MySQL as facebook is a completely different animal than you might be thinking of.

18:15 supersym: some of that is TAO, some of that is other things.

18:15 supersym: true in that sense, I must be my wording ;)

18:15 bitemyapp: supersym: they have an aggressive cache dependency graph built in TAO on top of memcached.

18:15 if B depends on A, and A gets busted, B must be busted too.

18:16 supersym: I never heard of TAO... going to read up some on that

18:16 bitemyapp: supersym: their whole OLAP stack is Hadoop.

18:16 only the core OLTP is the sharded MySQL, and realistically, most read requests are served by TAO/memcached if things are going well.

18:16 supersym: Its that I got involved with this magento shop now (they use this pretty advanced EAV setup) that I got to work with mysql again

18:17 but it really wants to make me stab my eyes out the whole PHP/HTML soup

18:17 bitemyapp: supersym: you do not want to model your backend stack based on anything Facebook does.

18:17 Seriously. Don't.

18:18 supersym: bitemyapp: nah... purely noticed for the fact of it, and what can be done as 'nice to know'

18:18 bitemyapp: making your own EAV for an ecommerce site seems terribly unwise.

18:18 if you really need EAV, there's always Datomic though.

18:18 supersym: nothing planned on that front, I was actually wondering if I couldn't do better clean slate with clojure and datomic :P

18:18 bitemyapp: clean slates are pretty risky.

18:19 incremental migrations are better.

18:19 pick off pieces of your stack and port a single component at a time.

18:19 supersym: my idea

18:19 yeah

18:19 bitemyapp: supersym: there are books on how to deal with legacy code-bases. Divide and conquer.

18:20 supersym: bitemyapp: thanks, I really do feel there is a case here but indeed, I should approach this from certain angle

18:20 got this experienced magento people to bring me up to speed so nice time to pick their brains on some stuff as well

18:22 luckily it isn't a huge site in terms of catalog size but still the amount of customization makes every upgrade a huge pain in the ass and those guys are running way way behind in production version already

18:22 takes about 50 hours after 1 or 2 trial runs, according to teh googles

18:22 bitemyapp: supersym: do you have any questions about Clojure?

18:24 supersym: well besides that I wonder in terms of components, my obvious picks would be hiccup, datomic, jetty or probably http-kit but then also styling using garden, compojure ofc, ring, friend probably would be a good one esp. since you've got online payments

18:25 bitemyapp: I use http-kit, Ring/Compojure, datomic, and selmer (instead of hiccup).

18:25 supersym: all in all a lot of dependencies... chopping it up would seperate those, yet since its still web based, I wonder if pedestal would be a option

18:25 bitemyapp: I avoid hiccup and friend. Garden depends on your frontend people.

18:25 supersym: its really single page apps I think

18:25 AeroNotix: What're people using for syntax checking in Emacs?

18:26 amalloy: syntax...checking? what would it check?

18:27 supersym: bitemyapp: ok I don't think I've used selmer (or have it register for that matter). Any particular reason for picking it over hiccup?

18:27 bitemyapp: Raynes: in Geidi Primes there are moments where she almost sounds like Kate Bush

18:27 technomancy: supersym: oh man, prepare for a rant

18:27 AeroNotix: amalloy: it would check if the syntax is valid clojure, what else?

18:27 surely you understand this concept?

18:27 supersym: technomancy: lol

18:27 Raynes: bitemyapp: I've actually never even listened to Grimes before.

18:27 bitemyapp: Raynes: ZOMG

18:27 Raynes: I just knew the name because... we share it.

18:28 technomancy: this used to be like a weekly thing where bitemyapp would complain how terrible web dev in clojure was because he couldn't use hiccup for some reason

18:28 amalloy: AeroNotix: the only syntax that exists is (stuff), [stuff], {stuff}. write code with paredit, and it's impossible to write incorrect syntax

18:28 bitemyapp: technomancy: hiccup is awful.

18:28 AeroNotix: amalloy: sure. Sure. SURE!

18:28 technomancy: lies

18:28 hyPiRion: oh, here we go again

18:28 AeroNotix: amalloy: I'll get RIIIIGGGHt on that

18:28 bitemyapp: hyPiRion: don't fear the reaper.

18:28 supersym: just use Selmer. The library speaks for itself.

18:28 AeroNotix: amalloy: and we both know that there are more invalid pieces of syntax, but whatevs.

18:28 e.g.

18:29 bitemyapp: (invalid lel :lol

18:29 supersym: lol ok

18:29 bitemyapp: I think the compiler catches that.

18:29 technomancy: supersym: if you have a team of designers and folks that don't know clojure touching the views, hiccup is not a good fit

18:29 bitemyapp: supersym: that's not the only reason to use Selmer.

18:29 supersym: it also narrows down the origin of template context to a single bottleneck

18:29 supersym: makes it super easy to log template context and what caused this or that output

18:29 AeroNotix: ,(let [m {:k :v}] (defn foo [{:keys [k] m}] k))

18:29 clojurebot: #<RuntimeException java.lang.RuntimeException: Map literal must contain an even number of forms>

18:30 hyPiRion: AeroNotix: I just attempt to compile the file through cider/nrepl through C-c C-k. If it fails somewhere, there will be error lines explaining what failed

18:30 AeroNotix: amalloy: very simple error

18:30 bitemyapp: supersym: you can have m * n "connection points" between templates and your application in Hiccup. It's awful.

18:30 supersym: technomancy: no I guess I should use enlive for that

18:30 amalloy: yes, i should have written {stuff stuff}, not {stuff}

18:30 technomancy: supersym: ehrm... you can try that. it can be ... difficult.

18:31 bitemyapp: supersym: enlive is worse than hiccup.

18:31 it's also horrifically slow.

18:31 technomancy: enlive code reads beautifully but when you go to modify it sometimes it can be difficult to know what to do

18:31 it's not slow anymore

18:31 amalloy: seriously, clojure's syntax is so simple (it really is just lists vectors and maps), and its semantics so flexible (you can define macros that make anything syntactically valid be semantically meaningful), there's nothing for a syntax checker to do

18:31 supersym: right...well that really makes sense, it's the idea that it would be a more generic concept of e-commerce appliance in clojure but I guess once you venture into Clojure development, you are faced with tons of people who aren't

18:31 bitemyapp: technomancy: time to rerun my benchmark suite then.

18:32 supersym: so use Selmer.

18:32 supersym: any freelance work I'd do in clojure and bet my ass people would come back cause it's hard to find developers ><

18:32 bitemyapp: there are a 1,001 reasons to use Selmer over Hiccup and you just named one of the better ones.

18:32 S11001001: &(-> (java.text.SimpleDateFormat. "MMM-dd-yyyy") (.format (java.util.Date.)))

18:32 lazybot: ⇒ "Jan-10-2014"

18:32 amalloy: aside from run the compiler, as hyPiRion suggested, and then let you know if it broke

18:32 bitemyapp: S11001001: non-ISO format? Pagan.

18:33 amalloy: I said that earlier :(

18:33 S11001001: bitemyapp: working specifically with UI-side

18:33 noonian: yeah, the biggest problem with Clojure is that most people hate lisps

18:33 bitemyapp: S11001001: ignore the mewling cries of weak humans and use the standard format.

18:34 hyPiRion: Someone sayin enlive is the best thing ever would bring so much joy into this channel.

18:34 locks: noonian: lisps are hard to understand (yes, I made that pun)

18:34 noonian: lol

18:34 bitemyapp: hyPiRion: why?

18:34 hyPiRion: bitemyapp: That was attempted irony.

18:36 bitemyapp: hyPiRion: Enlive just reinforces my hypothesis that francophones are from outer space.

18:36 supersym: haha...I'll give you that ;)

18:38 hyPiRion: bitemyapp: That's no problem, Clojure is my alien spacecraft anyway.

18:39 technomancy: http://www.lisperati.com/logo.html

18:41 bitemyapp: technomancy: almost seems quaint these days.

18:41 technomancy: it was quaint when it came out iirc

18:46 mikerod: lisp is only for *real* programmers, obviously

18:47 dnolen: noonian: considering how many people are in this channel these days, I don't know if any of the old complaints about Lisp really hold up.

18:49 noonian: i've just found it hard to get other people past it's syntax, i think it being a lisp is a strength for sure but many people don't want to invest the time to become comfortable with it

18:50 mikerod: noonian: it's "syntax" is one of the best part, is the irony

18:51 noonian: yep

18:51 mikerod: I can't type; is one of the best parts, that's the irony*

18:51 bitemyapp: noonian: really? I haven't had any trouble teaching it to Python programmers.

18:51 mikerod: Python people understand first-class functions

18:51 Tolstoy: People where I'm at (extremely traditional Java types) become interested as a result of a few of us writing "cool" apps with a simple build system and hardly any code (seemingly).

18:51 bitemyapp: noonian: on the rare occasion any of them say anything about syntax I give them a withering look that lets them know how shallow they are being and they clam right up.

18:51 Tolstoy: Trying to talk it up never works.

18:53 noonian: bitemyapp: my withering look must not be as effective as yours :P

18:53 bitemyapp: noonian: I am feared in three continents.

18:53 noonian: the bamboo stick helps.

18:53 AeroNotix: At the moment I'm using Clojure because our Erlang application needs to interface with authorize.net and they provide only a SOAP interface. They also provide a Java SDK, so naturally, I'm leveraging that. Using my functional programming experience from Erlang to hopefully help with Clojure.

18:54 technomancy: AeroNotix: how are you finding that transition?

18:54 my guess would be the language itself would be easy compared to the runtime

18:55 bitemyapp: Raynes: but seriously, listen to Grimes.

18:55 hiredman: if only erjang

18:55 AeroNotix: technomancy: fine. I "wrote" clojure a few years ago back when it first came out. I've also written Common Lisp for years

18:55 hiredman: no

18:55 technomancy: but from what I can tell erlang doesn't have a lot of HOF usage going on, so that's pretty different

18:55 bitemyapp: hiredman: pls no

18:55 alew: bitemyapp: what do you think of crystal castles?

18:55 bitemyapp: technomancy: you can't "scale up" Erlang.

18:55 AeroNotix: bitemyapp: uhhh what?

18:55 Raynes: bitemyapp: Okay

18:55 AeroNotix: erlang scales incredibly well, it's kind of the point

18:55 bitemyapp: AeroNotix: I'm talking about FP, not distributed systems.

18:56 AeroNotix: you can't really grow into high level FP in Erlang.

18:56 AeroNotix: Not sure what you mean there.

18:56 technomancy: bitemyapp: you mean build out new abstractions?

18:56 Raynes: bitemyapp: Apparently Gerard Way listens to Grimes :3

18:56 bitemyapp: technomancy: it's very difficult, yes.

18:56 AeroNotix: there are behaviours

18:56 bitemyapp: alew: not a fan. I think they're hacks. :(

18:56 technomancy: interesting word choice, but I see where you're coming from

18:56 AeroNotix: behaviours are kind of like Interfaces

18:56 bitemyapp: technomancy: Erlang code is generally 0 degrees removed, Clojure 1, Haskell...a lot more.

18:56 alew: bitemyapp: similar style to grimes imo

18:57 AeroNotix: and if you couple them with Dialyzer you get semi-static checking

18:57 bitemyapp: alew: I know who they are, I just avoid them.

18:57 lol. semi-static checking. No.

18:57 AeroNotix: So yeah, you can write higher level abstractions like that

18:57 bitemyapp: dialyzer is shit, but it helps

18:57 bitemyapp: AeroNotix: dialyzer is a linter on steroids, it doesn't make anything static and truly safe or sound.

18:57 AeroNotix: it's better than nothing

18:57 bitemyapp: AeroNotix: the point of a type system in FP is to help you scale your abstractions safely, Dialyzer cannot help you with that.

18:58 AeroNotix: Sure, it's no silver bullet. Dialyzer is shit, like I already said.

18:58 bitemyapp: AeroNotix: case in point, if you have a stack of monads Haskell can help you keep your code straight and correct. A comparable pattern in Erlang would be incomprehensible to Dialyzer.

18:58 AeroNotix: > Dialyzer is shit

18:58 I already said this

18:58 bitemyapp: AeroNotix: stop. I'm making a broader point than Dialyzer.

18:58 alew: so enlive isn't a good choice when working with designers?

18:59 bitemyapp: AeroNotix: that's why you can't really extend yourself beyond simple HOFs in dynamic languages.

18:59 alew: seems better than selmer would be for that

18:59 bitemyapp: alew: it complects the functionality of your templates with your HTML and CSS. That's insane.

18:59 arrdem: bitemyapp: hiccup?

18:59 bitemyapp: If you don't have a type system to keep things clear and correct you can't really abstract your FP very much without making it very hard to write correct code.

19:00 dnolen: noonian: people will ignore syntax if you show them you write better/faster software

19:00 AeroNotix: You present a false dichotomy

19:00 bitemyapp: the point of the types isn't just correctness, it's leverage.

19:00 arrdem: shush you.

19:00 AeroNotix: You can write perfectly correct code in dynamic languages, it's just harder to prove.

19:00 arrdem: bitemyapp: to that, nevar.

19:00 dnolen: noonian: you can't convince everyone, but for people who don't want to reason, can't do much for them anyway

19:01 AeroNotix: What *is* the comparable thing for Clojure, anyway? (re: dialyzer)

19:01 bitemyapp: AeroNotix: you're not disagreeing with what I just said.

19:01 alew: selmer builds in the template into the html and css, isn't that coupling them?

19:01 AeroNotix: bitemyapp: I'm just augmenting it to allow a wider definition

19:01 bitemyapp: AeroNotix: you're misunderstanding what I'm saying because you don't know the approaches I'm referring to.

19:01 dnolen: AeroNotix: nothing like dializyer, but you've got Typed Clojure

19:01 hyPiRion: AeroNotix: core.typed I guess

19:01 technomancy: AeroNotix: there's core.typed, but it doesn't have any of the inference functionality dialyzer has unfortunately

19:01 noonian: dnolen: right, people have to be willing to try something different

19:01 AeroNotix: dnolen: how well does that integrate with regular clojure?

19:02 bitemyapp: AeroNotix: the point is that things like map, filter, and reduce are nice, but you can do a lot better and further decomplect your implementations from your interfaces.

19:02 dnolen: AeroNotix: it designed to integrate with regular clojure

19:02 bitemyapp: core.typed is pretty ugly and won't really enable the patterns I'm talking about.

19:02 AeroNotix: dnolen: cool

19:02 dnolen: AeroNotix: some people already use it in production and seem to like it quite a bit

19:02 bitemyapp: AeroNotix: I think CircleCI uses c.c.t

19:02 dnolen: AeroNotix: ambrosebs is very reponsive and cranks on it

19:02 arrdem: AeroNotix: core.typed can be a pain, but it's a nice toolkit.

19:02 technomancy: AeroNotix: you still have to spec everything top-level, so it's a lot of work

19:02 AeroNotix: Haskell does provide some very interesting methods of providing really high level abstractions

19:03 functors, applicative functors are some really light and easy abstractions that make so much sense it's untrue

19:03 bitemyapp: AeroNotix: it's not just about being high-level, it's about keeping things simple and separate in a way that makes sense.

19:03 AeroNotix: and they really make sense when creating your own types

19:04 bitemyapp: The point is that map and filter aren't the essence of FP. Nor are 1-degree-removed HOFs.

19:04 technomancy: AeroNotix: stop saying good things about haskell; he's trying to argue with you =)

19:05 AeroNotix: technomancy: oh I have plenty of disagreements with Haskell

19:05 it's community being #1

19:05 kristof: There's no limit on the order you can write a higher order function in clojure

19:05 And map, filter, and first class functions are in fact the essence of some value of FP

19:05 * bitemyapp grins toothily

19:05 technomancy: kristof: I've wondered what's the highest order of HOF ever seen in real-world code

19:05 we should have a high-score board

19:06 kristof: technomancy: Doesn't matter, any good abstraction works for any degree-order

19:06 hyPiRion: technomancy: just apply some Y-combinators and get going?

19:06 bitemyapp: kristof: it turns into a tarpit pretty quickly.

19:06 becomes hard to debug, hard to write correct code.

19:06 technomancy: swap!+update-in+conj+fnil seems like a good starting point

19:06 kristof: bitemyapp: I'd appreciate some actual examples. I'm not being combative, I'm really interested in what you're saying.

19:07 AeroNotix: Is there nothing out there (or even if this is a sane approach) which uses type annotations in Clojure to deduce (some value of) correctness?

19:07 bitemyapp: kristof: just learn Haskell. You'll figure it out in a hurry.

19:07 technomancy: I guess you still need one more as an arg to fnil

19:07 bitemyapp: there's no better way to understand my point.

19:07 kristof: then try to take what you were doing in Haskell with functors/applicatives/monads and do them in Clojure.

19:07 kristof: bitemyapp: came to Clojure from some newbie use of Haskell

19:07 bitemyapp: kristof: then you'll realize you were standing on a sand castle.

19:07 technomancy: bitemyapp: are you seriously arguing that combo I refered to above is difficult to debug?

19:07 or are you talking about something else entirely

19:08 kristof: bitemyapp: The "sand castle" has not yet been discovered.

19:08 bitemyapp: technomancy: something else.

19:08 kristof: learn more Haskell.

19:08 kristof: the epiphany probably didn't hit yet. It takes awhile.

19:08 AeroNotix: bitemyapp: you could easily write an applicative monad in Clojure, you just cannot prove it's correct.

19:08 or at least typesafe

19:08 bitemyapp: AeroNotix: what exactly is an applicative monad?

19:08 AeroNotix: do you mean an applicative functor?

19:08 AeroNotix: sorry yes

19:08 kristof: bitemyapp: I certainly plan on it but like I said, I'd really like an example of what you're talking about. The coolest example I can think of is the maybe monad.

19:09 bitemyapp: AeroNotix: and how easy do you think it's going to be to write correct code in terms of those abstract interfaces without chewing through a bunch of type errors?

19:09 AeroNotix: bitemyapp: quite. The abstraction is still 'there' though, right? At least I still see the value in writing code like that.

19:09 bitemyapp: kristof: that's not a great way to explain monads.

19:09 kristof: Maybe/Some/Option is as much about algebraic data types as anything else.

19:09 kristof: bitemyapp: Hrm.

19:09 bitemyapp: kristof: you don't need monads for maybe. You can rely on ADT pattern matching or functors entirely.

19:09 AeroNotix: ADTs are wonderful, though

19:10 dnolen: AeroNotix: you cannot prove monad laws in Haskell either, so there's no proof of correctness there either.

19:10 bitemyapp: `fmap (+1) $ Just 1` returns Just 2

19:10 AeroNotix: dnolen: true

19:10 dnolen: word to the wise it's best to ignore bitemyapp on this channel

19:10 bitemyapp: AeroNotix: no, it's NOT

19:10 AeroNotix: you use quickcheck to verify monad laws in Haskell.

19:10 noonian: lol

19:10 dnolen: on anything to do w/ Haskell

19:10 bitemyapp: people do it all the time.

19:10 AeroNotix: bitemyapp: not by the compiler, though

19:10 bitemyapp: oh ffs.

19:10 so because the spaceship has one toilet instead of two you want to stay in a mud-hut?

19:10 for real?

19:11 AeroNotix: c'mon

19:11 so caremad

19:11 kristof: bitemyapp: You'll have to be more specific than "you're all living in a mudhut!"

19:11 bitemyapp: kristof: so fmap is from the Functor typeclass, you can do anything you want with a Maybe wrapped value just with that.

19:11 kristof: monads are overkill for that.

19:12 kristof: better examples would be State in Haskell, Async in OCaml.

19:12 kristof: Async in ocaml? Did you mean occam?

19:12 bitemyapp: kristof: I can't really drop an easy to digest explanation in IRC if you don't understand the math or Haskell behind it. You're better off just getting the epiphany yourself.

19:12 kristof: I mean Async in OCaml. It's a library.

19:12 AeroNotix: Do you really need to understand math to understand fmap?

19:12 bitemyapp: kristof: look at grenchman's source code.

19:12 AeroNotix: unless there was something else you wanted him to understand

19:13 bitemyapp: AeroNotix: no.

19:13 fmap is pretty straight-forward.

19:13 AeroNotix: sure

19:13 bitemyapp: it has the same type signature as map, it's just abstract instead of concrete, and specifically for Functors.

19:14 the best way I can bake it down is in terms of typeclasses and type deduction for method dispatch.

19:14 Fluokitten's use of protocols might demonstrate some of it.

19:14 AeroNotix: hm

19:14 bitemyapp: kristof: AeroNotix - https://github.com/uncomplicate/fluokitten

19:14 so, they're basically using protocols to solve the type deduction and dispatch thing

19:14 kristof: Type inference is cool, I'll give static typing that.

19:14 bitemyapp: but it's not really composable or type-checked the way typeclasses are.

19:15 AeroNotix: next up: Go's type system

19:15 bitemyapp: it also can't really help with the composition of multiple protocols and help you stay sane.

19:15 * AeroNotix Stands back

19:15 bitemyapp: Go's type system is pointless. Why even bother?

19:15 kristof: ^

19:15 AeroNotix: was a joke

19:15 bitemyapp: so the point is that in Haskell, you can (safely) write code in terms of composing things from different typeclasses

19:16 kristof: bitemyapp: So what you're saying is that protocol dispatch on type is flimsy without typeclasses and some form of single/multiple inheritance.

19:16 bitemyapp: kristof: you don't need inheritance, but yes.

19:16 kristof: you can compose without inheritance.

19:16 kristof: Well, that's what typeclasses are kind of for, aren't they?

19:16 This is a that

19:16 This is an Ord

19:16 and a Num

19:16 etc.

19:16 bitemyapp: yeah but they're independent.

19:16 those specific ones are.

19:16 kristof: So?

19:17 Classes can be independent

19:17 bitemyapp: Superclassing is a thing - people have been trying to turn Monad into a superclass of Applicative for awhile

19:17 so that the relationships are more clear and match the category theory more directly.

19:17 but it doesn't harm anything.

19:17 kristof: bitemyapp: I'm really think about generic functions and multiple inheritance in Common Lisp

19:17 bitemyapp: kristof: ick, you can do better than that by far.

19:17 kristof: Oh, probably, but it's certainly a step above Clojure protocols

19:17 bitemyapp: Rust traits, Scala traits, and Haskell typeclasses are a better way to do it.

19:18 kristof: bitemyapp: when's rust 0.9 out?

19:18 bitemyapp: kristof: yeah, I think I'd agree with that, but I was an AOP'er in CL.

19:18 kristof: now.

19:18 kristof: Woah! Hold the phone! :P

19:18 * locks eats popcorns

19:18 kristof: bitemyapp: AOP?

19:18 locks: aspect-oriented programming

19:18 seangrove: ~aop

19:18 clojurebot: I don't understand.

19:18 locks: ?

19:18 kristof: Oh, I see

19:19 seangrove: clojurebot: aop is Aspect-oriented Programming http://en.wikipedia.org/wiki/Aspect-oriented_programming

19:19 clojurebot: Ok.

19:19 seangrove: ~aop

19:19 bitemyapp: kristof: metaobject protocol stuff.

19:19 clojurebot: aop is Aspect-oriented Programming http://en.wikipedia.org/wiki/Aspect-oriented_programming

19:19 bitemyapp: kristof: I do the same in Clojure occasionally with dire/robert.hooke

19:19 locks: is this channel always this caremad?

19:19 bitemyapp: I don't think bringing 4chan jargon into this channel improves anything - can we drop that word?

19:20 kristof: locks: I coerced bitemyapp into having cordial discussion, no harm in that

19:20 bitemyapp: it implies that you should be detached from everything you say and that seems a poor way to communicate with others.

19:20 insincerity ain't a good thing.

19:20 kristof: The internet is at stake, after all

19:20 :P But yes, discussion is important and I think it's healthy for any language community

19:21 locks: what I’ve seen isn’t discussion

19:21 bitemyapp: it's also how a lot of knowledge gets propagated in programming language communities.

19:21 locks: it’s “everything sucks"

19:21 bitemyapp: locks: well, I don't think you're obligated to be here.

19:21 locks: literally even, a couple pages up

19:21 kristof: locks: Everything does suck!

19:21 bitemyapp: you could go make a sandwich.

19:21 kristof: I'm about to fix myself a sandwich, actually.

19:22 locks: bitemyapp: oh, nice

19:22 bitemyapp: locks: if you're satisfied, you're not looking hard enough.

19:22 locks: yes I will leave because I won’t put up with your passive aggressiveness

19:22 bitemyapp: good way to blub it up.

19:22 alew: when writing clojure macros that involve functions included from other namespaces, should you unquote them?

19:22 technomancy: alew: just look at the macroexpansion

19:22 bitemyapp: alew: you mean fully qualify them?

19:23 justin_smith: alew: quasiquote already does the full neamespace expansion

19:23 kristof: bitemyapp: if you're on haskell or here regularly, I'll pester you sometime, thank you for piquing my interest again with opinionated combative behavior

19:23 hyPiRion: ,`(+ 1 2) ;; alew

19:23 clojurebot: (clojure.core/+ 1 2)

19:23 bitemyapp: kristof: no problem. I give Haskell tutorials periodically in person and over the internet so if you need any help with anything please ping me.

19:23 kristof: I'm always online but not necessarily at my terminal. I see my logs.

19:24 kristof: bitemyapp: I will. My biggest problem with Haskell was the bondage and discipline, but it's not without justification.

19:24 alew: right, it namespace expands them, but if that macro is used in another namespace, there won't be any issues?

19:24 bitemyapp: kristof: hum. Usually if it feels BDSM-y you might be going about things the hard way.

19:25 justin_smith: alew: if the defining namespace requires the ns in question, it is available if fully ns qualified, it all just works

19:25 bitemyapp: kristof: one of the better ways to break out of that when you want to "say less than things actually are" is Lens.

19:25 especially to handle non-deterministically structured data.

19:26 justin_smith: alew: it would break if the macro uses an ns that its own file does not require, but then again that would break down at ns qualification time when compiling

19:26 noonian: alew: syntax quote namespace expands things in the namespace that the macro is written in which will have required the relevant namespaces so it's all good

19:26 bitemyapp: kristof: I prefer the BDSM compiler errors to the long tail of unnecessary type errors/stack-traces. That's subjective I s'pose, but I am legitimately more productive over a given period of time that way, not just preferentially.

19:26 kristof: Oh, no, I wasn't talking about static typing

19:26 It was with regard to state in general

19:27 alew: what about with java imports? those don't seem to be qualified

19:27 * technomancy coughs "ocaml" quietly

19:28 bitemyapp: kristof: I think that comes with grokking the typeclassopedia really.

19:29 kristof: having pure/impure functions decomplected is pretty nice and monads let your side effects and state be introspectable, typed values instead of magic aetheria.

19:29 kristof: I don't recall having any trouble firing off side effects at will.

19:29 kristof: that might be awkwardness around not knowing how to write valid monadic code.

19:29 I had the same problem earlier on.

19:30 but again, I'd rather get smacked on the nose called a bad puppy for writing incorrect code.

19:33 Raynes: bitemyapp: I listened to the entirety of Visions and only realized it because I noticed the music stopped.

19:34 Me not realizing I'm listening to music for 45 minutes isn't a good sign

19:35 bitemyapp: Raynes: a good sign for the music or your dehydration?

19:35 Raynes: For the music :p

19:35 bitemyapp: Raynes: you're used to really rambunctious stuff.

19:36 with clear, loud, proud vocals.

19:36 Raynes: Grimes is this spooky chick with a tape recorder from the 80s and a garage sale keyboard.

19:36 Raynes: Indeed.

19:39 arrdem: if I notice that the music is there, it's doing its job wrong.

19:39 white noise ftw.

19:39 noonian: dnolen: is this an appropriate way to nest components in om or is this not a good idea to do? For example (om/build my-c app {:opts {:content (om/build my-c2 app {})}})

19:40 lsdafjklsd: noonian: why not

19:41 noonian: /shrug, it just doesn't feel intuitive

19:42 lsdafjklsd: noonian: yea, it doesn't look great just looking at it, but there is no context

19:42 Tolstoy: noonian: That doesn't seem right at all. Aren't ops for passing in small "configuration" settings for the my-c component?

19:42 stcredzero: In Rich Hickey's ant simulation, I keep seeing things like (send-off *agent* #'animation) in timing loops. What is with *agent*? Do those asterisks mean something, or is it just a different method name?

19:42 lsdafjklsd: tolstoy: well you can pass dynamic view in the ops

19:42 tolstoy: he does that in an example

19:43 hyPiRion: stcredzero: That's old examples, but *name* means that the variable is dynamic

19:43 technomancy: stcredzero: it means the agent running the current code

19:43 Tolstoy: lsdafjklsd: Ah, okay.

19:43 justin_smith: strax: method? - *agent* is just a name for a var

19:43 noonian: lsdafjklsd: which example?

19:43 alandipert: stcredzero: the 'earmuffs' indicate in lisp a dynamic or mutable variable

19:44 justin_smith: naming dynamic bindings with *name* is a convention, but is not enforced at all

19:44 hyPiRion: and technomancy beat me to the second part

19:44 stcredzero: So it's just a convention, not some kind of sigil?

19:44 noonian: Tolstoy: its either in the ops or in the cursor for the app state right?

19:44 hyPiRion: stcredzero: yeah, just convention, but you'll get warnings by default if you don't follow it

19:44 justin_smith: right, a naming convention

19:45 Tolstoy: noonian: Alas, I always tend to try to keep things simple. I'd rather pass in an option, then use a "cond" or whatever to decide what to do.

19:45 hyPiRion: ,(def *foo* nil) ;; e.g.

19:45 clojurebot: #<CompilerException java.lang.SecurityException: denied, compiling:(NO_SOURCE_PATH:0:0)>

19:45 lsdafjklsd: noonian: the sortable example

19:46 justin_smith: ,(do (def *thing* 1) (def *what* 2) (+ *thing* *what*))

19:46 clojurebot: #<CompilerException java.lang.SecurityException: denied, compiling:(NO_SOURCE_PATH:0:0)>

19:46 noonian: lsdafjklsd: thanks

19:46 lsdafjklsd: noonian: (om/build sortable app {:opts {:view item}}))))

19:46 justin_smith: &(do (def *thing* 1) (def *what* 2) (+ *thing* *what*))

19:46 lazybot: java.lang.SecurityException: You tripped the alarm! def is bad!

19:46 justin_smith: hmm

19:46 lsdafjklsd: noonian: item is an om/component

19:46 noonian: Tolstoy: it'd be nice to be able to write reusable component libraries though so you couldn't know ahead of time what to do in the different cases

19:47 robonerd: in the context of web app dev (+ client/mobile/etc would only be a bonus), does anyone happen to know of a language similar to ruby, but perhaps slightly tightened up? (eg, [opt-in] static typing, of which so far i've found erlang and racket)

19:48 alew: clojure has opt-in static typing

19:48 sort of

19:48 robonerd: please explain?

19:48 noonian: lsdafjklsd: but there he builds it in the component he passes it to, which then needs to know about the interface for the item right?

19:49 alew: https://github.com/clojure/core.typed

19:50 lsdafjklsd: noonian: yea, it just get's wrapped in the functionality of sortable so not exactly as decouple as what you're trying to do

19:50 robonerd: in the context of web app dev (+ client/mobile/etc would only be a bonus), does anyone happen to know of a language similar to ruby, but perhaps slightly tightened up? (eg, [opt-in] static typing, of which so far i've found erlang and racket) ideally, on the topic of opt in typing i want to not only be able to say some property is an array, but say it's an array with only string elements.

19:50 there, updated

19:51 alandipert: noonian: have you given hoplon.io a peep? our goal is modularity and to do it we separate the app state machine from the rendering via 'cell' ref type

19:51 hiredman: core.typed is based in some part on typed racket

19:51 alandipert: noonian: a similar approach might be possible using om but i haven't tried

19:52 lsdafjklsd: in react cant you render into components through mounting?

19:52 arrdem: hiredman: in large part...

19:52 lsdafjklsd: i've been meaning to look into that

19:52 dyreshark: robonerd: if you can deal with full static typing, F# is pleasant, runs on Windows/WP and OS X (with Mono, which is decent). Also, it has Xamarin for porting directly to iOS/Android. (Xamarin website advertises C#, but they have plugins for F# dev IIRC)

19:52 hiredman: and it can type collections just fine

19:52 dyreshark: s/OS X/Anything supported by mono/

19:52 noonian: alandipert: thanks for the link, i'll check it out

19:53 robonerd: in the context of web app dev (+ client/mobile/etc would only be a bonus), does anyone happen to know of a language with [opt-in] static gradual typing? ideally, i want to not only be able to say some property is an array, but say it's an array with only string elements.

19:53 (updated)

19:53 dyreshark: ok :p

19:53 technomancy: robonerd: this isn't a forum, geez

19:53 hiredman: stop updating please

19:53 robonerd: oh sorry

19:53 Tolstoy: robonerd: Groovy? ;)

19:54 xuser: robonerd: Dart

19:54 hiredman: anyway, you've gotten plenty of responses

19:56 robonerd: loaded them up, will reearch now, ty

19:56 btw does clojure have this feature?

19:56 ah, loading core.typed now

19:57 hiredman: he must irc via email

20:00 bitemyapp: robonerd: if you want full static typing with FP give Haskell a shot!

20:01 robonerd: the types are organized around typeclasses, and the functions are abstract/polymorphic by default rather than concrete by default.

20:01 robonerd: so a relatively common function signature would be things like a -> b or a -> a with some relevant typeclass qualifier than having to go to extra trouble to make your functions reusable.

20:03 Makes doing things the right way lower friction.

20:04 arrdem: $google haskell javascript compiler

20:04 lazybot: [The JavaScript Problem - HaskellWiki] http://www.haskell.org/haskellwiki/The_JavaScript_Problem

20:05 bitemyapp: arrdem: Fay, GHCJS, Haste.

20:05 dyreshark: ^ Also, as much as it's considered good practice to add explicit type information in Haskell for functions, most types can be inferred for you by the compiler if you're feeling lazy ;)

20:05 arrdem: bitemyapp: yep.

20:05 bitemyapp: dyreshark: I use the inference to "query" what my code is doing. Very informative.

20:05 arrdem: things that aren't Haskell but are similar that compile to JS include: PureScript and Roy.

20:06 the most practical option right now is Fay.

20:06 and that's what I use.

20:06 FPComplete has about 10k+ LOC of Fay in their frontend at the moment.

20:06 Types are shared directly with the backend.

20:06 arrdem: Javascript: not an acceptable PL, acceptable compile target. wat.

20:07 technomancy: * if you don't need integers

20:07 bitemyapp: technomancy: uh, mostly. |0 is guarantee to return an integer.

20:08 technomancy: so if you annotate the results of all numeric operations with that, it's integers all the way down modulo precision loss.

20:08 asm.js understands it.

20:08 technomancy: bitemyapp: precision loss is what I mean

20:08 bitemyapp: technomancy: oh yeah, that part sucks but that's what asm.js is for.

20:10 technomancy: asm.js compatible VMs will turn the operations into integers specifically.

20:10 alew: is there a good way to avoid increasingly nested conditionals for handling complex validation? specifically in web handlers

20:10 technomancy: sure, nice if you can assume it's there

20:12 alew: s/avoid/refactor/

20:12 arrdem: alew: dire's postconditions/preconditions could be useful...

20:12 bitemyapp: alew: Monoids!

20:13 arrdem: bitemyapp: quiet you.

20:13 bitemyapp: I'm serious :(

20:14 alew: I'm not super familiar with dire, but from what I gathered it doesn't give much benefit for one off conditionals?

20:14 I'm probably off here

20:15 bitemyapp: alew: dire's fine if it's a match for what you want. Monoid Validator + Writer/Error is one way to do it "scalably" with sensible error messages.

20:15 arrdem: I mean if you are truly faced with a raft of disjoint, once-off conditionals there's nothing that can really help you. Any refactoring approach or tool will rely on commonalities or common sub-conditions.

20:16 alew: I guess I should just break them out into internal helper functions

20:18 bitemyapp: arrdem: if they're separated by space and time then you can use Monads...

20:18 arrdem: bitemyapp: I suppose -> [ a:Value, b:Err ] with short curcuiting would be a monoid...

20:18 bitemyapp: alew: Monoids let you aggregate a super-conditional, monads let you sequence functions against the value with sensible validation/error output as needed after/before the operations without repeating yourself.

20:18 * arrdem needs to get monoid vs. monad straight again

20:18 bitemyapp: there are many options here!

20:19 alew: Well I'm using clojure, so monoids might not be the most idomatic approach here

20:19 * bitemyapp grump grump grump

20:20 ehabs: After profiling some code, I found out that walking lazy seqs is a big performance bottleneck in one of my functions. The problem is that running doall on it causes a stack overflow. Whats the best way for me to handle this?

20:20 steerio: why do you need the doall?

20:21 ehabs: because i don't want to re-walk the seq over and over again. or am i misunderstanding something?

20:21 steerio: re-walk as in?

20:21 arrdem: ehabs: need code to comment. refheap please.

20:21 steerio: the seq gets realized the first time you walk over it. whether the head gets retained depends on your code.

20:22 if the sequence is too large for your memory, however, it's your heap that gets blown, not your stack

20:22 alew: maybe your lazy seq is infinite, that would blow the stack

20:23 or actually no

20:23 steerio: it wouldn't, that'd be the heap

20:23 ehabs: just a minute. i'll post the code for you to check out. i'm sure it isn't infinite because it evaluates as expected when its lazy. its just extremely slow

20:24 steerio: can you paste the actual output when that overflow happens?

20:24 (along with the code)

20:25 ehabs: here is the code: http://pastebin.com/45aweM15

20:26 arrdem: (dec pastebin)

20:26 lazybot: ⇒ -1

20:26 arrdem: ~pastebin

20:26 clojurebot: Titim gan éirí ort.

20:26 arrdem: clojurebot: you have failed me for the last time commander

20:26 clojurebot: Huh?

20:27 ehabs: sorry, i haven't used refheap before. i'll try to use it next time

20:28 http://pastebin.com/gpuEa652

20:28 steerio: can you see the repeating pattern in the stack trace?

20:29 in fact your problem has nothing to do with the fact that you deal with lazy seqs

20:30 there's simply endless recursion somewhere in there

20:30 arrdem: steerio: it may be bounded, just bigger than stack size.

20:30 ehabs: let me see what i changed. it definitely ran for me a minute ago

20:31 steerio: that's true, just unlikely

20:33 ehabs: this code runs without a stack overflow: https://www.refheap.com/22773

20:35 steerio: i'm a bit too tired to diff them now

20:35 also, they contain quite some references to functions that you define but are not included

20:37 any of them could easily be the culprit

20:37 ehabs: do you have any advice on what i should look for?

20:37 steerio: anything that ends up in a circular call

20:38 shep-home: ehabs: are you running all of that code in the REPL?

20:38 ehabs: yes

20:39 shep-home: you might want to put some of it into a different namespace - that would help the stacktraces identify your code

20:42 steerio: in fact there's nothing in the visible stack trace that's not from core

20:42 shep-home: steerio: good point, I was just scanning for something different..

20:43 Is it possible to have created a circular structure of some type?

20:43 s/to have/that ehabs has/

20:44 ehabs: i don't think i do. the code works exactly as expected if i use a subset of the data

20:44 the problem is when its using 12,000 data points

20:45 steerio: which is weird.

20:45 shep-home: ehabs: the only difference in the code is adding `vec` to the apply?

20:45 steerio: if it was a head retention problem, you'd blow the heap, not the stack

20:46 as far as lazy sequences go, they don't care how many items you end up having in them

20:46 shep-home: I wonder if you are just realizing something now that you weren't before

20:46 ehabs: yes that is correct. taking vex out causes it to blow the stack

20:46 shep-home: oh, taking it out...

20:46 ehabs: *vec

20:50 steerio: so what does seq-without-nth look like?

20:50 i think i'm starting to see what's going on here

20:51 you're basically creating lazy seqs of lazy seqs of lazy seqs...

20:51 so you're doing operations on sequences that yield lazy seqs in a depth proportional to your data size

20:51 which is all fine until you realize it

20:51 and then you blow the stack because it's so deep

20:52 imagine (map #(map #(map ....

20:52 in a 12k level depth

20:52 your call on vec is a way out of it because it realizes the given depth and frees you from one level of calls whenever you do it

20:53 ehabs: here are the other two helpers used in the let: https://www.refheap.com/22774

20:54 the data is shaped like: X= [{1 float 2 float 3 float 4 float 5 float}...] and Y=[zeros-and-ones]

20:55 steerio: let me just illustrate you what i'm talking about

20:55 shep-home: steerio: so it could be "fixed" by only realizing a bit at a time, but there's still a timebomb waiting...?

20:55 steerio: ,(reduce (fn [s _] (map identity s)) (range 12000))

20:55 clojurebot: #<StackOverflowError java.lang.StackOverflowError>

20:56 steerio: in fact the buildup of lazy sequences should be identified and eliminated

20:56 perhaps by a different algorythm, perhaps by realizing every step

20:57 ehabs: can you see where the buildup is happening?

20:57 steerio: your code is way more complex than what would allow me to see that at 3am

20:57 :D

20:59 in such situations what happens is that you repeatedly do some operation over elements of a collection

20:59 which in most cases can be refactored into one operation

21:00 like: (map inc (map inc (map inc coll))) is equivalent to (map #(+ 3 %) coll)

21:00 in this case you are thousands of level deep in the "(map inc (..."

21:00 granted, it's more complex than this example

21:01 ehabs: yeah, that makes sense. too bad it isn't that obvious in this case

21:01 steerio: start taking apart this huge functions into smaller ones

21:02 kristof: If it has over 5 levels of nesting...

21:02 steerio: and testing and comprehending what they do one by one, and you'll probably end up finding it

21:02 kristof: Ah, how does that joke go again...

21:02 "How do you know when a function or method gets too big?" "When it's bigger than my head." "You mean when it's too conceptually large?" "No, I LITERALLY put my head against the monitor."

21:04 ehabs: haha yeah, i definitely need to do that. the top part of the cross validation function is seems to be where the problem is and that can easily be broken out into small pieces.

21:06 steerio: ehabs, check this

21:06 ,(class (flatten [1 [2 3] 4]))

21:06 clojurebot: clojure.lang.LazySeq

21:06 steerio: flatten yields a lazy seq. now, you're storing these as values in a hash

21:06 then you probably at some point repeat this operation and nest lazy seqs at a huge level

21:07 as you merge hashes and whatnot

21:08 every merge-with just nests those lazy seqs even more

21:08 without actually doing any flattening

21:08 the (vec) call realizes them at each level to create that vector out of them

21:09 thereby saving you from this nesting

21:09 in fact probably everything goes fine and dandy until your REPL tries to _print_ the insanely nested lazy seq

21:12 ehabs: yeah, that makes sense. thats definitely what its doing. i just don't see how it would get deep enough to matter in this case. i'm running it with only 10 groups, so it would at most be 9 levels deep.

21:12 steerio: remember that pretty much every operation you do on a collections yields a lazy seq

21:13 ehabs: yeah, thats true. i'm starting to visualize it now. is the solution to just start running doall on them or convert them to vectors? or is there a better way?

21:14 steerio: and in your case, if you merge two hashes with the same keys, all the values have just become at least one more level deeper nested

21:14 xuser: d

21:14 steerio: and all those hashes have the same keys, :training and :testing

21:15 (which begs the question of why you don't use a two-element vector for this)

21:15 also, partitioning data can be done more efficiently too

21:16 same goes for the :x/:y map, use a vector

21:16 so your data becomes [x y] instead of that (map #(hash-map ... thing

21:17 gtrak: I've missed it when other folks have talked about it, is 'austin' the most full-featured cljs repl? I'm hoping for some autocomplete love.

21:17 steerio: (get-in [:training :x] foo) becomes (first (second foo))

21:18 ehabs: yeah, that makes sense. but that still doesn't solve the issue with most of the clojure functions returning lazy seqs. whats the best way for me to avoid that?

21:19 steerio: a better algorythm :)

21:19 this normally isn't a problem

21:19 while in a non-lazy lisp this would not blow your stack, it'd be really ineffective

21:20 as you'd traverse collections 12k times, instead of writing less functions that do it in one step

21:23 bitemyapp: arrdem: doters?

21:25 ehabs: ok, i'll make the changes that you mentioned. thanks for the help steerio

21:25 steerio: np

21:26 in fact even using vector tuples instead of the hashes eases up on this

21:27 well, maybe even solves it

21:29 ehabs: ok, thats the first change i'll make

21:31 hiredman: /win 26

21:46 logic_prog: in clojure, is it possible to construct an object where (1) it supports all operations of map and (2) can only be constructed by a certain function

21:47 i.e. I want "(my-magic-foo ...)" to be the only way to construct a special map

21:48 alandipert: logic_prog: check out def-map-type in potemkin, https://github.com/ztellman/potemkin

21:49 logic_prog: alandipert: this is interesting, let me look into this

21:50 noonian: logic_prog: sounds like records might be what you want

21:50 sritchie: noonian: I think logic_prog wants to hide the constructors

21:50 noonian: ah

21:50 logic_prog: yeah, I want guarantee that a function was only created via (my-magic-foo ...)

21:51 s/function/map

22:04 how can I check if something is a core.async.chan ?

22:04 err, clojure.core.async/chan

22:06 gtrak: seems like they all may extend clojure.core.async.impl.protocols/Channel

22:06 satisfy, rather

22:07 but.. one way to know is to try to use it as a channel :-)

22:07 surely that'll fail.

22:07 logic_prog: I'm surprised there's no (chan? ...) function

22:08 noonian: me too

22:08 logic_prog: great wizards of clojure,

22:08 fix the above please

22:08 add a (chan? ..._) to clojure.core.async

22:09 gtrak: seems harmless enough

22:10 I'm trying to get a dump of the cljs analyzer state, massive rabbit hole

22:11 from hacking cljsbuild

22:20 abp: logic_prog: There was a ticket for it: http://dev.clojure.org/jira/browse/ASYNC-12

22:21 logic_prog: (defn chan? [c] #+clj (= (type c) clojure.core.async.impl.channels.ManyToManyChannel) )

22:21 looks sorta ugly

22:24 arrdem: bitemyapp: just got back from a barbeque outing. hopping on.

22:27 bobajett: hi folks, Im wondering why in Perl/Ruby split("foo", "") -> ["f","o","o"] and in clojure (str/split "foo" #"") -> ["","f","o","o"]?

22:29 andyf: bobajett: Clojure's split is based on Java String class split, and that is the way Java String split works.

22:29 bobajett: andyf: gotcha. Thanks!

22:30 amalloy: bobajett: i can't speak for ruby, but clojure of course just delegates this to java. and java asks "where is the first match of #"" in this string? okay, it's before all the characters. i'll return a match there. now where's the next? after f, all right, return a match there..."

22:30 TEttinger: bobajett, there's also ##(vec "fpp")

22:30 lazybot: ⇒ [\f \p \p]

22:30 TEttinger: but that returns chars

22:30 amalloy: that's as sensible an interpretation of "split on [nothing]" as ruby's

22:30 TEttinger: or ##(mapv str "foo")

22:30 lazybot: ⇒ ["f" "o" "o"]

22:31 noonian: is there an empty string on either end of "foo"?

22:31 bobajett: amalloy: :-) cool thanks for the detailed explanation

22:31 amalloy: TEttinger: (seq "foo") seems nicer than vec

22:31 noonian: seems like theres actually any number of them

22:31 bobajett: noonian: yeah thats what I was wondering too

22:31 TEttinger: amalloy, yeah, that too

22:31 hiredman: ,(.charAt "foo" 0)

22:31 clojurebot: \f

22:32 bobajett: TEttinger: sorry Im only very early in my learning clojure career what do the two ## mean in ##(mapv str "foo")?

22:32 lazybot: ⇒ ["f" "o" "o"]

22:32 TEttinger: just a command to execute the bot's eval

22:32 amalloy: noonian: http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#split(java.lang.String,%20int) says some things about "trailing empty matches", but the sentence is hard for me to follow

22:32 TEttinger: same as starting a line in IRC with ,

22:32 bobajett: ah got it thanks.

22:33 andyf: noonian: If you want to get all splits, including the trailing ones, give a negative integer as a 3rd arg

22:33 amalloy: &(.split "foo" "" -1)

22:33 lazybot: ⇒ #<String[] [Ljava.lang.String;@9ffba4>

22:33 amalloy: &(seq (.split "foo" "" -1))

22:33 lazybot: ⇒ ("" "f" "o" "o" "")

22:33 logic_prog: in cljs, how can I check if an object is an atom, a string, or a cljs.core.async ?

22:34 andyf: Several examples available here that might be more instructive to read through than to try to give general rules: http://clojuredocs.org/clojure_core/clojure.string/split

22:34 TEttinger: so (mapv str "foo") will take "foo", and for each element (a character), return the result of calling str on it "f" "o" "o", and then make it a vector (not a lazy seq as for map, which may be preferable or not)

22:36 bobajett: TEttinger: got it thanks. I could guess what (mapv str "foo") did, but didn't know what the two ## were for.

22:37 ##(class "foo")

22:37 lazybot: ⇒ java.lang.String

22:37 TEttinger: bobajett, heh it's an odd shortcut for the bot to use, since #(* %1 %1) is an anon fn that will multiply an argument by itself

22:38 same as (fn [n] (* n n))

22:39 bobajett: TEttinger: isn't the reader macro for creating a set also start with a "#" ?

22:39 TEttinger: yes

22:39 # is a dispatch char

22:39 it changes what comes after it

22:40 #() is a fn, #{} is a set, there are a few others

22:40 I believe one causes a form to be ignored, can't remember what it is

22:40 bobajett: logic_prog: I shouldn't be answering this, since my clojure knowledge only some days old, but maybe (class yourObject) ? and compare it with java.lang.String or java.lang.Long or some such?

22:41 logic_prog: bobajett: good try, but I need it to work in cljs

22:41 TEttinger: bobajett, that would definitely work on JVM, but maybe it doesn't on CLJS aaaagh

22:42 bobajett: TEttinger: '("foo" #_(elide this stuff) "bar")

22:43 TEttinger: bobajett, seems like that's one of them. I believe #> also gets elided, it came up earlier

22:44 amalloy: wat

22:44 bobajett: TEttinger: ah did not know about that one. don't see it on the cheatsheet.

22:44 amalloy: ,'(x #> y)

22:44 clojurebot: #<RuntimeException java.lang.RuntimeException: No reader function for tag >>

22:44 amalloy: that doesn't work in any version of clojure

22:45 bobajett: ,'(x #_y z)

22:45 amalloy: as far as i know

22:45 clojurebot: (x z)

22:45 TEttinger: it was one of the reader macros on that one thing earlier today

22:47 bobajett: thanks folks, I was trying to do regex splitting and noticed Perl/Ruby behaved differently and Python behaved differently and Clojure behaved differently. #clojure is where I found the most helpful people :-)

22:51 logic_prog: given an object

22:51 TEttinger: http://sprunge.us/GbOX?diff

22:51 logic_prog: is there a easy way to list all protocols it satsifies/implements?

22:52 tbaldridge: no, but you can list all objects that extend a protocol

22:57 bja_: logic_prog, maybe something involving #(.keys js/Object %)?

22:57 err, maybe not.

22:57 cljs$lang$protocol_mask$partition0$ doesn't look super helpful

23:03 gtrak: cemerick: would you balk at an autodoc sort of thing in lein-cljsbuild? I managed to make it dump the analyzer output, now I want to see if I can grab what I need to build something like that.

23:05 I'm also thinking auto-complete eventually, not sure if that's the right approach, but just trying stuff :-).

23:05 cemerick: gtrak: Not sure. Open an issue when you're closer. :-)

23:05 gtrak: cool

23:13 logic_prog: what are the names of the protocols that string, number, atom implement ?

23:19 gtrak: logic_prog: huh?

23:19 logic_prog: in clojure, everything implements some protocol right?

23:19 what protocols do string, number, and atom objects implement?

23:20 gtrak: not necessarily, plus some of those are java interfaces

23:20 like IDeref

23:20 tbaldridge: clojure or clojurescript?

23:21 in clojure, most things are backed by java interfaces

23:22 gtrak: holy jesus, the serialized output of the cljs compiler is massive

23:22 I mean the state

23:23 tbaldridge: yeah....it will be

23:23 there's a ton of structural sharing

23:24 so the same hashmap will extist on almost every ast node

23:24 gtrak: in general are there libs that walk it? trying to simply extract 'vars' and metadata and such.

23:24 I could do it in-process, but was hoping to just dump it :-)

23:25 tbaldridge: yeah, it's not really dump-able. You want to do it in process

23:26 although you might be able to strip the :env nodes before export. That's where 99% of the bulk is, and it's not really needed

23:30 gtrak: I might resort to inspector.clj :-)

23:30 I've used that like once.

23:30 andyf: gtrak: I've used the inspector quite a bit for looking at output data from tools.analyzer(.jvm)

23:30 tbaldridge: just use prewalk and post walk

23:31 andyf: gtrak: It does not show metadata, unfortunately

23:31 gtrak: ah

23:31 tbaldridge: and metadata isn't really used by the cljs compiler

23:31 gtrak: yea, metadata seems silly, the whole thing is metadata

23:32 logic_prog: https://github.com/clojure/clojurescript/search?p=2&q=swap%21&type=Code <-- where is swap! defined ?

23:32 tbaldridge: https://github.com/clojure/clojurescript/blob/master/src/cljs/cljs/core.cljs#L7081

23:32 That's swap! ^^

23:32 andyf: gtrak: I wouldn't use it for looking at analysis results of large source files, but worked OK for me for small to medium source files.

23:35 logic_prog: tbaldridge: https://github.com/clojure/clojurescript/search?q=defn+swap%21&type=Code <-- how should I be searching for taht instead?

23:36 tbaldridge: most stuff is in that single file, I'

23:37 I've never really used github search

23:37 amalloy: logic_prog: just look in the file that it "should" be in - the cljs source is organized pretty predictably. i have no experience with github code search, but it sounds like it's not that useful

23:37 logic_prog: amalloy: I'm getting started, "should" means nothing to a newb with no intuition

23:37 however, grep seems to work

23:38 amalloy: like tbaldridge says, most functions from cljs.core are in that one file

23:38 macros are all in another file somewhere

23:38 Raynes: Yay for shoving everything in a giant file!

23:39 tbaldridge: at least it's easier to find.

23:39 I really don't have a problem with putting it all in one file

23:43 KeithPM: Good day. I am having a few problems with a function to generate permutations. I created a gist here https://gist.github.com/kpmaynard/8367053. I have some commentary at the top but I am currently running in to two errors in LightTable (permx '(1 2 3)) is generating the following errors

23:43 at recursion$permx.invoke(/Users/kpm/dev/clojure/recursion/src/recursion.clj:262)

23:43 in the status window

23:43 and

23:43 clojure.lang.ArityException: Wrong number of args (0) passed to: recursion$permx

23:43 AFn.java:437 clojure.lang.AFn.throwArity

23:43 AFn.java:35 clojure.lang.AFn.invoke

23:43

23:43 In the REPL

23:44 gtrak: eek, don't paste multi-lines like that

23:45 KeithPM: Would you prefer that to be on one line?

23:45 gtrak: well, here's the relevant single line: clojure.lang.ArityException: Wrong number of args (0) passed to: recursion$permx

23:46 KeithPM: gtrak: I am calling the function (perms '(1 2 3)) That looks like one argument to me right?

23:47 gtrak: permx is the breaking one

23:47 KeithPM: OK… Maybe in the recursive calls?

23:48 gtrak: seems like you didn't evaluate something before running it

23:48 so, it's running an old version of the function or something like that

23:48 KeithPM: I think I know why… Looks like when the seq is a singleton, rest is nil...

23:48 Let me take a look at that

23:48 gtrak: nil is still an arg

23:48 KeithPM: OK

23:48 Hmmm

23:48 gtrak: so.. it's whatever's calling that in the first place most likely

23:49 TEttinger: KeithPM, are you sure your parens line up?

23:50 KeithPM: TEttinger Hmmm… I think so, I have pretty much cleared out the repo and the file compiles OK

23:51 TEttinger: yeah, it's just the indents were at different levels in the gist

23:51 nvm just checked

23:54 KeithPM: TEttinger: OK.

23:55 gtrak: The first call is being made in the instarepl

23:55 TEttinger: also I think you may be using nil incorrectly: ##(nil? [])

23:55 lazybot: ⇒ false

23:55 hansel-han: What could I use to get a set where values have a TTL?

23:55 TEttinger: hansel-han, like an expiration date?

23:56 hansel-han: TEttinger: it's for a Who's Online box on a forum. yeah. users get conj'd when they do click around on the forum but fall off when inactive for 5 minutes.

23:58 amalloy: hansel-han: i've used a sorted-map of {timestamp, value}

23:58 TEttinger: I'd use something like overtone/at-at and schedule an event to delete users who have are inactive for 5 minutes, resetting on action

23:58 KeithPM: TEttinger: Do you mean in permx? RH says when there is nothing left in a sequence clojure returns nil not ()… I therefore test for nil? not empty? Is that a problem?

23:58 hansel-han: I've never used core.cache but I see it has a "TTLCache". Perhaps that's an option?

23:59 amalloy: with such a sorted map, you can easily say "remove all entries whose keys are less than x", and updating someone's timestamp is just dissocing them and re-associng to the current timestamp

23:59 TEttinger: KeithPM, kinda. the preferred idiom is using seq to test for non-emptiness, which returns nil on an empty seq and the seq otherwise.

23:59 ,(seq [1 2 3])

23:59 clojurebot: (1 2 3)

23:59 TEttinger: ,(seq [])

23:59 clojurebot: nil

23:59 amalloy: using scheduling or a cache sounds like a lot of work, and less predictable (timing-wise) than doing it yourself

Logging service provided by n01se.net