#clojure log - Feb 02 2015

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

0:00 justin_s3ith: zapho53 (go-loop (let [[f, reply-chan] (<! file-chan)] (>! reply-chan (fs/readFile f))) (go (let [result-chan (chan) _ (>! file-chan ["file", result-chan]) res1 (<! result-chan) _ (>! file-chan res1 result-chan) ...] (console/log resN)) ; something like this I think

0:02 zapho53: basic idea is have a file reader in a go block, and repeatedly pass it file names and get back file contents (which happen to be file names)

0:02 zapho53: justin_smith: Thanks. Looking at it now.

0:02 justin_s3ith: zapho53: that's a rough sketch

0:02 but the basic idea should be right

0:06 zapho53: justin_smith: Sorry to say my fFirst impression is the JS is much simpler :(

0:07 justin_s3ith: zapho53: not a great example

0:07 zapho53: that is to say, there are other things core.async does better, and the simple examples won't really show it

0:08 zapho53: justin_smith: I think the JS is fairly representative of typical nested callbacks.

0:09 justin_smith: I've chosen this simple example because I want to see what typical transposed Node -> CLJS code would look like.

0:10 justin_smith: My concern is whether core.async makes the code easier to understand, ie. simpler. Not convinced so far :(

0:10 justin_s3ith: OK

0:10 dnolen: zapho53: I've programmed JS for 10 years professionally, JS callback code is an abomination

0:10 zapho53: what is your example that you want to see a simpler version of of?

0:10 justin_s3ith: dnolen: you can probably do a much better job of translating that nested callback example than I did

0:11 http://pastebin.com/JM1wEz5z

0:11 zapho53: dnolen: http://pastebin.com/JM1wEz5z

0:12 dnolen: zapho53: justin_s3ith example is not the write way to do it

0:12 zapho53: write a callback to channel helper once and for all

0:12 justin_s3ith: I'm actually glad to hear that

0:12 dnolen: s/write/right

0:13 zapho53: dnolen: OK. I've looked around a bit but can't find a simple JS -> core.async example. I'm pretty new to core.async

0:13 dnolen: I went through Tim Baldridge's great examples but they're all in clj/cljs so couldn't quite make the connection mentally

0:15 dnolen: I'm asking here because for me a canonical JS callback -> cljs/core.async snippet would nail it for me.

0:15 dnolen: zapho53: well first off, expecting to understand core.async in anything less than a couple of weeks is unrealistic

0:16 zapho53: dnolen: No, I've been at it for a while, on and off.

0:16 dnolen: zapho53: a core.async version of your snippet is literally a version w/o callback nothing to see here

0:16 (let [res (<! ...) res (<! ...) ...] ...)

0:16 zapho53: dnolen: I'm half way there. Just missing a kind of mental JS equivalent. I get the conecepts as bits and pieces.

0:17 dnolen: zapho53: there is no JS equivalent, unless you are using js-csp

0:18 zapho53: https://github.com/ubolonton/js-csp

0:19 zapho53: dnolen: The example was taken from an article by Byan Gilbert about his asynchronize library

0:21 dnolen: zapho53: anyways my earlier point still stands. With core.async for that code the only thing that will change is no callbacks

0:21 zapho53: dnolen: Are you saying my snippet doesn't contain callbacks?

0:21 dnolen: zapho53: I'm not saying anything about your snippet other than that is typical JS callback hell

0:22 zapho53: the problem with justin_s3ith "solution" is that it's at the wrong level of abstraction you would never write it that way

0:22 zapho53: dnolen: Yes, that's why I posted it - to see how core.async would improve on it.

0:22 dnolen: zapho53: Node.js fns are have a regular form, it's trivial to write a channelizer thing

0:23 zapho53: dnolen: An example would help. Then I'll let it rest :)

0:23 dnolen: zapho53: which I already answered, it's no different if you used generators - it would look like straightline code w/ no callbacks

0:24 zapho53: dnolen: OK, thanks.

0:24 dnolen: zapho53: your example is covered in this more general case I blogged about http://swannodette.github.io/2013/08/31/asynchronous-error-handling/

0:25 zapho53: your example is covered where ES6 generators are discussed, core.async goes way further, pretty much any example you might encounter about Go has a trivial translation

0:26 zapho53: dnolen: Didn't see that one. Looks exactly like what I was looking for. Thanks.

0:28 PigDude: dnolen: i think that zapho53 is curious about the ellipses in your example. i'd be curious too, how <! is pulling the files off some channel in the right order while the file opening is still non-blocking. also, zapho53's code provides a place to handle each file read error explicitly, whereas your blog post only demonstrates generic error-handling for a series of channel reads, but the <? becomes verbose too with specific error handling (though the

0:29 dnolen: PigDude: your question means you need to read to blog post several more times

0:29 PigDude: and the previous blog entries too

0:31 PigDude: but the hint is that <! is semantically blocking, but not really blocking, once that sinks in the rest makes sense

0:31 PigDude: dnolen: pardon me for not reading the *previous* blog post. the mechanics of <! in this case were not clear from the first post alone (which was a quick read)

0:32 dnolen: PigDude: I'm just pointing out that you were interjecting on a conversation where some expressed at least some experience /w core.async :)

0:32 s/some/soneone

0:32 erg someone

0:32 PigDude: dnolen: i've used core.async in production code, in a library targetting both clojure and cljs runtime

0:33 dnolen: PigDude: right, but I don't think zapho53 was expressing confusion about <!

0:33 PigDude: dnolen: but to be fair it's been a few months. either way, i could see why zapho53 would be confused.

0:33 dnolen: PigDude: could be wrong about that of course, I didn't read all the backlog

0:34 PigDude: dnolen: i could see how to somebody new to core.async the <! usage there could be confusing because without some special handling, those reads would be either blocking or non-deterministic

0:34 dnolen: so mostly i was hoping to provoke further discussion for zapho53's sake :)

0:35 dnolen: PigDude: ok but it's simple, <! is semantically blocking w/o actually tying up a whole thread :)

0:40 PigDude: dnolen: ah, i see my confusion -- you're proposing an API used like (let [f1 (<! (read-file fname1)) f2 (<! (read-file... ] , while i was reading as (let [out (file-reader fname1 fname2 ... fnamen) f1 (<! out) f2 (<! out) ... ] ;; sorry for the confusion!

0:42 dnolen: PigDude: yeah, sorry, my point was that you could write the imperative thing w/o callbacks

0:42 PigDude: dnolen: i was thinking of the question as "how do i express something waiting for n files to be read" and came up with a clunky api in my head, the other version is definitely simpler and more flexible

0:44 dnolen: and then i thought you were saying "he wants to hear from somebody with experience with core.async" and got a little huffy ;)

0:45 dnolen: PigDude: sorry I didn't mean to assume anything, and I sounded like I did

1:30 zacts: hi clojurists

1:42 riceandbeans: do carbs make you sleepy or energitic?

1:47 zacts: I hear energetic

1:50 riceandbeans: so is it protein that makes you sleepy?

1:57 zacts: riceandbeans: milk does, but partly I think due to the lactose

1:57 cow's milk

2:01 ddellacosta: crazy Clojurists, always on about macro-nutrients

2:07 bonanza: Hi,

2:08 does anybody know, why I'm getting HTMLCollection by this expression: (-> dom-node .-children)

2:08 but a normal JS array with this: dom_node.children

2:08 where dom-node/dom_node is some HTML node in my app

2:09 ofc I'm talking about clojurescript in the first sentence

2:39 michaelr525: hmm

2:39 so I wonder, compojure-api or liberator?

2:40 bonanza: michaelr525: are you refering to my question?

2:40 michaelr525: bonanza: nope, that's my own question

2:40 what was yours?

2:40 bonanza: "does anybody know, why I'm getting HTMLCollection by this expression: (-> dom-node .-children)"

2:40 "but a normal JS array with this: dom_node.children"

2:41 "where dom-node/dom_node is some HTML node in my app"

2:41 in another words,

2:41 TEttinger: I'm wondering if .- and internal . are different

2:41 bonanza: I'm trying to translate this to clojurescript with no luck

2:41 document.querySelector("#news-list").children[0].children[0].className

2:42 . means refering to functions,

2:42 .- to properties

2:42 (like (.-length some-array))

2:42 TEttinger: so is dom_node.children getting a function or what?

2:42 bonanza: anyway, how to express this "document.querySelector("#news-list").children[0].children[0].className" in CLJS?

2:43 well, I tried "(-> (reagent/dom-node this) .-children (aget 0) .-children (aget 0) .-className)" but I'm just getting "undefined"

2:43 "children" is a DOM node property

2:44 it's an array

2:44 TEttinger: (-> document (.querySelector "#news-list") .-children first .-children first .-className)

2:44 bonanza: one more thing: "(reagent/dom-node this)" actually returns a dom node, it's a library function but it doesn't matter, it's just a DOM node

2:45 TEttinger: maybe something like that?

2:45 bonanza: let's try

2:46 I got "Uncaught Error: [object HTMLCollection] is not ISeqable"

2:46 that's another story - I should have got a plain JS array but instead I have HTMLCollection returned

2:47 TEttinger: hm

2:47 try taking out the - ?

2:47 I really don't know how the JS underlying this works

2:50 bonanza: I tried, but then I've got an error "object is not a function",

2:51 which is understandable since these are properties, not functions

2:51 TEttinger: I wonder if [0] is actually accessing a property 0

2:52 in which case you'd use (-> document (.querySelector "#news-list") .-children (get 0) .-children (get 0) .-className)

2:53 or, depending on weirdness levels, (-> document (.querySelector "#news-list") .-children (get "0") .-children (get "0") .-className)

2:53 bonanza: it seems like it does,

2:53 this is the output of this expression: "(-> (.querySelector js/document "#news-list") .-children (aget 0))" => "(document.querySelector("#news-list").children[(0)])"

2:54 get is a function for getting from normal CLJ data types,

2:54 aget is for Java(-script) arrays

2:54 TEttinger: I was wondering if it wasn't actually an array

2:55 bonanza: It is - following expression works as exprected: (-> (.querySelector js/document "#news-list") .-children (aget 0))

2:55 i.e. it selects first ("0") node from "children" of #news-list

2:56 but when I try to get first child of *that* node, I get "undefined"

2:56 TEttinger: uh hm. check its type however you do that in cljs?

2:56 (doc type)

2:56 clojurebot: "([x]); Returns the :type metadata of x, or its Class if none"

2:58 bonanza: yeah, but what node are you refering to?

2:58 TEttinger: first ("0") node from "children" of #news-list

2:58 bonanza: function HTMLDivElement() { [native code] }

2:59 TEttinger: yeah I have no idea how this works

2:59 bonanza: it's a normal HTML div element, it's just a way CLJS prints it

2:59 TEttinger: michaelr525: you seem to know something about cljs, which is about 10x more than I can say

3:06 michaelr525: hmm

3:06 what?

3:06 clojurebot: what is not a bug

3:06 michaelr525: what

3:10 Mr0rris0: lol it said that to me too

3:10 what?

3:10 clojurebot: what is http://gist.github.com/306174

3:10 Mr0rris0: what?

3:10 clojurebot: what with pervasive side effects

3:10 Mr0rris0: what?

3:10 clojurebot: what is cells

3:10 michaelr525: TEttinger: I've been disconnected. What was the problem?

3:11 Mr0rris0: what?

3:11 clojurebot: what is exceptions

3:12 TEttinger2: michaelr525: bonanza is having issues with html elements not acting like collections

3:13 bonanza: or - acting like HTMLCollections, not as arrays (as I'd expect)

3:13 michaelr525: why do you expect them to be arrays?

3:15 bonanza: because I'd like to get first elements from them,

3:16 or, in other case (not presented here), I need to loop over such array

3:17 zacts: how can I easily convert a vector of vectors into a map of maps (map the data structure)?

3:18 michaelr525: bonanza: (-> (.querySelector js/document "#mich") (.-children) (aget 0))

3:18 bonanza: in other words, I simply need this "(-> some-HTML-node .-children (aget 0) .-children (aget 0))" to be equal to this "some_HTML_node.children[0].children[0]"

3:18 michaelr525: yeah, that works,

3:19 problem is when I have *two* such expressions in a row

3:19 like in above example

3:19 michaelr525: let me try a sec

3:20 bonanza: works for me

3:20 bonanza: maybe your html structure doesn't match what you expecet

3:20 bonanza: simply put, this "(-> (reagent/dom-node this) .-children (aget 0))" gives me a first parent (some div in my case)

3:20 michaelr525: (-> (.querySelector js/document "#mich") (.-children) (aget 0) (.-children) (aget 0))

3:21 bonanza: but this "(-> (reagent/dom-node this) .-children (aget 0) .-children (aget 0))" gives me nothing, where there *are* children of that node (one child, to be exact)

3:22 this is my compiled invocation (no optimizations): "((reagent.core.dom_node.call(null,this$).children[(0)]).children[(0)])"

3:22 michaelr525: what does (reagent/dom-node) return?

3:23 TEttinger3: zacts: ##(let [vecvec [["a" "A" "b" "B"] ["z" "Z" "y" "Y"]]] (into {} (map #(into {}) vecvec)))

3:23 lazybot: clojure.lang.ArityException: Wrong number of args (1) passed to: sandbox6330/eval12173/fn--12174


3:23 lazybot: java.lang.ClassCastException: java.lang.Character cannot be cast to java.util.Map$Entry

3:23 TEttinger3: gah

3:23 bonanza: michaelr525: just a plain DOM node

3:24 michaelr525: https://github.com/reagent-project/reagent/blob/master/src/reagent/core.cljs#L151

3:24 reagent is a CLJS React wrapper

3:25 michaelr525: in this case, "root node of a mounted component" is my #news-list div

3:26 TEttinger3: zacts: ##(let [vecvec [["a" "A" "b" "B"] ["z" "Z" "y" "Y"]]] (apply hash-map (map #(apply hash-map %) vecvec)))

3:26 lazybot: ⇒ {{"a" "A", "b" "B"} {"z" "Z", "y" "Y"}}

3:26 michaelr525: bonanza: does it work fine when you use javascript api and not dom-node?

3:26 TEttinger3: that has a map as a key and a map as a value

3:27 michaelr525: what's that .' syntax btw?

3:27 bonanza: michaelr525: yes - "document.querySelector("#news-list").children[0].children[0]" gives me desired node

3:28 michaelr525: bonanza: and dom-node returns the same type as querySelector?

3:28 bonanza: the thing is that I just have a container which has "content" and "scrollbar", and after mounting that container node in a DOM, I need to select the "scroller" (div inside) of a "scrollbar"

3:29 michaelr525: yes, it returns a plain DOM node (as in http://facebook.github.io/react/docs/working-with-the-browser.html)

3:29 michaelr525: do you wait until it's rendered?

3:30 bonanza: yes, because React works that way, it operates on "Virtual DOM"

3:31 and to get a plain DOM node, you have to wait till it's "mounted" into, then you can select it

3:32 michaelr525: could you maybe "inspect" the desired element in chrome dev tools and paste a screenshot somewhere?

3:36 bonanza: michaelr525: screenshot of a page?

3:37 or a dom structure?

3:37 drakezhard: Hi does anyone know how to use (proxy) to extend a class?

3:38 bonanza: michaelr525: OK, I'll give you a DOM structure to see

3:43 michaelr525: there's it: http://i.imgur.com/IC0qa2e.jpg

3:45 michaelr525: hmm

3:45 looks ok

3:45 Viesti: argh

3:46 trying to make a custom reporter for cljs.test

3:46 targeting karma

3:46 for some reason, I can't pass a custom :reporter key to the environment :(

3:47 michaelr525: bonanza: maybe try fetching them one at a time and inspecting their types and content?

3:47 Viesti: (run-tests (test/empty-env :karma) 'xxx.app-test)

3:47 this should probably do it

3:48 michaelr525: bonanza: browser-repl for example prints result types like that: #<[object HTMLDivElement]>, #<[object HTMLCollection]>

3:48 so it's easy to know what you are getting

3:50 bonanza: michaelr525: well, the problem is that if I print result by plain js/console.log I got a HTMLCollection, like [item: function, namedItem: function]

3:50 i.e. it prints like this, when I click, there is my "div.scroller" at [0], but I cannot select this by (aget 0)

3:51 michaelr525: i meant to use cljs repl

3:52 bonanza: michaelr525: result will be the same as printing it by ex. (println ...)

3:53 michaelr525: because it just uses IPrettyPrint interface under the hood

3:54 michaelr525: so when you (println (dom-node "#news-list")) you get HTMLCollection?

3:55 and (println (-> (dom-node "#news-list") (-.children)))?

3:55 and (println (-> (dom-node "#news-list") (-.children) (aget 0))?

3:55 i think you get my point

3:55 did you try debugging like that?

3:56 bonanza: michaelr525: actually, (println (reagent/dom-node this)) yields "#<[object HTMLDivElement]>"

3:56 and that's normal since it's a div, after all

3:56 michaelr525: right

3:57 what about the next step and the next one?

3:57 Viesti: has anyone tried to make a custom reporter for cljs.test?

3:58 bonanza: michaelr525: http://pastebin.com/wwLndRDJ

4:00 michaelr525: bonanza: ok, just go on and when you get a result you didn't expect, inspect the problematic node at hand. that's what i'd do..

4:01 bonanza: michaelr525: I'll definately try :)

4:01 michaelr525: thanks for your effort

4:05 michaelr525: let me know what you came up with

4:24 zacts: ah thanks

4:41 dysfun: is there a builtin equivalent to (fn [seq pred] (let [a (filter pred seq) b (remove pred seq)] [a b])) ?

4:41 probably with the argument order reversed

4:47 Glenjamin: ,(doc split-with)

4:47 clojurebot: "([pred coll]); Returns a vector of [(take-while pred coll) (drop-while pred coll)]"

4:47 Glenjamin: oh, not quite

4:51 hyPiRion: it's just (juxt filter remove)

4:53 group-by is a generalisation if you need to separate values even more

4:56 dysfun: juxt is good, thanks

4:56 and does anyone know of a great example of cond-> ?

4:56 it's very difficult to google for

5:01 hyPiRion: dysfun: (cond-> foo true (assoc :a :b)) acts as (assoc foo :a :b), and (cond-> foo false (assoc :a :b)) acts as foo only

5:01 and they chain

5:02 ,(map (cond-> % (odd? %) (* 2) (even? %) (* 3) (neg? %) -) (range -3 3))

5:02 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: % in this context, compiling:(NO_SOURCE_PATH:0:0)>

5:02 hyPiRion: ,(map #(cond-> % (odd? %) (* 2) (even? %) (* 3) (neg? %) -) (range -3 3))

5:02 clojurebot: (6 6 2 0 2 ...)

5:05 dysfun: hrm, so effectively a conditional pipeline?

5:05 hyPiRion: yep

5:06 * dysfun is having a little difficulty wrapping his head around precisely what will come out

5:06 dysfun: so this might be useful, for example for performing a bunch of data correction?

5:06 if data displays this brokenness, fix it this way?

5:07 fairuz: anyone use Tinkerpop stack with clojure here? :)

5:07 dysfun: fairuz: did a very small amount with the orientdb library

5:07 hyPiRion: dysfun: yeah, that's an example

5:07 dysfun: hyPiRion: hrm. any other good cases you can think of, in terms of the high level?

5:08 * dysfun has decided it's about time he got to grips with more of the macros in clojure core

5:13 hyPiRion: dysfun: Well, afaik it was introduced because Rich (?) had a lot of code which looked like this:

5:13 (let [a input, a (if (old-style? a) (update-in a [:res] update-to-new) a), a (if (negative-results? a) (fix-results a) a)] (do-something-with a))

5:14 With cond->, that's (let [a (cond-> in (old-style? in) (update-in [:res] update-to-new) (negative-results? in) (fix-results))] (do-something-with a))

5:16 dysfun: right, so again that's pretty much a data fixing up use case :)

5:17 Glenjamin: it's fairly good in speccing ring middleware

5:17 hyPiRion: Well, that's the examples I managed to come up with right now :p

5:17 Glenjamin: (-> app (cond-> dev wrap-stacktrace))

6:20 dysfun: Glenjamin: ooh yes, that's quite a nice one

6:20 in fact, i've got a pattern for dealing with that that i'm not happy with, so i'm going to rewrite it in that manner

6:22 Glenjamin: it's actually not ideal for that, because you can only do one middleware per condition

6:22 dysfun: that's fine, they're already in functions for grouping

6:22 Glenjamin: unless you do (cond-> test? (-> () () ()))

6:22 dysfun: hrm, that could work

6:33 Viesti: hmm

6:33 is there something like alter-var-root for ClojureScript?

6:34 Glenjamin: you can probably just use def

6:34 Viesti: hmm so how do I override a def in another namespace?

6:41 CookedGr1phon: Hey all. I want something which behaves like a promise mixed with an atom. Is there such a thing without two derefs?

6:42 i.e. I want to promise and deliver later, block on read until it's delivered, but also with the possibility of changing it later on

6:44 Glenjamin: CookedGr1phon: i don't think that exists out of the box, but you could probably reify something

7:03 clgv: CookedGr1phon: maybe you should separate both concerns

7:03 CookedGr1phon: as soon as it is delivered you can wrap it in an atom and pass that along

7:04 CookedGr1phon: that's pretty much what I've done

7:06 clgv: well, then you do not need something merged ;)

7:07 CookedGr1phon: I meant that's what I've done since asking the question

8:21 LukasK: Hi, i tried to add the clojars repo to my maven nexus but it is not working

8:23 clgv: LukasK: did you add it as "proxy repository"?

8:25 LukasK: our nexus admin did, the type of the repo is proxy. but when i click on browse storage (nexus browser UI) there is just a corrupt archetype-catalog.xml

8:26 browse remote is working

8:26 clgv: LukasK: and the index download is enabled as well?

8:26 LukasK: i dont think so

8:26 clgv: LukasK: it is enabled by default if you add a new proxy rep as far as I have seen

8:27 when you enable that, you can search for clojars artifacts in your nexus instance

8:27 LukasK: ok i ask my nexus admin if he enabled the index download, but if it is enabled by default and it is not working there must be another problem

8:28 clgv: LukasK: clojars.org/repo is the location

8:30 LukasK: do you know by any chance how your admin detects "failed logins"? nexus has an rss feed but you cant use that for fail2ban :(

8:32 LukasK: sorry clgv, i have no idea

8:32 clgv: LukasK: ok

8:32 it's pretty weird to have an rss feed for it but not to include it in the log files...

9:05 LukasK: hmm nexus can't download the clojars index

9:07 clgv: LukasK: mine did so yesterday..

9:20 LukasK: hmm strange

9:22 ah it's working :P

9:22 just took forever but now it is working :P

9:49 Scorchin: Hello, I'm using cider in emacs now instead of nREPL. Everything looks good so far, but it's not running the tests for a Clojure test when I run `C-c ,` or `C-c C-,`. It just shows "Testing..." in my mode line but no output. Has anyone seen this before and know what the fix is?

10:00 Never mind, figured it out. Had to add `[cider/cider-nrepl "0.8.2"]` to my :user :profiles hash

10:37 dnolen: just release ClojureScript 0.0-2760, fixes some ns parsing regressions introduced by 0.0-2755

10:39 clgv: dnolen: regarding the versions. is there a roadmap or essential features that need to be done before having some kind of 1.0 release?

10:40 dnolen: clgv: Google Closure Module support, fixing tons of bugs (> 100 open issues in JIRA), optional bootstrap at a minimum

10:41 clgv: dnolen: ok, sounds like a lot of work

10:41 dnolen: clgv: yep

10:41 daniel__: what about 0.1? :)

10:50 muhuk: Greetings. Which convention do you use for constructors in your libs; foo/make-foo or foo/create or foo/new ?

10:50 Glenjamin: module.exports = function(){}

10:51 oh, wrong channel

10:51 duh

10:51 ignore me

10:51 stuartsierra: muhuk: I use just "foo" if it creates a new Foo; "new-foo" if I want to distinguish from returning a pre-existing foo; and "create-foo" if it has side effects (e.g. updating a database)

10:53 gfredericks: concoct-foo

10:53 discover-foo

10:53 muhuk: stuartsierra: so foo/foo, it's likely to be imported as foo

10:53 gfredericks: invent-foo

10:53 llasram: gfredericks: derive-foo ?

10:53 gfredericks: ooh: evolve-foo

10:53 gfredericks: imagine-foo

10:54 prove-foo-by-construction

10:57 stuartsierra: I generally like to name non-side-effecting functions as nouns for the thing they return.

10:57 My side-effecting functions are verbs.

10:57 So "foo" or "new-foo" are pure constructors.

10:57 "create-foo" has side-effects.

10:57 muhuk: stuartsierra: makes sense. Thanks!

10:58 stuartsierra: And yes, I do end up with a lot of foo/foo, but it doesn't really bother me.

10:58 I also break these rules all the time :)

11:01 uris77: rules are meant to be broken :)

11:02 gfredericks: I like breaking the "rules are meant to be broken" rule

11:03 clgv: gfredericks: no self-referential statements allowed! you probably know what this has done to mathmatics ;)

11:04 gfredericks: arguably the prior statement was already self referential

11:04 TimMc: (defn allocate-tmp-stack-frame [] nil)

11:05 gfredericks: (inc TimMc)

11:05 lazybot: ⇒ 88

11:05 clojurebot: No entiendo

11:05 hyPiRion: ,(let [x [1]] (aset (.tail x) 0 2) x) ; <- breaking the rules

11:05 clojurebot: [2]

11:05 clgv: gfredericks: maybe it was just a suggestion ;)

11:05 TimMc: I suppose that should have a ! at the end.

11:05 clgv: gfredericks: or an observation

11:06 hyPiRion: that's to easy to spot - convert an array to a vector and then modify the underlying array values ;)

11:07 hyPiRion: or just do this

11:07 (let [x [1]] (aset (.tail x) 0 x) x)

11:13 sdegutis: I can't help but notice tons of similarities between Clojure and Haskell.

11:17 hipsterslapfight: well they're both functional languages sure

11:18 clgv: but on of them has a, let's say, "suboptimal" syntax ;)

11:18 sdegutis: hipsterslapfight: They both have things like comp and partial, they both have plenty of ways to operate on lists, they both encourage writing small, pure functions...

11:19 hipsterslapfight: about the only thing i really miss from haskell is auto currying

11:20 sdegutis: hipsterslapfight: you don't miss the compile-time type safety?

11:20 hipsterslapfight: sdegutis: no, if that were the case i'd be using haskell still :v

11:20 CookedGr1phon: hipsterslapfight: but in return you get varargs

11:21 hipsterslapfight: CookedGr1phon: sure, i have mixed feeligns on variadic functions though ...

11:24 tcrayford____: sdegutis: haskell was an explicit inspiration for rich when designing cleaxjure

11:24 sdegutis: tcrayford____: huh, I didn't know that

11:24 That explains a lot of the similarities.

11:27 Are Clojure's lazy sequence functions essentially lazy in the same way as any of Haskell's list functions?

11:30 stuartsierra: sdegutis: not really

11:30 sdegutis: oh ok

11:30 stuartsierra: I mean, you can use them to achieve similar ends, but the mechanism is totally different.

11:30 In Haskell, evaluation itself is lazy, even function arguments.

11:30 List laziness just falls out of that.

11:31 Clojure functions always use strict evaluation semantics. Lazy sequences are a special-purpose data structure for achieving laziness in one specific area.

11:34 tbaldridge: Haskell's laziness can also have the same problems as lazy seqs in Clojure. In haskell it's possible to get into a situation where a while chain of calls are held in memory since you haven't executed them yet. Those calls could result in a single integer which would have been cheaper to evaluate when they were constructed.

11:34 So I kindof compare that to some of Clojure's issues with "holding the head

11:34 ... of seqs"

11:39 mdrogalis: tbaldridge: Are promise channels out in any core.async releases yet?

11:39 tbaldridge: not that I know of, puredanger would be the one to ask about that

11:39 mdrogalis: tbaldridge: Okay, thanks man.

11:49 sdegutis: tbaldridge, stuartsierra: ahh, that's very informative, thank you

12:11 zerokarmaleft: it's all just lambda calculus

12:11 clgv: $karma zerokarmaleft

12:11 lazybot: zerokarmaleft has karma 0.

12:11 * clgv had to check

12:16 llasram: (inc zerokarmaleft)

12:16 lazybot: ⇒ 1

12:17 * clgv shivers

12:17 hellofunk: lol that was scary there for a moment

12:24 zerokarmaleft: some people just want to watch the world burn

12:30 dnolen: cfleming: ping

12:30 csd_: Is there any way for me to have a function use global var foo of the current namespace calling the function, rather than global var foo of the namespace the function is in?

12:31 llasram: csd_: That honestly sounds horrific :-). Dynamic vars are the closest you'd get (fortunately)

12:32 csd_: its for testing purposes

12:32 i have a function that references a global ref, and i want to test the function

12:33 (open to alternatives)

12:33 llasram: csd_: It's not without its own limitations, but maybe `with-redefs`?

12:33 justin_s3ith: csd_: it can be hacked with a macro

12:33 but that's macro abuse

12:34 brb getting rid of this silly nick

12:34 csd_: with-redefs looks like it would do the trick

12:35 Frozenlock: Is there a way to list all the methods of a protocol?

12:37 justin_smith: Frozenlock: look up its source?

12:37 Frozenlock: it should be possible via reflection too actually, but all the methods should have to be right there in the protocol def, so I think that's easier

12:37 csd_: llasram-- thx, that works. what would the typical approach be when someone is trying to test a function that uses global state?

12:38 justin_smith: csd_: :P stop using global state maybe?

12:38 csd_: but i need it

12:38 justin_smith: OK

12:38 Frozenlock: justin_smith: yeah I did that, but I get "Can't define method not in interfaces" when I try a method defined in the source :-/

12:38 justin_smith: Frozenlock: that makes me think the arg count doesn't match

12:38 llasram: csd_: I'm actually with justin_smith on this one. I'm skeptical of general actual need for global state

12:39 (modulo wanting to use a library which is written to depend on it)

12:39 justin_smith: csd_: it should be possible to segregate the management of global state from program logic

12:39 csd_: llasram, writing an IRC server?

12:39 Frozenlock: justin_smith: hmm maybe... let me check that.

12:39 justin_smith: csd_: if you really need global state, make a logicless shim (which won't need testing) plus a pure function with all the logic (easy to test)

12:40 csd_: very similar to the trick of using a function to generate the expansion for a macro

12:40 llasram: csd_: Why would that necessitate process-global state, where you wouldn't be able to have e.g. the same JVM running multiple servers simultaneously on different ports?

12:40 csd_: sorry i don't understand the question

12:41 justin_smith: csd_: what if an app needs two or more instances of what your code implements

12:41 llasram: csd_: I'm saying that just because you have state doesn't mean it needs to be "global"

12:41 Frozenlock: justin_smith: Everything looks okay. Would you mind checking this very short example and telling me if there's any obvious problem? https://www.refheap.com/96802

12:41 csd_: i'm implementing global state with a ref, and each client will be its own thread, and will have functions to access global state

12:42 this is an area i'm pretty ignorant in so i'm learning as i go

12:42 llasram: csd_: But why does it have to be global? Why don't the threads start with a reference to the ref passed in as an initial argument instead?

12:43 tbaldridge: csd_: you could still use a ref, but pass it in to each client thread when you construct it

12:43 csd_: i was initially thinking of doing it that way, llasram, but someone smarter than i suggested otherwise, asking why should a single connection need access to everything

12:44 tbaldridge: bleh, didn't see what llasram wrote

12:45 justin_smith: csd_: if it's global, then everyone get's full access, that's no different than passing it as an arg

12:45 *gets

12:46 Frozenlock: all I can think is maybe a typehint that the result is Object? that seems like an odd thing to need though.

12:46 csd_: , do you know of any good reading on architecting this sort of thing?

12:46 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: do in this context, compiling:(NO_SOURCE_PATH:0:0)>

12:46 csd_: sorry my ERC is broken :-/

12:47 -- that was addressed to you

12:47 jesus

12:47 llasram: csd_: https://github.com/stuartsierra/component

12:47 justin_smith: csd_: sicp covers the general concept of transforming global state into explicit args iirc, but that's a tiny part of what it covers, and is actually pretty simple once you do it a few times

12:47 csd_: and yeah, component has some stuff built around that idea too

12:48 (inc llasram)

12:48 lazybot: ⇒ 47

12:48 csd_: ok i'll check it out thanks

12:48 justin_smith: almost forgot to inc dnolen for saving that newb from my shitty code last night

12:48 (inc dnolen)

12:48 lazybot: ⇒ 20

13:06 Frozenlock: ,(clojure.pprint/pprint (->> (clojure.reflect/reflect clojure.lang.IAtom) :members (map :name)))

13:06 clojurebot: #<ClassNotFoundException java.lang.ClassNotFoundException: clojure.pprint>

13:06 Frozenlock: ,(->> (clojure.reflect/reflect clojure.lang.IAtom) :members (map :name))

13:06 clojurebot: #<CompilerException java.lang.ClassNotFoundException: clojure.reflect, compiling:(NO_SOURCE_PATH:0:0)>

13:07 Frozenlock: grr... here's the result (swap swap swap reset swap compareAndSet)

13:07 justin_smith: Frozenlock: perhaps you need to require some namespaces

13:07 ,(require 'clojure.pprint 'cojure.reflect)

13:07 clojurebot: #<FileNotFoundException java.io.FileNotFoundException: Could not locate cojure/reflect__init.class or cojure/reflect.clj on classpath.>

13:07 justin_smith: well, at least we have the pprint

13:07 Frozenlock: :-p

13:08 I just wanted to show what was visible... 'deref' is not there. Any ideas why?

13:09 felixflores: Can anyone tell me why transit is not recognizing java.sql.Timestamp even after I've defined a handler for it? https://gist.github.com/felixflores/20a8cfa034628cae09ac

13:11 Frozenlock: oh dang... deref might be a IDeref method.

13:11 clgv: Frozenlock: there is IDeref

13:11 ah you got it

13:12 future, promise and ref implement IDeref as well

13:12 R0B_ROD: !seen godd2

13:13 clgv: it's "$seen" afaik

13:13 justin_smith: $seen godd2

13:13 lazybot: godd2 was last seen quittingPing timeout: 246 seconds 20 hours and 56 minutes ago.

13:13 clgv: strange order

13:19 felixflores: ignore me. I made a stupid mistake. I didn't send the appropriate MIME type

13:21 justin_smith: Frozenlock: yeah, I see that too, no actual deref in the IAtom methods

13:21 clgv: how do I find out the client IP from a ring request?

13:21 justin_smith: Frozenlock: do you remember if that was maybe protected?

13:21 clgv: I need that for monitoring abuse of the web app

13:21 Frozenlock: justin_smith: No, it looks like deref is an IDeref method, not an IAtom one.

13:22 justin_smith: Frozenlock: aha, for some reason I saw deref in the IAtom source, maybe I was mistakenly looking at an old version of the code

13:22 clgv: ah there is :remote-addr

13:23 Frozenlock: justin_smith: I saw it too (https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Atom.java#L29) which is why I didn't even think of looking in other interfaces.

13:27 tbaldridge: Frozenlock: there is a IDeref interface.

13:28 R0B_ROD: thanks justin_smith

14:20 ben_vulpes: anyone have a handle on clojure-west promo codes?

14:20 i missed the early reg :(

14:25 justin_smith: ben_vulpes: yeah that was over fast, and you're probably in the same boat I am where you would be buying your own ticket

14:26 noonian: us pdxers late to the party should all register together for the 10% discount

14:28 justin_smith: noonian: sounds like an excellent plan

14:28 "clojerk discount"

14:28 noonian: lol nice

14:50 crazydiamond: Hi. Can I wrap function (or macro?) deftest into my function? I.e. to have bunch of tests generated (e.g. to test single function on multiple data)?

14:51 slipset: hmm, maybe look into :pre and :post

14:51 which are like asserts?

14:51 or, better yet, could you show us an example of what you're trying to achieve?

14:52 crazydiamond: ah.. design by contract? :D

14:53 justin_smith: crazydiamond: you can define a test with defn similarly to how :pre and :post are defined https://clojuredocs.org/clojure.core/test

14:53 yeah, :pre and :post are more similar to design by contract, and :test is for tdd

14:53 though frequently/usually people directly use assert or clojure.test/deftest

14:53 crazydiamond: yep, I want TDD

14:54 but I have repetition, like this: http://dpaste.com/09RV7F4

14:54 slipset: crazydiamond: if you're into TDD, checkout midje and autotest

14:54 justin_smith: crazydiamond: you can always define a function to be called inside tests

14:55 crazydiamond: calling deftest inside defn seems odd to me

14:55 hyPiRion: gfredericks: Implementation of factorial using a Y combinator:

14:55 ,(((->(->>(#(% %)(->>(!(->>(($ $)?)#()(->[?])))#()(->[$]))))(->> #()(->[!])))(->>(->>(({(=(+)$)#(*)}(= =)#(* $(!(- $(*))))))#()(->[$]))#()(->[!]))) 10)

14:55 clojurebot: 3628800

14:55 crazydiamond: justin_smith, yes, but every time... if I would have 50 tests, that would be 50 functions...

14:55 arrdem: (inc hyPiRion) ;; that's revolting but you deserve it.

14:55 lazybot: ⇒ 64

14:56 justin_smith: crazydiamond: if there is duplicated logic between the tests, you can define one function, if there isn't there's no point in putting it in a function

14:56 hyPiRion: I implemented SKI as well. Pretty sure that proves Swearjure is turing complete, no?

14:56 slipset: crazydiamond: also, maybe you should look into propertybased/generative testing

14:57 justin_smith: crazydiamond: also, that defn that calls deftest is not doing what you think it does

14:57 slipset: seems like you're using your functions to generate test-data for your tests?

14:57 justin_smith: crazydiamond: you are repeatedly redefining the same test

14:57 crazydiamond: justin_smith, yep. I realized that. my test doesn't fail (but it should)

14:57 huh

14:57 arrdem: hyPiRion: now if only it were TCO'd it'd be useful as well

14:57 justin_smith: crazydiamond: test_run_func would need to be a macro

14:58 crazydiamond: also, camelcase and snake case for functions is a bad idea, it confuses readers. CamelCase is for classes, snake_case is for json / db keystrings. For clojure vars use kebab-case

14:59 hyPiRion: arrdem: Hrm. Need to find a way to implement trampoline.

14:59 slipset: hyPiRion: you need to stop with this hand crafting nonsense and write a clojure2swearjure code-walking macro

15:00 or something ;)

15:00 hyPiRion: slipset: I'm not that far away from doing that actually

15:00 slipset: Don't you write compilers for a living?

15:01 hyPiRion: yes

15:01 I found the SKI properties while working on my swearjure interpreter.

15:02 crazydiamond: thanks for help

15:02 Frozenlock: What's the clojure way of doing the 'extends' part of this: "final public class Atom extends ARef implements IAtom" ?

15:02 crazydiamond: I wonder if I may just change defn to defmacro for test_run_func

15:02 hyPiRion: (Clarification: I don't implement a swearjure interpreter for work)

15:02 tbaldridge: Frozenlock: you can do it with proxy, but I'm not sure that's what you want

15:02 justin_smith: Frozenlock: deftype could do it, or proxy

15:02 tbaldridge: Frozenlock: what are you trying to do?

15:02 justin_smith: wait, maybe deftype can't

15:03 Frozenlock: adding IRef to a deftype without reimplementing all the methods.

15:03 justin_smith: Frozenlock: for interfaces, you can use deftype or defrecord to extend, for concrete classes you need proxy or gen-class I think

15:04 Frozenlock: oh, that's easy - clojure won't complain about partial coverage at all

15:04 Frozenlock: just add an IRef clause to your deftype

15:04 tbaldridge: yeah, it'll just throw NotImplementedException on any unspecified methods

15:04 justin_smith: if/when they are called :)

15:04 Frozenlock: Well, I want those methods...

15:04 justin_smith: Frozenlock: wait, what?

15:05 you want methods from an interface, but don't want to implement them?

15:05 Bronsa: justin_smith: he's ok with the impl provided by ARef

15:05 justin_smith: ahh, right

15:05 slipset: tbaldridge: just curious, the idea of implementing the go-macro as a state-machine, is that something that falls out of Hoare's CSP, the Go-lang implementation of CSP or out of the bright heads like yourself?

15:05 Frozenlock: Bronsa: yes, that.

15:06 Bronsa: Frozenlock: genclass/proxy are the only way to do that ATM

15:06 Frozenlock: If you look at this https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Atom.java#L17, you can see that Atom is just using ARef.

15:06 justin_smith: Frozenlock: you can do that kind of thing with proxy or gen-class

15:06 or just write some java

15:07 Bronsa: or use a custom version of clojure https://github.com/Bronsa/clojure/blob/defclass/src/clj/clojure/interop.clj#L27 ;)

15:08 justin_smith: Bronsa: I'm not sure whether I love that or hate it... definitely one of the extremes, just not sure which yet.

15:10 {blake}: OK, so I'm now maintaining/expanding this app I've built, at the very bottom of which, there's a call (.javaMethod obj). And now I've discovered obj MAY be nil. I can catch the nil going in, or I can make the call at the bottom return nil instead of trying to make the call.

15:11 justin_smith: {blake}: some-> can be helpful for either (depending on your current code)

15:12 ,(some-> "hello" .toUppercase)

15:12 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: No matching field found: toUppercase for class java.lang.String>

15:12 justin_smith: ,(some-> "hello" .toUpperCase)

15:12 clojurebot: "HELLO"

15:12 justin_smith: ,(some-> nil .toUpperCase)

15:12 clojurebot: nil

15:12 {blake}: justin_smith: Interesting. I think. =P

15:13 justin_smith: {blake}: easy enough to turn (.meth O) into (some-> O .meth) and get free short-circuiting on nil

15:13 ianhedoesit: ,(.toUpperCase "hello")

15:13 clojurebot: "HELLO"

15:13 justin_smith: of course this works nicely with chaining

15:13 ianhedoesit: ,(.toUpperCase nil)

15:13 clojurebot: #<NullPointerException java.lang.NullPointerException>

15:14 ianhedoesit: neat

15:14 {blake}: justin_smith: Yeah...Hmmm. That argues for doing it higher level, I think. Because I can make the least traumatic change that, and it's easy to apply as-needed without making large assumptions about...things.

15:15 justin_smith: ,(some-> {:a 0} :b inc) ; also useful without interop

15:15 clojurebot: nil

15:15 justin_smith: ,(some-> {:a 0} :a inc)

15:15 clojurebot: 1

15:17 {blake}: (inc justin_smith)

15:17 lazybot: ⇒ 179

15:27 muhuk: I have a function that takes a namespace as a keyword like this (foo :bar.baz.foobar), it needs to call some bar.baz.foobar/bat then. But bat is not always named bat, it can be something else for another namespace. How do you suggest I set up the protocol here?

15:27 Having an alias of bat with a fixed name comes to mind: (def that-thing bat)

15:32 amalloy: muhuk: that seems like a really weird function to write. why do you have a function looking up arbitrary things in arbitrary namespaces represented as keywords?

15:33 muhuk: amalloy: :) good question

15:34 Mr0rris0: maybe its not arbitrary?

15:34 muhuk: amalloy: it's for a library I'm working on. It provides different backends, and it is extensible

15:34 amalloy: that's why I'm not creating a static table

15:34 amalloy: okay, so put things in a map?

15:35 namespaces are great for compile-time lookups, and maps are great for runtime lookups

15:35 AeroNotix: muhuk: you might want to use defgeneric

15:35 uhm, defmulti, sorry

15:35 too much CL

15:36 justin_smith: muhuk: why not a map from keyword to implementation? or a defmulti yeah

15:36 muhuk: amalloy: I think I couldn't describe my situation. fn in question here: https://github.com/muhuk/clecs/blob/master/src/clecs/core.clj I'll take a param to go find the backend.

15:36 justin_smith: muhuk: the keyword -> symbol -> var-in-ns -> function thing is so indirected

15:37 muhuk: AeroNotix: that's a cool idea, except it'll be a bit backwards maybe

15:37 justin_smith: hi

15:37 justin_smith: yes, you're right

15:38 justin_smith: muhuk: depending on your other needs, any number of those steps in the middle could be skipped by just providing the thing it dereferenced to

15:38 amalloy: muhuk: so like, your caller, whoever is calling this function, has to pass you a namespace they wrote, right? as a keyword, for some reason. and in that namespace there are functions they had to write, yes?

15:38 justin_smith: eg. providing a symbol instead of keyword, var instead of symbol, function instead of var

15:39 muhuk: amalloy: they, or 3rd parties. Not known by clecs.

15:39 AeroNotix: it sounds like you might want a protocol then

15:39 justin_smith: yeah, I would use a multimethod or protocol, that's exactly what those things are for

15:39 amalloy: so, it's no more trouble for them to instead pass you a map, which contains the functions that would have been in a namespace

15:39 AeroNotix: if you know what you're going to call on the object, you pass in an instance of that and call the right methods on it

15:40 muhuk: justin_smith: suppose I give you a backend, as a lein dep, you'd need to read the source to find out which fn to use.

15:41 justin_smith: but you already know the ns (hopefully)

15:41 justin_smith: muhuk: why? you pass me something implementing my protocol or multimethod, I call the protocol / multi methods

15:41 AeroNotix: justin_smith: this

15:41 justin_smith: muhuk: I don't need to know anything about your ns in order to call implementations of my protocol

15:41 just pass me the thing that satisfies it and we are good

15:41 AeroNotix: just a value of something which implements the protocol

15:42 justin_smith: exactly!

15:42 muhuk: I don't want the consumer to know anything more than the ns of the backend

15:42 (if I can get away with it)

15:43 justin_smith: passing a map from keyword to keyword (said keyword needing -> string -> symbol -> var -> deref translation to be used) is just a very inefficient way of doing the same thing

15:43 AeroNotix: you don't need to know *anything* about the backend at all

15:43 justin_smith: muhuk: the consumer doesn't need to even know the ns!

15:43 AeroNotix: muhuk: you already know the operations you want to call on that object, right?

15:43 justin_smith: muhuk: if you implement my protocol, all I need to know is the methods I defined for my protocol

15:43 that's it

15:43 nothing else

15:43 AeroNotix: muhuk: look up defprotocol

15:44 justin_smith: (well that plus an instance of a thing that implements it, but how that's done is none of my business as the caller)

15:44 muhuk: justin_smith: see core.clj, suppose I removed that require

15:44 justin_smith: muhuk: the caller only needs to know it's protocol

15:44 muhuk: it can call the protocol methods

15:44 muhuk: justin_smith: and pass the ns as a symbol or keyword to make-world

15:44 justin_smith: the object implementing those methods is known because it is anonymously passed in

15:45 muhuk: why should the caller give a shit about your ns at all? it shouldn't matter

15:45 AeroNotix: muhuk: make a protocol which mandates `make-world` as a function, pass in a value which implements that

15:45 justin_smith: muhuk: the implementor shouldn't even need to implement an ns

15:45 jackhill: I'm having trouble with clooj: I only get a blank window, nothing is drawn in it. Has anyone else seen this?

15:45 muhuk: justin_smith: ok, how does the consumer call make-world and choose a backend then?

15:45 justin_smith: muhuk: it doesn't chose a backend, the end user passes one to it

15:46 muhuk: jackhill: it used to work for me. Any particular reason why you're not using Lighttable?

15:46 justin_smith: and make-world is a part of the implementor's protocol / is the implementor's multimethod, so they know how to call it

15:47 muhuk: justin_smith: I don't want the backend to be imported by consumer. How does that work?

15:47 jackhill: muhuk: I just wanted to try it out, but I suspect something is wrong with my Java setup, so I would like to get that fixed

15:47 muhuk: you guys are inverting my deps

15:47 justin_smith: muhuk: why not? they are creating something that is designed around the back-end's needs

15:47 muhuk: jackhill: probably. Maybe try another GUI app.

15:47 justin_smith: so why shouldn't they import an interface defined by that backend?

15:48 jackhill: muhuk: do you have a suggestion?

15:48 muhuk: jackhill: not really. You can try compiling a minimal swing example maybe.

15:49 justin_smith: not really, backends should be interchangeable.

15:49 justin_smith: muhuk: make the backends all use the same protocol

15:49 same idea

15:49 mmitchell: I want to catch exceptions based on their ex-data contents. Any suggestions for how to do this? An existing library perhaps? Also, are there any plans to provide this sort of thing in clojure core?

15:49 justin_smith: the backends all use the same protocol, the frontends pass in an instance of a thing implementing said protocol to the backend

15:50 thus both frontend and backend are fully interchangable

15:50 muhuk: if you really must use magic keys in a map instead of a formal interface, just use {:f x :g y} etc. where x and y are just functions, don't force people to implement special namespaces

15:51 muhuk: justin_smith: I still don't like it if the consumer is calling stuff directly on the backends.

15:51 amalloy: mmitchell: slingshot is basically it, i think. maybe gfredericks has something, called catch-data?

15:51 muhuk: justin_smith: map doesn't do it either.

15:51 mmitchell: oh slingshot right!

15:51 justin_smith: muhuk: the consumer is calling what the implementor explicitly passed to it

15:51 amalloy: yeah, he totally does

15:51 mmitchell: will have a look at catch-data too

15:51 amalloy: i'd try catch-data first

15:51 mmitchell: cool will do

15:51 justin_smith: muhuk: doesn't do what?

15:52 muhuk: are you aware that a namespace is a map from symbols to vars?

15:52 muhuk: justin_smith: I don't know which backends are available, so I can't create a map.

15:52 justin_smith: it's just less flexible because we use it in special ways via require and resolution

15:52 but if you don't need those features, why use an ns?

15:52 muhuk: I think you are being silly

15:53 muhuk: well, you can always move on. It's not a first on IRC.

15:54 justin_smith: muhuk: I wanted to be sure you understood your options, and the extra complexity you are imposing on yourself. If the options are too simple and you prefer the complexity, have at it, hope that's enjoyable to you. No biggie.

15:55 AeroNotix: boom

15:55 mmitchell: +1 on catch-data looks nice and simple. Thanks!

16:00 csd_: - I'm still confused after watching Stuart Sierra's two videos on components, and reading the example code. At some point I think a global var needs to be defined if you're going to let concurrent threads have access to shared state, no?

16:01 @justin_smith

16:01 dnolen: ClojureScript now support Nashorn based REPL https://github.com/clojure/clojurescript/commit/d0c9451035d3a9adf9a32e16e759d1e4384268dc

16:01 justin_smith: csd_: for shared mutable state you can pass an atom to each component

16:01 amalloy: csd_: no, you can pass those threads whatever state you want without a global

16:01 justin_smith: csd_: it's not global because it could pass a different atom to a different set of components

16:01 what amalloy said

16:02 csd_: would you be able to put in a pastebin a small sketch of what you mean?

16:02 tbaldridge: csd_: if you start and stop a system within a single let you can store the state as a local. I do this all the time when writing tests.

16:03 csd_: if have a local context, create a ref inside it, and then pass the ref to threads, will one thread's mutation of the ref show up in the other threads ?

16:03 justin_smith: absolutely

16:04 wouldn't be much point to refs if it didn't in fact

16:05 csd_: ok seems a bit clearer now

16:07 so crudely, the better solution would be something like: (let [state (ref {})] (map #(do-stuff state %) [threads]))

16:07 justin_smith: csd_: something with that basic outline, yeah

16:07 csd_: ok

16:08 justin_smith: csd_: advantage being, of course, that testing is now much easier

16:08 if you do it right

16:09 csd_: this is one of those concepts that coming from python etc takes a while to get used to

16:09 amalloy: gfredericks: wait, i remember us talking about the locals-capture feature in catch-data, and you removed it, but i thought you also made throw-data into a function instead of a macro (since it now doesn't have any macro-y features)

16:10 justin_smith: csd_: it's a place where we have options we can articulate, while imperative languages leave only one way to do it for the most part :)

16:11 gfredericks: amalloy: well it does have the macro-y feature of not making noise in your stacktrace

16:11 amalloy: hah. well, fair enough

16:12 gfredericks: I remember talking about that and the other point was that anybody tring to use throw-data not in the call position is a weirdo

16:12 justin_smith: us weirdos get no respect

16:14 amalloy: gfredericks: https://www.refheap.com/d80a9dd79c1374bae013e88a4

16:14 all this has happened before, and will happen again

16:14 gfredericks: I look forward to round 3

16:15 amalloy: feature request: add to docstring for throw-data: "macro instead of a function to protect you from yourself, you weirdo"

16:16 gfredericks: patches welcome

16:18 ~patches is <reply> welcome

16:18 clojurebot: Roger.

16:18 Glenjamin: what is throw-data from?

16:19 is throw-data just comp throw ex-info ?

16:19 amalloy: Glenjamin: yes

16:19 gfredericks: github.com/gfredericks/catch-data

16:19 Glenjamin: presumably throw being a macro means that doesn't just work

16:19 gfredericks: throw isn't even a macro but yeah that doesn't work

16:19 Glenjamin: s/macro/special-form

16:20 gfredericks: ,(comp throw ex-info)

16:20 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: throw in this context, compiling:(NO_SOURCE_PATH:0:0)>

16:20 gfredericks: ,(let [throw #(throw %)] (comp throw ex-info))

16:20 clojurebot: #<core$comp$fn__4458 clojure.core$comp$fn__4458@3fceb526>

16:20 Glenjamin: makes sense

16:21 gfredericks: I'm going to go add a comment above (defmacro throw-data) to save amalloy some time next time

16:22 amalloy: ;; amalloy please stop bothering me, you agreed this should be a macro

16:37 so, i have written two different functions in my config-map-munging file that look like (reduce (partial apply assoc) x y), and i can't decide whether it would be more readable or less if i extracted that out into a function. also i don't know what name i would give to (partial reduce (partial apply assoc))

16:37 er, assoc-in

16:38 gfredericks: amalloy: this isn't what reduce-kv is for is it?

16:38 amalloy: i'm reducing over a seq, not a map

16:38 reducing *into* a map

16:39 Glenjamin: isn't that (into {}) ?

16:39 amalloy: Glenjamin: yeah if it were actually assoc (like i first said) it would be. but i'm using assoc-in

16:39 Glenjamin: right

16:39 amalloy: on a seq like ([[:x :y] 1] [[:a] 2])

16:40 DerGuteMoritz: how about assoc-into

16:40 amalloy: that's cute

16:40 DerGuteMoritz: hehe

16:41 gfredericks: ininto

16:41 uptown`: is there a lein plugin to profile performance or a way to wrap tests with a profiler to get a sense of how efficient a given form or fn is?

16:42 tcrayford____: uptown`: that's intensely difficult on the JVM

16:42 uptown`: thought so but we live in hope

16:42 tcrayford____: generally I'd recommend using FlightRecorder for profiling, and criterium for benchmarking

16:43 e.g. the JVM after the JIT has warmed up, will sometimes completely eliminate benchmark code, etc

16:45 http://docs.oracle.com/javacomponents/jmc-5-4/jfr-runtime-guide/run.htm for flight recorder (assumes you're on an oracle jvm iirc)

16:45 https://github.com/hugoduncan/criterium for criterium

16:45 though note you'll want to turn off leiningen's default jvm options - it turns off most of the advanced JIT optimizations

16:46 (just throw `:jvm-opts ^:replace ["-server"]` in your project.clj, or in a benchmark/profile specific thing)

16:47 note: I've seen perf differences of 5000x times different because of different benchmarking code, different ordering on benchmark runs etc. It's *incredibly* difficult to measure perf numbers on the JVM and have them be useful

16:57 uptown`: thanks for the pointer

16:57 i'll see if i can get any traction

17:00 tcrayford____: uptown`: sure. I'm giving a talk on clojure and performance at a user group tomorrow, so this has been on my mind a bunch lately :)

17:01 uptown`: glad I could help :)

17:03 Bronsa: tcrayford____: will you upload slides/notes somewhere? I'd be interested :)

17:03 tcrayford____: Bronsa: I'll (hopefully) post a video somewhere

17:03 Bronsa: ah, that's even better

17:06 justin_smith: tcrayford____: for that 5kx diff, were lazy seqs being forced or not a factor?

17:07 tcrayford____: justin_smith: nope, just reordered benchmarks

17:07 like

17:08 (do (bench a) (bench b)) (do (bench b) (bench a)) performs astonishingly differently

17:10 justin_smith: image of the ancient aliens guy, caption: "hotspot"

17:11 tcrayford____: exactly

17:14 uptown`: *cries* so true

17:24 TimMc: ~aot

17:24 clojurebot: aot is Ahead Of Time compilation

17:24 TimMc: ~aot

17:24 clojurebot: http://i.qkme.me/3vb225.jpg

17:47 gfredericks: ~aot |was| so ahead of its time

17:47 clojurebot: In Ordnung

17:50 cfleming: dnolen: pong

17:52 denik: I'm having trouble writing integration tests that depend on channels. For example: I publish 100 messages to rabbitMQ, then, in a go-loop I want to pull each & count to make sure I have 100.

17:53 This is mostly to make sure the go-loop pulls down every message rather than to test rmq

17:54 cfleming: tcrayford____: I'd also be very interested in video/slides/notes to your talk

17:55 dnolen: cfleming: so how do I get Cursive to understand my Clojure Maven project?, also how can I setup a REPL? Do I just need to specify the entire REPL command? Include nrepl?

17:55 cfleming: if this is documented somewhere I'm more than happy to read over the setup

17:56 hiredman_: denik: pulling from rabbit mq is blocking io you should not be doing in a go block

17:56 cfleming: dnolen: Not really documented unfortunately. This is about as good as it gets: https://cursiveclojure.com/userguide/projects.html

17:56 denik: horedman: how then?

17:57 hiredman_: I need someway to feed rmq into core.async chans

17:57 cfleming: dnolen: It should just work. You can set up a REPL using the "Use normal process" option instead of "Run with Leiningen". That does assume nREPL is on the classpath, right.

17:58 dnolen: That basically starts a Java process with the classpath of the module you select, and starts an nREPL server

17:59 dnolen: Actually, I lie - it will automatically add the version of nREPL shipped with Cursive to the classpath.

18:00 dnolen: So you should just be able to run it.

18:00 dnolen: cfleming: what Module am I supposed to be selecting? "Java"?

18:01 cfleming: dnolen: Right, you set it up as a Java project

18:01 dnolen: But do you already have a Maven project you want to import?

18:01 dnolen: cfleming: yes it's a pre-existing Maven project

18:02 cfleming: so I should import it?

18:02 cfleming: dnolen: Ok, then you want File->Import project, Import from external model, Maven, then follow the options

18:13 dnolen: Back in a bit - if that doesn't work, let me know the steps you're trying and I'll try to reproduce. I'll update that doc too, since a few people are using Maven now

18:14 dnolen: cfleming: ok so I imported but the same thing always happens for me, nothing is resolveable

18:14 cfleming: i.e. the source code

18:14 AeroNotix: Which kafka client do people recommend/

18:14 dnolen: is all highlighted

18:14 AeroNotix: ?

18:15 cfleming: dnolen: Has it created source dirs in the right places? Blue folders in the project view?

18:15 AeroNotix: people are using just maven for clojure?

18:15 dnolen: cfleming: blue java folder but not a blue clj one

18:15 AeroNotix: yes

18:15 AeroNotix: dnolen: why?

18:15 dnolen: AeroNotix: lots of reasons

18:16 cfleming: AeroNotix: It just works, I guess

18:16 AeroNotix: dnolen: such as?

18:16 dnolen: AeroNotix: I'm not going to enumerate them for you

18:16 AeroNotix: :(

18:16 cfleming: dnolen: If you mark the folder as source, are things resolved correctly? Right click, mark as source

18:16 AeroNotix: I'm genuinely curious what I might be missing out

18:16 on

18:16 cfleming: dnolen: Sorry, right click, mark directory as, source

18:17 dnolen: cfleming: ok that fixed that thanks!

18:17 amalloy: AeroNotix: better integration with a zillion java tools is one thing, i imagine

18:17 AeroNotix: amalloy: such as the IDEs and things?

18:17 cfleming: dnolen: What you'll find is that that source folder will be removed next time your project is synced

18:17 dnolen: You'll have to add something to your POM so that Maven knows that's a source root

18:18 dnolen: Whatever the :source-paths Maven equivalent is

18:20 dnolen: Actually, check the Clojure project for inspiration, looks like it uses a Clojure Maven plugin to do that

18:20 dnolen: cfleming: hrm REPL interactions don't work

18:20 I mean the REPL works

18:20 but commands to send stuff to the REPL don't

18:24 cfleming: ok got it working, a little weird but this is good enough for me

18:25 cfleming: dnolen: What did you have to change?

18:25 dnolen: For the REPL, I mean?

18:26 dnolen: cfleming: I think I had to exclude some directories?

18:27 cfleming: dnolen: That sounds strange - normally it should just require an open active REPL, and to be doing it from a Clojure source file

18:29 dbronico: hey all. i'm new to cljs and am wondering what the idiomatic way to store the response from an xhr call would be in cljs without the callback function being a giant function with all of the program logic.

18:30 dnolen: cfleming: anyways this is good enough for me, after all this time in Cursive for ClojureScript dev now I just want to use it all the time

18:30 dbronico: you should look into core.async

18:30 amalloy: cfleming: put dnolen's testimonial on your website somewhere

18:31 raspasov: cfleming: I've always been connecting to a remote REPL (running in a terminal window) and it works great for me; just trying to run a local version to test out the break points etc - I believe it has to run locally right?

18:32 dbronico: dnolen: I actually was, but was a little stuck on how to store. like, do this async thing and put it on the channel, but I can't have below it, (def xhr-response (take! the-chan)), can I?

18:33 raspasov: just trying to make it work with https://github.com/ninjudd/lein-protobuf , for some reason the protocol buffer classes don't get added to the classpath I believe and I get CompilerException java.lang.ClassNotFoundException when try to run locally

18:33 dnolen: dbronico: you can as long as you're in a go block

18:33 raspasov: maybe it doesn't play nicely with the leiningen plugin somehow?

18:33 dbronico: dnolen: oh, ok. and then I can use xhr-response outside of the go block?

18:34 cfleming: dnolen: Great, good to hear :-)

18:34 dnolen: dbronico: by storing it somewhere sure

18:34 cfleming: dnolen: I have a build coming out in the next day or two, hopefully the following one will have CLJS REPLs based on all the new hotness

18:35 dnolen: dbronico: you might want to ask your question in the #clojurescript channel, show us the JS code you would write and someone can show you how to do it better in core.async

18:35 cfleming: sweet!

18:35 dbronico: dnolen: oh, ok. i didn't know it had a dedicated chan. thanks!

18:36 cfleming: raspasov: No, you can run it remotely too, but you'll have to create a remote debug connection. Run->Edit Configurations->+->Remote, then start your JVM with the parameters it shows you

18:36 raspasov: Connect the remote debugger then the remote REPL, all should work

18:36 raspasov: cfleming: oh great, that's cool, let me try

18:36 cfleming: raspasov: Someone confirmed on the mailing list the other day that that works, let me know if you have problems

18:43 raspasov: cfleming: "Run->Edit Configurations->+->Remote, then start your JVM with the parameters it shows you" - are there special parameters I need to add when running lein repl?

18:45 cfleming: raspasov: Yeah, where it says "Command line arguments for running remote JVM" you need to add those to your JVM startup, in your project.clj

18:46 raspasov: hm I don't see that, could it be because I'm on 13.1 ?

18:50 http://i3.minus.com/iXvgpqOA3r2J7.png

19:08 trptcolin: how (if at all) does one get korma (with the postgres jdbc adapter) to tell them how many rows got updated?

19:09 seems like i always get a single record (if any were updated) or an empty seq

19:09 w/ no way to see how many succeeded

19:09 tcrayford____: trptcolin: are you using RETURNING ?

19:10 * tcrayford____ tries to remember postgres

19:10 trptcolin: oh clojure.java.jdbc is all good

19:10 tcrayford____: oh ok :/

19:11 * tcrayford____ doesn't know anything about korma

19:11 * tcrayford____ doesn't want to know anything about korma

19:11 trptcolin: well, "all good" meaning there exists some path where i can get what i want

19:11 yeah... i really like the idea of being able to share pieces of queries, something something composable something

19:12 but every library is frustrating when i'm in the internals trying to figure out a monkeypatch to make it work like i want :)

19:12 {blake}: I tried Korma on Friday, along with Yesql, and I'm using straight JDBC.

19:12 raspasov: ORM = OMG :)

19:13 rhg135: indeed

19:13 tcrayford____: trptcolin: sorry I can't help more :(

19:13 trptcolin: tcrayford____: no worries, thanks for the try :)

19:14 cfleming: raspasov: That's the remote REPL - the config you want is just called "Remote", it's for remote debugging

19:15 raspasov: You need two connections to the remote JVM - the debugger and the REPL

19:15 raspasov: cfleming: ah got it, I'm blind

19:15 {blake}: cfleming: As long as you're hanging around...what's the magic for starting the debugger?

19:15 raspasov: /don't follow instructions carefully/ lol

19:16 I'm sure cfleming is having a hard time working with all of asking questions :-)

19:16 all of us*

19:16 {blake}: I hardly see how we can be held accountable for a lack of adequate cloning technology.

19:18 raspasov: haha well

19:22 AeroNotix: ok what's the deal with lazy-seqs

19:22 I have found some code which blocks outside of a lazy-seq, but works inside of one

19:22 "works"

19:22 amalloy: AeroNotix: ?

19:23 AeroNotix: hmm

19:23 it's 1:21am

19:23 Should I be doing this....

19:26 noonian: AeroNotix: what do you mean 'works inside' of lazy-seq? if you aren't every realizing the lazy seq it might just never be executing the blocking code

19:26 AeroNotix: noonian: yeah that's what I just realised

19:27 noonian: heh

19:27 AeroNotix: this is inside a library

19:28 noonian: what library/code?

19:28 AeroNotix: clj-kafka

19:30 I actually can't get it to read messages out of a kafka queue for some reason

19:30 and the laziness inside the read with clj-kafka covered up something for a while

19:32 TimMc: Ugh, just got bit by http://dev.clojure.org/jira/browse/CLJ-1232

19:32 noonian: sounds frustrating. I have zero experience with kafka so probably can't be much help. If you posted some code snippets someone might notice something funky.

19:32 AeroNotix: noonian: just run of the mill stuff really. Straight out the README.

19:32 TimMc: (defn foo ^Hint [] ...) fails when a.b.Hint is not imported in the namespaces that *calls* that fn.

19:33 cfleming: raspasov: If it weren't for you people I'd be at version 7 by now, instead of still in beta :)

19:33 AeroNotix: TimMc: :(

19:33 raspasov: cfleming: lol

19:33 cfleming: {blake}: Are you having problems starting the debugger?

19:33 {blake}: cfleming: Yes! Uh...where is it? =P

19:33 cfleming: raspasov: Actually, that's mostly true of my daughter rather than tech support

19:34 {blake}: Haha, I see

19:34 raspasov: raspasov: haha well

19:34 cfleming: haha well

19:34 cfleming: {blake}: See here under Starting a debug REPL: https://cursiveclojure.com/userguide/repl.html

19:35 {blake}: There's no real doc on this at the moment, in the meantime you can try https://confluence.jetbrains.com/display/IntelliJIDEA/Debugger

19:35 {blake}: That's Java specific but mostly relevant

19:35 There are bugfixes for the debugger in the next build too

19:36 {blake}: cfleming: Oh, okay, cool, I'll give it a shot. I didn't think that would work.

19:36 cfleming: When are we going to be able to buy?

19:36 cfleming: {blake}: Yeah - make sure you're on 0.1.44, lots of fixes there

19:36 {blake}: Not sure, but the shortlist for a version 1 is getting shorter

19:37 {blake}: cfleming: Cool. Yeah, I'm up-to-date.

19:45 andyf: TimMc: Fortunately clj-1232 has a pretty easy workaround - add import, or edit function to fully qualify the type. I was going to recommend voting, but see you already have

19:46 cfleming: TimMc andyf: The other workaround is to type hint the var, not the args vector

19:47 TimMc: andyf: Easy, but annoying and bloaty. Also, I'm annoyed at Rich for saying it shouldn't be fixed at all.

19:48 cfleming: TimMc: Yeah, I hate that bug.

19:49 TimMc: Fortunately type hinting the var works fine, so that's what I do everywhere.

19:49 TimMc: With an imported class, I mean.

19:56 TimMc: cfleming: I found if I put a newline after the arity hint it's not so bad -- it increases vertical space use, but at least the giant Java class names don't push the arglist waaaay over.

19:56 cfleming: TimMc: Any reason you don't want to hint the var?

20:00 OldTree: is it possible to use Om's transact function outside of a component?

20:01 amalloy: yeah, hinting the var is the thing you're supposed to do

20:02 i basically regard hinting the argvector with a non-primitive type to be an accidental feature and am not terribly surprised when it doesn't work

20:02 hiredman_: which is hilarious, because it used to not work at all, until someone tried to unify the two ways to hint the return type

20:03 cfleming: amalloy: I'd say based on the doc, you're *supposed* to hint the arg vector, but no-one does because of this bug

20:03 amalloy: what doc?

20:04 cfleming: amalloy: http://clojure.org/java_interop#Java%20Interop-Type%20Hints

20:04 "For function return values, the type hint can be placed before the arguments vector:"

20:05 The doc for fn and defn make no mention of type hints at all

20:06 I guess the only advantage is that you can hint individual arities differently

20:07 Although IMO that's probably bad, or at least confusing, form anyway

20:15 gfredericks: dangit I'm writing a little data diff/patch library

20:15 how could this have happened.

20:15 dangit: Are you taking my name in vain?

20:16 gfredericks: no in vein

20:16 also sometimes in vane

20:21 cfleming: I've always wondered who someone is - they must get pinged a lot

20:22 amalloy: hey, speaking of, whatever happened to the guy named so?

20:22 $karma so

20:22 lazybot: so has karma -33.

20:29 gfredericks: oh is that why so gets dec'd

20:30 amalloy: gfredericks: yeah, numerous times i heard people complain that he kept making the word "so" get the username-highlight treatment in their clients

20:31 gfredericks: (dec so) ; serves him or her right

20:31 lazybot: ⇒ -34

20:40 gfredericks: there we go https://github.com/gfredericks/minus

20:40 now it just needs a decent algorithm or two

20:41 amalloy: ahaha that algorithm. too good

20:42 gfredericks: hey man it works great and anybody can understand it

20:42 amalloy: i was like, wow, what algorithm could be correct but trivial

20:42 question answered

20:56 justin_smith: gfredericks: seeing the defmulti for diff, I expected something using data.diff at first

20:57 (inc dangit)

20:57 lazybot: ⇒ 1

21:12 gfredericks: justin_smith: well it could but that would be an impl detail

21:27 dnolen: https://github.com/omcljs/om

21:29 julianleviston: Building a thing to run n things in “parallel” using core.async go blocks… but I want the results to be co-ordinated into a set of results and the main body to block until the results are in, at which time it does something contingent on them finishing. This code is currently sitting in a doseq block… is there a nice way to do this? What would you call this? is it fanning? I can only think of doing it via a bunch

21:29 n go blocks, then a blocking loop that takes n values off a “results chan”… is that a good way?

21:37 Maybe I’ll take a stab at that and see what happens.

21:38 justin_smith: between "doing it via a bunch" and "n go blocks" I think your irc client ate something


21:43 bunch of n go blocks, then a blocking loop that takes n values off a “results chan”… is that a good way?

21:43 amalloy: julianleviston: there is a maximum length to the length of an IRC message

21:44 justin_smith: julianleviston: your message is cut off (even eariler this time)

21:44 amalloy: your client doesn't seem to know what it is

21:44 julianleviston: Maybe my expressions capacity got broken

21:44 ah....

21:44 That’s weird.

21:44 lol

21:44 Building a thing to run n things in "parallel" using core.async go blocks, but I want the results to be co-ordinated into a set of results and the main body to block until the results are in,

21:44 at which time it does something contingent on them finishing.

21:45 This code is currently sitting in a doseq block. Is there a nice way to do this? What would you call this? is it fanning?

21:45 I can only think of doing it via a bunch of n go blocks, then a blocking loop that takes n values off "a results chan"... is that a good way?

21:45 Hopefully all that came thru :)

21:45 (it may have been due to strange chars I was typing)

21:46 justin_smith: julianleviston: that idea looks perfectly reasonable (now that I know there is nothing insane hiding in the truncating part)

21:46 julianleviston: haha :)

21:46 ok thanks.

21:46 justin_smith: julianleviston: a function that spawns one of the worker go blocks

21:46 and then a go block that sends your inputs to those channels, and then waits on all of them coming back, perhaps with a timeout or whatever

21:47 that is, function that spawns the worker go blocks, then run it N times etc.

21:50 julianleviston: yep. Just seems a little clunky to write it myself. I kind of assumed there would be prior work... like ?oh, that?s a fanning pattern, just use the fan function from blah blah? or something...

21:51 but I’m halfway done writing it so, all good :)

21:51 justin_smith: julianleviston: oh yeah, that likely exists, I can't name the function though

21:51 haha

21:52 drsco: julianleviston: have you looked at pipeline or pipeline-async?

21:52 julianleviston: drsco: do they work on cljs?

21:53 drsco: yep

21:53 julianleviston: drsco: I did look at them and followed a tute oh them… but I wasn’t sure coz the tute was for clj, not cljs.

21:53 drsco: used pipeline-async yesterday

21:53 julianleviston: drsco: ah ok. cool… that sounds like it’d be helpful...

21:53 I find the dox a bit… terse.

21:53 drsco: yeh, i didn't see that mentioned on the clojure docs either, but i found some docs elsewhere that did mention. lemme see if i can find the link.

21:54 julianleviston: good if you know what they’re talking about...

21:54 drsco: for sure. precise, but hard to puzzle the use case unless you've seen it before.

21:55 julianleviston: drsco: no, not really… I think it’s hard to even see the use case sometimes, even if you’ve had it before...

21:55 drsco: julianleviston: check this http://www.core-async.info/reference/apidocs#pipeline_async

21:56 julianleviston: drsco: until you’ve built it yourself… then you’re like… “oh… this thing here!”

21:56 yeah that site is great!

21:56 drsco: page is slow. painful client side rendering, but nice looking.

21:56 julianleviston: ironically for about 2 weeks I could never get it to load on safari… works fine on chrome tho.

21:56 drsco: i like how it breaks out the clojure and cljs source. very handy.

21:57 weird. looks like maybe it's polymer or material design type of thing. probably relying on something slightly experimental.

21:57 julianleviston: drsco: isn’t it the same as the main clojure site for core async?

21:57 drsco: I really don’t undrestand what the desc of pipeline-async means. :(

21:57 drsco: the part from the docstring is. no inlined source on clojure docs i don't think.

21:58 julianleviston: drsco: ah ok.

21:58 drsco: hmm...well i think it does what you're asking for. let me see if i can break it down. i'm pretty new to this still.

21:58 julianleviston: drsco: I guess pipeline-async handles the “paralleling

21:58 “paralleling” part...

21:59 and then I’d write a doseq n underneath that blocked the main go block until I had all the results in?

21:59 justin_smith: julianleviston: yeah, it does the fanning out, and then you can then feed it into your own fan in (via the design of the function parallelized)

21:59 julianleviston: got it.

22:00 drsco: right, af is a transducer that runs on the fan in part.

22:00 julianleviston: um…

22:00 it is?

22:01 I’m not confident I can write a transducer, and that’s not what the doc says.

22:01 drsco: it could just be a simple 1-to-1, but it doesn't have to be

22:01 wait, i'm wrong. my mistake

22:01 julianleviston: I’ve looked quite a bit into transducers, but they’re complex.

22:01 drsco: phew! :)

22:01 ironically it’s complex to understand them because they’re so simple.

22:02 drsco: af is the async function. derp.

22:02 julianleviston: yay! :)

22:02 JustinusIII: does transducers require understanding of reducers?

22:02 drsco: but using them isn't so tricky.

22:02 http://matthiasnehlsen.com/blog/2014/10/06/Building-Systems-in-Clojure-2/

22:02 julianleviston: drsco: using tranducers is easy. Making them is tricky.

22:02 drsco: i enjoyed that article a lot. nice graphic.

22:02 justin_smith: JustinusIII: not really - transducers are stackable transformations you can put on some source of data

22:03 julianleviston: uhm (filter isafoo?) is a transducer

22:03 julianleviston: or (map frob-it)

22:03 ,(type (map even?))

22:03 clojurebot: clojure.core$map$fn__4507

22:03 julianleviston: justin_smith: sorry I mean making a function that creates transducers.

22:03 justin_smith: ,(fn [] (map even?))

22:03 clojurebot: #<sandbox$eval49$fn__50 sandbox$eval49$fn__50@799b710e>

22:03 justin_smith: :P

22:04 julianleviston: they may seem weird, but they are not actually super hard

22:04 drsco: and they're composable with comp, stackable as you said

22:04 julianleviston: justin_smith: what do you call functions that create transducers?

22:04 justin_smith: right. They do what I expected eg. nested usage of map to do when I first learned clojure

22:05 ,(sequence (comp (filter even?) (map inc)) (range 10))

22:05 clojurebot: (1 3 5 7 9)

22:05 justin_smith: there's a pair of transducers composed and applied to a lazy-seq

22:05 TEttinger: it's weird how comp is in reverse order here

22:05 or not reversed I guess

22:05 justin_smith: TEttinger: middleware style :)

22:06 drsco: yeh, it's mindbending

22:06 just a little

22:06 julianleviston: justin_smith: yeah, the thing that is hard is creating your own transducer factory.

22:06 justin_smith: julianleviston: when do you need to do that?

22:07 julianleviston: justin_smith: when you want to write map, or something different than the provided ones.

22:07 drsco: julianleviston: take a look at the streaming-buffer example in the link i posted above

22:07 julianleviston: drsco: why?

22:07 drsco: or log-count in the same one, that one is a bit simpler

22:08 justin_smith: OK, but one main point of transducers is not needing to implement eg. map over and over - you just pull in the transducers that have them all defined

22:08 drsco: it describes how to make your own transducing function

22:08 JustinusIII: reducers in Joy Of Clojure 2 was scary....I didn't have the courage to look into transducers after that

22:08 justin_smith: JustinusIII: I think it's much easier when you get to a point where you've done the stuff they abstract over enough times to realize the benefit

22:09 julianleviston: drsco: I’m pretty familiar wth transducer usage.

22:09 drsco: just not the nomenclature...

22:09 drsco: ah, ok, got it.

22:09 julianleviston: drsco: aparently.

22:09 drsco: so map is an example of a transducing function?

22:10 drsco: a “tranducing function” is any function that has a single-arity that produces a transducer, yes?

22:10 drsco: perhaps i'm not using the right nomenclature either. should probably verify.

22:10 justin_smith: julianleviston: if you provide one arg, yes

22:10 JustinusIII: justin_smith: hmmm....what are the best resources to learn transducers?

22:10 justin_smith: julianleviston: the single arg thing isn't a pre-req

22:10 julianleviston: justin_smith: that’s a single arity, is it not?

22:10 justin_smith: ah ok.

22:11 justin_smith: julianleviston: right, but the arg count is an implementation detail is all I am saying

22:11 julianleviston: I think rich hickey’s trandsucer talks are the best. He explains well.

22:11 justin_smith: a transducer with two or three args could exist, as long as it has the right behaviors

22:11 drsco: justin_smith: because map, filter, et al already had two and three arity versions, right?

22:11 justin_smith: I like this talk by Rich Hickey on transducers. Opens with the classic burrito joke. https://www.youtube.com/watch?v=6mTbuzafcII

22:12 drsco: right

22:12 julianleviston: he gives a really nice intro to what the point of transducers is

22:13 julianleviston: even just the first couple minutes is very informative

22:13 julianleviston: justin_smith: it is a great talk. As is the precursor talk...

22:13 I really liked his core async ones, too...

22:13 plus, this page is obviously pretty useful… http://blog.cognitect.com/blog/2014/8/6/transducers-are-coming

22:20 god I can never remember which of <! or >! is which, or which order they go in. GUH

22:21 justin_smith: julianleviston: in a let block, the > or < will point in the direction the data is going

22:21 julianleviston: justin_smith: that makes no sense.

22:21 justin_smith: sorry, but these things always depend on your perspective, and mine isn’t fixed.

22:21 justin_smith: so (let [result (<! c)] ...)

22:21 julianleviston: justin_smith: again… that doesn’t help.

22:21 justin_smith: that means c has contents going into result

22:22 OK

22:22 julianleviston: justin_smith: yeah, I know when I look it up, but what’s to say that it’s pointing to the data, or the channel?

22:22 justin_smith: lol :)

22:22 justin_smith: julianleviston: the arrow points in the direction the data moves

22:22 > means left to right

22:23 < means right to left

22:23 julianleviston: justin_smith: in relation to what, positionally?

22:23 justin_smith: the syntax of clojure?

22:23 justin_smith: the thing that gets the data, and the thing that sends it

22:23 right

22:23 rerb: Newbie alert. I want to swap a couple of values in a vector. What's the idiomatic way of going from, e.g., [1 2 3 4] to [1 3 2 4]?

22:23 julianleviston: ok… so !> chan is put?

22:23 justin_smith: the binding in the let block will be to the left of the (<! call)

22:23 right

22:23 gfredericks: rerb: an assoc call

22:24 justin_smith: because the place the data is going is to the right of >!

22:24 gfredericks: (defn swap [m k1 k2] (assoc m k1 (get m k2) k2 (get m k1)))

22:24 julianleviston: so <! means takne?

22:24 amalloy: !> doesn't exist, it's >!

22:24 julianleviston: take*

22:24 justin_smith: julianleviston: right

22:24 julianleviston: gfredericks: don’t def swap!

22:24 gfredericks: okay

22:25 julianleviston: gfredericks: IMHO.

22:25 rerb: gfredericks - thanks

22:25 gfredericks: np

22:25 julianleviston: amalloy: see my problem? lol

22:25 it’s fine… just annoying

22:25 amalloy: *shrug* everyone has to figure out their own mnemonics

22:25 julianleviston: amalloy: exactly. That’s the problem.

22:25 gfredericks: we need to standardize on mnemonics

22:25 amalloy: how do you keep + and * straight?

22:25 julianleviston: amalloy: I’ve never once had to look up put or take tho...

22:26 amalloy: they're both crossy mathy things

22:26 gfredericks: (inc amalloy)

22:26 julianleviston: amalloy: it’s not quite the same, actually…

22:26 lazybot: ⇒ 220

22:26 amalloy: both make numbers bigger

22:26 julianleviston: amalloy: - and + would be a better example/

22:26 amalloy: and the’re clearly different.

22:26 TEttinger: yeah, and I always mess up my addition and tetration operators

22:26 justin_smith: amalloy: or even > and < in a math context :)

22:26 julianleviston: + has more strokes than -

22:27 gfredericks: I'm always confusing unchecked-byte with alter-var-root

22:27 julianleviston: justin_smith: > and < is a better example. the big part is linguistically on the left… we say “5 is greater than 3”

22:27 lol… ok maybe I’m being a douche… point taken.

22:27 amalloy: julianleviston: justin_smith was trying to give you an analogous mnemonic

22:28 but instead of stopping to think about it you immediately reponded "that makes no sense"

22:28 julianleviston: amalloy: I value his help, and what I was annoyed about wasn’t him.

22:28 amalloy: I have thought about it a fair bit, actually :) I’m not flaming at the moment.

22:29 justin_smith: julianleviston: in general, in data-flow or related types of frameworks, you often see some kind of "arrow" as an operator that indicates which direction your data is flowing in a given statement

22:29 > and < are popular constituent characters for "flow of data" arrows

22:30 TimMc: cfleming: Hinting the var with a classname looks icky. :-P (It makes it a little harder to read.)

22:30 julianleviston: justin_smith: yeah, I know this. I’m not debating the logic of using it. I just generally expect Rich to make saner decisions than “the majority did it that way”.

22:30 justin_smith: OK

22:30 julianleviston: at the end of the day it doesn’t matter, tho… I’ll just be quiet. It’s just syntax.

22:31 Oh… the pling is the pling of “whatchout”?

22:31 justin_smith: general question: would people hate you for remapping <! and >! to more verbose names in your code?

22:31 julianleviston: the bang? yeah

22:31 julianleviston: justin_smith: It’s cool… I want to use the condoned names. Thanks for being so supportive… :)

22:31 TimMc: _GT__BANG_ is a good choice

22:31 julianleviston: justin_smith: revelation!

22:31 TimMc: but not for both

22:31 hmmm

22:31 justin_smith: (inc TimMc)

22:31 lazybot: ⇒ 89

22:31 julianleviston: lol

22:31 TimMc: I have karma for the stupidest things.

22:32 julianleviston: (inc TimMc)

22:32 lazybot: ⇒ 90

22:32 TimMc: amalloy has karma for actually helping people

22:32 justin_smith: I've likely got an even mix

22:32 julianleviston: (dec julianleviston )

22:32 lazybot: ⇒ -1

22:33 julianleviston: clojureland is so pretty :) <3

22:33 amalloy: i like to imagine that the ! is the channel

22:33 justin_smith: oh, nice :)

22:33 amalloy: stuff being pushed into it, squeezed out of it, via the <>

22:34 julianleviston: amalloy: yeah, I used to do that, too… then I forgot which side it went on. LOL. But now I undrestand it’s the bang of danger, I can always know.

22:38 drsco: thanks for the help, the async fanning worked nicely. I should probably rewrite it to use pipeline now tho… because I have unlimited width… which is not good. I like the pipeline fn which requires a parallelism argument… mine just fans infinitely.

22:40 raspasov_: julianleviston: are you using core async pipelines?

22:40 julianleviston: raspasov_: I’m about ti.

22:40 to*

22:41 raspasov_: Cool I use them as well

22:41 Pretty good, you know about the pipeline vs pipeline-blocking?

22:41 julianleviston: raspasov_: not really… do tell :)

22:41 raspasov_: the doc says “same but blocking” lol :)

22:42 raspasov_: Depending on the type of operations you are going to do

22:42 If there's going to be blocking IO calls basically use blocking otherwise you are going to exhaust the limited core async thread pool potentially fast

22:43 justin_smith: amalloy: gfredericks: thanks for the laugh

22:43 amalloy: you're welcome

22:43 i think if obtainance were a word it would quickly degrade to obtenance, so i can't advocate that choice

22:44 julianleviston: raspasov_: the work I’m doing is caching some data…

22:45 gfredericks: catch-data!

22:45 julianleviston: lol.

22:45 raspasov_: Caching data in memory?

22:45 On the same machine?

22:45 julianleviston: raspasov_: yissir!

22:45 raspasov_: in cljs, tho.

22:46 raspasov_: Oh

22:46 I'm pretty sure there's no blocking there

22:46 julianleviston: raspasov_: yeah, no core.cache for me.

22:46 raspasov_: It's only one thread

22:46 julianleviston: raspasov_: yeah.

22:47 it’s only a tiny memoizationy kind of cache anyway.

22:47 raspasov_: Ok well I don't even know if you really get any benefit from pipelining on cljs?

22:47 julianleviston: raspasov_: just wanted to make sure I didn’t do it in sequence too much or it takes too ages.

22:47 raspasov_: I don’t either! :)

22:48 raspasov_: Yea you should benchmark with and without

22:48 julianleviston: raspasov_: I’m experimenting… but it seems to be faster with my fanning in place…

22:48 raspasov_: at this stage I’d be happy if my UI didn’t block.

22:48 raspasov_: Yea I have no experience with pipeline on cljs

22:49 That's always good to avoid ! :)

22:49 You building a web app?

22:50 Lewix: hello all

22:51 https://gist.github.com/6ewis/f86d3c0721e79197712c - please some insight

22:51 drsco: julianleviston: glad to hear it's working out

22:51 julianleviston: raspasov_: yeah, a really difficult one.

22:51 raspasov_: Well, for me… seeing as it has been my first clojure app…

22:51 raspasov_: rewriting it from Ember.

22:51 raspasov_: Difficult = learning = good ;)

22:51 julianleviston: raspasov_: indeed!

22:51 raspasov_: Even better lol!

22:52 Lewix: julianleviston: how do you like it. Im new too

22:52 justin_smith: Lewix: can you explain what you think ` is for?

22:52 julianleviston: Lewix: I’m not that new…

22:52 Lewix: justin_smith: changing it to the data structure list

22:52 justin_smith: Lewix: it being...

22:52 julianleviston: Lewix: about 7 months into clojure… more or less...

22:53 Lewix: justin_smith: I see. It's only me myself and i then..sniff

22:53 julianleviston: Lewix: lol how new are you?

22:53 justin_smith: Lewix: the problem here is that (1 2 3 4) is evaluated before your function is run

22:53 Lewix: if you want to be able to provide a list in that way, second would need to be a macro

22:54 Lewix: julianleviston: two days ago new

22:54 julianleviston: Lewix: wow… that *is* new.

22:54 Lewix: is CLJ your first lisp?

22:54 TEttinger: ` is the syntax-quote, and it's not meant for newbies. I've used clojure for at least 2 years now, off and on, and I have never used it

22:54 julianleviston: Lewix: just FYI, on your gist, you should probably mention your expected output, too...

22:54 justin_smith: Lewix: functions get their args evaluated before they are called, macros get access to the raw form of the provided arguments, and can modify them before they are evaluated

22:54 Lewix: justin_smith: so it doesnt expect it as arg

22:55 justin_smith: Lewix: can you rephrase that?

22:55 Lewix: justin_smith: sorry

22:55 julianleviston: Lewix: yeah, what are you trying to do?

22:55 raspasov: mmm

22:56 raspasov: Using Om.

22:56 Lewix: justin_smith: so if i have a function fn and arg [arg], it expect a data structure right?

22:56 and ( 1 2 3 4) is not a pure list

22:56 justin_smith: Lewix: the function doesn't get to decide how its args are evaluated

22:57 in clojure source code, (f) means invoke f (except for a few very specific contexts)

22:57 julianleviston: Lewix: maybe you mean to write ‘list not `list

22:57 TEttinger: julianleviston, wrong quote

22:57 ,(defn snd [coll] (nth coll 1))

22:57 clojurebot: #'sandbox/snd

22:57 justin_smith: ,(+ 1 (+ 2 3)) ; in this case, (+ 2 3) is not passed to the top level +, it is evaluated to 5 first

22:57 clojurebot: 6

22:57 TEttinger: ,(snd '(0 1 2 3))

22:57 clojurebot: 1

22:57 julianleviston: tho that wouldn’t work very well...

22:58 Lewix: it’d be good to know what you’re trying to do.

22:58 Lewix: julianleviston: i thought my gist was informative enough

22:58 if you read the comments

22:58 justin_smith: Lewix: in order to change the rules for evaluation, you need to use a macro

22:58 TEttinger: (doc second)

22:58 clojurebot: "([x]); Same as (first (next x))"

22:58 julianleviston: Lewix: your gist just says it doesn’t work.

22:59 justin_smith: Lewix: and making (1 2 3) mean '(1 2 3) means changing evaluation rules

22:59 TEttinger: I think you should not start with macros

22:59 start with 4clojure maybe

22:59 justin_smith: agreed

22:59 TEttinger: $google 4clojure

22:59 lazybot: [4clojure – Welcome!] https://www.4clojure.com/

22:59 julianleviston: (second (1 2 3 4)) isn’t valid syntax… because (1 2 3 4) means “run the function called 1 with the arduments 2 3 4)

23:00 Lewix: julianleviston: what i thought. thanks

23:00 justin_smith: thank you

23:00 TEttinger: also, [] is strongly preferred for list-like data instead of '()

23:00 Lewix: TEttinger: isnt [] vectors

23:00 TEttinger: yes

23:00 justin_smith: Lewix: np

23:00 TEttinger: they're extremely similar

23:00 julianleviston: Lewix: which brings me back to my question… what are you trying to do?

23:00 Lewix: julianleviston: learning

23:00 simple

23:00 TEttinger: vectors however don't quote their insides

23:00 justin_smith: Lewix: most of clojure is defined in terms of interfaces, not concrete classes, so it is quite rare that you actually need a list rather than a vector

23:01 Lewix: justin_smith: i see - thanks. i have a long way to go

23:01 justin_smith: Lewix: if you repeatedly add items to the front, yes you want an actual list, otherwise using a vector loses nothing

23:01 julianleviston: Lewix: in that case, all lists that are being used as data must be quoted, or they will be evaluated as function calls…

23:01 Lewix: thanks guys

23:01 back to playing with some code

23:02 julianleviston: Lewix: you might want to look into defn next. :)

23:02 TEttinger: map filter reduce are all important, and you'll get to them quickly I hope

23:03 justin_smith: Lewix: actually, now that I think about it "list the functions that work on a list but break when supplied a vector" would be a fun clojure trivia question

23:04 Lewix: I think the answer is very close to 0 if it isn't 0

23:04 any suggestions? I can't think of any...

23:05 TEttinger: map, filter, reduce, and a few others are kinda the building blocks of most other functions in clojure. they're where clojure starts to have a massive edge over java in succinctness of code beyond just "no java boilerplate"

23:05 justin_smith: (in clojure.core that is)

23:05 TEttinger: yup, and all of those seamlessly turn a vector into a seq if needed

23:08 TEttinger: ,(eval (list + 1 2))

23:08 clojurebot: #<ExceptionInInitializerError java.lang.ExceptionInInitializerError>

23:08 TEttinger: uh....

23:08 ,(eval '(+ 1 2))

23:08 justin_smith: TEttinger: security restrictions :P

23:08 clojurebot: 3

23:08 TEttinger: nope

23:08 justin_smith: oh, wow

23:08 TEttinger: ,(eval [+ 1 2])

23:08 clojurebot: #<ExceptionInInitializerError java.lang.ExceptionInInitializerError>

23:08 justin_smith: ,(eval [+ 1 2])

23:08 clojurebot: #<ExceptionInInitializerError java.lang.ExceptionInInitializerError>

23:08 justin_smith: wat

23:09 TEttinger: needs quoted

23:09 eval

23:09 ,(eval '[+ 1 2])

23:09 justin_smith: ,(eval (seq [+ 1 2]))

23:09 clojurebot: [#<core$_PLUS_ clojure.core$_PLUS_@2e18648a> 1 2]

23:09 #<ExceptionInInitializerError java.lang.ExceptionInInitializerError>

23:09 justin_smith: wurt

23:09 OK

23:09 ,(eval (seq '[+ 1 2]))

23:09 clojurebot: 3

23:09 justin_smith: :P

23:10 TEttinger: hiredman_ is the boss, lazybot can't eval

23:10 justin_smith: TEttinger: anyway, point taken - eval definitely behaves very differently when supplied a vector :)

23:10 TEttinger: lol

23:10 I had to rack my brain on that one

23:11 I was thinking, peek/pop?

23:11 justin_smith: oh yeah, that changes in behavior too

23:11 so we have eval, peek, pop

23:11 TEttinger: but it's documented

23:11 justin_smith: and of course conj

23:11 yeah

23:11 julianleviston: but we weren’t talking about behaviour.

23:11 list the functions that work on a list but break when supplied a vector

23:11 justin_smith: ahh, yeah, the code doesn't break

23:11 julianleviston: ;-)

23:12 justin_smith: it just does something different :)

23:12 (inc julianleviston)

23:12 lazybot: ⇒ 1

23:12 TEttinger: yay karma

23:12 justin_smith: for the technical save

23:12 julianleviston: lol

23:12 (julianleviston)

23:13 I can’t call myself :(

23:13 TEttinger: (identity julianleviston)

23:13 lazybot: julianleviston has karma 1.

23:13 TEttinger: (identity justin_smith)

23:13 lazybot: justin_smith has karma 179.

23:13 julianleviston: (map identity [justin_smith julianleviston])

23:13 (help)

23:14 lol. sorry everyone.

23:14 justin_smith: haha

23:14 TEttinger: it is just a little bot quirk. it doesn't eval it

23:14 justin_smith: ((juxt inc dec) julianleviston)

23:14 TEttinger: it's like justin_smith++ in C++ channels

23:14 justin_smith: I like (juxt inc dec) for bad puns - it leaves karma unchanged just as you would expect

23:15 julianleviston: TEttinger: today is the first day I was exposed to this ;)

23:16 TEttinger: here's a good evil C obfuscation: [18:46;31] <jdaywin> for (int c = 10; c--; c >= -10) { } // will stop after 0, of course, not -9, but at a glance not everyone will notice

23:17 julianleviston: TEttinger: oh that’s quite cool… it took me 20 seconds to work out!

23:18 TEttinger: heh, it was after he brought up that any loop that needs to stop before 0 can be done without all 3 forms: for (int c = 10; --c;) { }

23:19 or after 0 with c--

23:19 justin_smith: oh wow that is evil

23:19 (it's been a while since I touched C)

23:19 TEttinger: yes, I'm glad I don't use much of that kind of iteration these days

23:20 you can write some crazy for loop one-liners though

23:20 raspasov_: Wait why does that stop lol?

23:20 justin_smith: gfredericks: I think one could turn this into a slide in a talk about boxing of primitives in clojure http://i.imgur.com/R89vgJB.jpg

23:20 julianleviston: raspasov: the last two segments are out of order.

23:21 c - - will get to 0… which is the condition clause.

23:21 raspasov_: Oh shit lol

23:21 TEttinger: raspasov: the condition is c--, and 0 is falsy in C

23:21 julianleviston: raspasov: and 0 is logical false in c.

23:21 raspasov_: Got it :)

23:21 julianleviston: TEttinger: much succincter! ;-)

23:21 TEttinger: lol

23:21 raspasov_: I guess even in PHP that would "work" lol

23:22 Java?

23:22 julianleviston: TEttinger: (intentional abuse of the English language intended).

23:22 TEttinger: that's adorable, justin_smith

23:22 justin_smith: it could also be used as a set theory intro, if you replaced the equation

23:22 julianleviston: oh my god. it IS.

23:22 that’s so cool

23:23 justin_smith: ,#{:cat #{:cat}}

23:23 clojurebot: #{:cat #{:cat}}

23:23 gfredericks: justin_smith: but it's so obviously about cons cells

23:23 justin_smith: aha

23:23 gfredericks: just needs something about "taking the tail" maybe "holding onto the head"

23:24 so if we take the tail of (cons cat (cons cat nil)) it will freak out and swat the other cat...

23:24 gfredericks: for some reason I've never put internet photos in any of my slides

23:25 julianleviston: gfredericks: coincidentally, I’ve never slid on any photos of the internet.

23:26 gfredericks: (inc julianleviston)

23:26 lazybot: ⇒ 2

23:27 gfredericks: omg

23:27 somebody help me out

23:27 (first (range)) ;; => 0

23:27 (second (range)) ;; => 1

23:27 (with-redefs [first second] (first (range))) ;; hangs

23:28 justin_smith: $source second

23:28 lazybot: second is http://is.gd/9vPOzT

23:28 gfredericks: oh hah of course

23:28 that's the best

23:28 justin_smith: it becomes an infinite loop

23:28 gfredericks: (inc justin_smith)

23:28 lazybot: ⇒ 180

23:29 raspasov_: gfredericks: why are you redefing first to be second? :D

23:29 julianleviston: raspasov: I’m guessing it’s for the lols.

23:29 raspasov_: Lol

23:29 justin_smith: gfredericks is a madman

23:30 rhg135: #define 1 0

23:30 SegFaultAX: Is that analogous to do `True, False = False, True` in Python? :)

23:31 gfredericks: raspasov_: it's only temporary

23:31 julianleviston: coz we have the immutability on our side… ironically.

23:32 rhg135: I'm afraid people actually do this stuff

23:33 justin_smith: it's humor, kind of like using 1nth or 3nd in normal text

23:36 or that story from the cyberiad about the machine that can make anything starting with the letter n

Logging service provided by n01se.net