#clojure log - Jan 24 2014

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

0:00 rovar: it's best to not have dysfunctional bros

0:00 all drama

0:01 however, I'm afraid clojure is my bro, I don't share my bros

0:02 deadghost: dude man

0:02 if you love your bro

0:02 you gotta set your bro free

0:02 unless you want to marry your bro

0:02 then you need to ask for rich hickey's permission

0:02 akurilin: So, I love how ring will add both url and post data params into the params map, except you have to remember that you can't tell if something is a number or a string in a GET's URL param :(

0:03 Do people end up using the two separate param maps to know when they need to parse for numbers and when they can assume the JSON got parsed correctly to a number?

0:03 bbloom: akurilin: form and url encodings are EVIL

0:03 i can not tell you how many damn rails apps i've seen that just have params[...] with url, form, and json data all conflated

0:04 then they scratch their heads for a month when they have a bool a number and a string and can't tell em all apart

0:04 guest1234: can't some bright clojurean fix this intractable 'form params' problem, once and for all?

0:04 bbloom: frankly, it makes a man wish for tcl :_P

0:05 deadghost: who is our hero

0:05 akurilin: bbloom: what kind of options do I have if I need to read the :id in the compojure route and query params? Doesn't sound like I have much of a choice, right?

0:05 guest1234: Heroes can run. I'm learning to walk.

0:05 bbloom: akurilin: i dunno, i haven't used compojure

0:05 akurilin: outside of redesigning the api to use all posts

0:05 but then you're pooping on http methods

0:05 deadghost: wrong guest1234

0:05 heroes can FLY

0:06 bbloom: http deserves pooping on for most things we try to do with http... and it's too damn complicated for the things that SHOULD be done with something like http :-)

0:06 deadghost: and breathe underwater

0:06 and shoot laser beams

0:06 like superman and rms

0:06 akurilin: I get that.

0:07 guest1234: how much of the damn web is genuinely, just getting damn form data from a to b. that's the entire 'healthcare' problem

0:07 problem / industry.

0:07 but that's another talk

0:09 dead-ghosts can fly. and presumably breathe under water too?

0:09 deadghost: it's funny how many different frameworks need to be made for CRUD apps

0:09 guest1234: maybe they're all trying to resolve it the same <wrong> way.

0:09 deadghost: will we ever have one unified thing with skinnable syntax

0:10 guest1234: like with the magic of btc, just have data 'zap' from point A to B.

0:11 magically show up where it needs to, without hassle or conflated, ill-formed nonsense

0:11 deadghost: I want to hug the internet

0:11 wait no scratch that

0:11 that sounds awful

0:11 guest1234: nope. it's logged.

0:12 deadghost: so what are you guys working on

0:13 I'm herpaderpin a website to keep track of my lists

0:13 compojure + enlive

0:14 guest1234: does anyone have the source for D. Nolen's Om ToDo. the source link, https://github.com/tastejs/todomvc/tree/gh-pages/labs/architecture-examples/om has some funky lookin' git jedi

0:15 off this page: http://swannodette.github.io/todomvc/labs/architecture-examples/om/

0:15 deadghost: I have a friend that likes forking everything he uses

0:15 in case stuff disappears one day

0:16 guest1234: that's a little creepy, and incredibyl helpful.

0:16 deadghost: I wouldn't say helpful

0:16 because he doesn't have your package

0:17 guest1234: did he fork todo?

0:17 deadghost: read above^

0:17 meaning no

0:17 guest1234: I guess there's plenty else to read through

0:18 sorry. misread as fork anything that shows up on his page.

0:19 as if stalking daily for any updates to grab.

0:20 anyway, back to the hero that's going to fix FORMS and data integrity across the wire.

0:20 deadghost: godspeed

0:20 guest1234: if you could have that by tomorrow, TTThhhat be great. thanks.

0:27 akurilin: bbloom: actually I just realized why Parse.com uses POST for fetching and SO uses GET. The former has somewhat complex queries you can define, and so it requires nested datastructures, which you can't really do that well in the URI. SO on the other hand doesn't support complex queries, so it can get away with no nesting.

0:27 So if I want nesting, I'm kind of screwed and need to POST it.

0:28 I guess you can serialize a JSON object into the URI, but I don't know if that's just a recipe for sadness.

0:30 Actually it looks like people do this.

0:30 I don't know if it should make me sad or not.

0:32 dsrx: deadghost: websocket repl transport for clojurescript

0:33 deadghost: I'm only vaguely aware of websockets

0:33 you lost me at "repl transport"

0:37 dsrx: deadghost: right now, browser-connected repls for clojurescript work with the usual iframe cross-page communication hackery which works... except you can't do it unless the page you'd like to run the repl on is served over something besides http (like a spotify application or chrome extension)

0:38 er you can't do it *if* the page isn't served over http

0:39 deadghost: sounds neato

0:39 I haven't had a chance to try clojurescript

0:39 can that voodoo work with normal js

0:40 or is it some clojurescript specific magic

0:40 egghead: deadghost: cljs is to js what clojure is to java

0:40 deadghost: that sounds stupidly amazing

0:42 I'm pretty happy with just clojure in my life

0:42 but a clojure for JS rocks my socks

0:42 I'm not a huge fan of js you see

0:42 akurilin: Nvm, Parse actually does use GET, they URL-encode a json blob.

0:42 Ugh guess I'm doing that

0:43 dsrx: deadghost: to be honest i'm not totally sure if it will work, i've implemented the CLJS and still have to do the CLJ side that gets piggiebacked to nrepl and be sure it "acts like" the standard repl enough that it will even work

0:45 hrm i guess i should verify that i can actually use websockets in spotify >:D

0:46 deadghost: it's k, you can be our hero

0:46 do a write up when you're done

1:02 andyf_: Wow, someone has been having fun maintaining the channel topic message

1:06 coventry: Anything obviously funky about this clojurescript code? I'm getting an assertion failure, "alts! used not in (go ...) block". Also, I get "can't recur here", if I use (go-loop) instead of (go (loop)). https://www.refheap.com/26844

1:10 dsrx: coventry: are you requiring the core.async macros?

1:10 have to do it separately in cljs

1:11 coventry: dsrx: That was the problem. Thanks.

1:27 akurilin: Sanity check: I should be able to specify environ variables in project.clj's :profiles :uberjar :env, right?

1:33 andyf_: when one is using Leiningen and has intra-file dependencies using :require and :use, is there ever a valid reason for a file foo/bar.clj to have any namespace in it other than foo.bar?

1:34 And as an edit to that question, I would guess that Leiningen has nothing to do with the answer to the question.

1:34 tomjack: no

1:35 noonian: i don't think you can do that because of how java expects your file paths to correspond to namespace (package) names

1:35 tomjack: there are examples in clojure of violations that involve using load instead of require

1:35 clojure/core_*.clj

1:36 etc

1:36 andyf_: tomjack: Yeah, I know Clojure implementation itself sometimes uses load, but I'd consider that the exception rather than the rule, from what I have seen

1:37 But I am pretty sure that the implementation of require, use, and ns always look for a namespace foo.bar.blat in foo/bar/blat.clj, in some directory on your classpath.

1:37 tomjack: right

1:37 so, no

1:38 is there a sane way to add namespaces to edn?

1:38 andyf_: I am testing the Eastwood lint tool on some projects, and finding some placeholder files in the test directory with a namespace declared by ns that does not match the file path, and wondering whether I should make simple-to-understand error message for that.

1:40 egghead: pretty sure Cannot call method 'call' of undefined is the npe of cljs

1:41 andyf_: tomjack: You mean, enable edn to read namespace-qualified symbols?

1:42 tomjack: At least the tools.reader implementation of an edn reader can read namespace-qualified symbols, so not sure if I understand the question.

1:43 dsrx: egghead: heh

1:44 tomjack: andyf_: yes. and keywords

1:44 where "namespace" no longer means clojure.lang.Namespace

1:44 ..and data readers?

1:44 nah

1:44 well, yeah. the tag can be data-namespaced, but the var its bound to by *data-readers* will be clj-namespaced

1:44 dsrx: weird, i considered changing my nick to 'tomjak' on freenode today

1:45 andyf_: tomjack: I am not familiar enough with data readers to give any advice there

2:16 logic_prog: what browser does lighttable use for rendering?

2:17 I know lighttable users node.js

2:17 but it needs to use a browser for rendering -- what browser does it use?

2:19 xuser: logic_prog: chromium

2:20 logic_prog: https://github.com/rogerwang/node-webkit/wiki/How-node.js-is-integrated-with-chromium ?

2:20 or should I be reading something else?

2:21 xuser: yeah, node-webkit uses chromium, node-webkit is wat LT uses

2:22 s/wat/what/

2:30 fredyr: have you guys seen anybody doing cljs and node on the server side for web stuff?

2:31 logic_prog: xuser: nice, thanks!

2:31 fredyr: I have been wanting to, as a poor man's version of erlang

2:32 fredyr: erlang? in what way

2:41 jonathanj: are there any good reads about what core.async isn't?

2:42 coming from mainly a Deferred/Promise-based workflow, it's kind of surprising to me that core.async channels aren't a more common return value from libraries (i was looking at irclj)

2:43 tomjack`: does irclj use core.async now?

2:43 ah

2:45 go blocks seem reminiscent of promises

2:45 from the outside..

2:45 well, no

2:46 ok, "reminiscent". but promises "complect control flow and communication"

2:46 this quote is from the blog post about core.async, which I assume you've already read?

2:46 egghead: hmm, in om why might i get "Uncaught Error: No protocol method ITransact.-transact! defined for type cljs.core/Atom: [object Object]"

2:47 I thought atoms were perfectly fine things to be 'application state' and that you could use (transact! ...) outside of the react lifecycle to change it's state

2:47 tutysara: ddellacosta: I had tried fixing the issues with error response from provider, update the issue with comments, see if it is ok

2:49 ddellacosta: , and for multiple provider thing changed the implementation to use a :provider-uri config instead of redirecting /login to the form to choose provider, updated that issue with comments :)

2:53 egghead: or... why might I be getting errors saying that part of my app state isn't a cursor?

2:53 dsrx: egghead: i think transact! accepts a cursor into the state, not the state itself

2:53 egghead: ya, I realized I could just use 'swap!' isntead of transact! outside of the react lifecycle, but now it's saying that things like (:thing state) isn't a cursor

2:55 i'm probably just misunderstanding something

2:56 I'm just trying to do (apply dom/ul nil (om/build-all! my-lis (:get-list-from state)))

2:56 but it's saying that the value in (:get-list-from state) isn't a valid cursor

2:56 jonathanj: tomjack`: no, i don't think it does; it talks about callback functions

2:56 tomjack`: i don't see a lot of libraries that have an async nature with an outward facing core.async interface (some don't even use core.async) and i'm wondering if i've missed what core.async isn't

2:58 ddellacosta: tutysara: okay, responded--thanks!

2:58 dwwoelfel: Is it common knowledge that the :or destructuring form is eagerly evaluated?

2:59 user> (let [{:keys [a] :or {a (println "hi")}} {:a 1}]

2:59 a)

2:59 "hi"

2:59 1

3:00 logic_prog: did the word complect exist before rich hickey?

3:00 did rich hickey just come up with a word complect

3:00 ddellacosta: logic_prog: yes, he explains that in one of his early talks in fact, if I recall

3:00 logic_prog: and the rest of the wold go: okay, we accept this world you've defined

3:00 dwwoelfel: Seems like a bug in core/destructuring, where it uses a get

3:00 dsrx: com·plect [kuhm-plekt] Show IPA verb (used with object) Obsolete . to interweave; intertwine. Origin: 1515–25; < Latin complectī to embrace, enfold, equivalent to com- com- + plect ( ere ) to plait, braid + -ī passive infinitive ending; cf. complex

3:00 ddellacosta: logic_prog: http://wordnetweb.princeton.edu/perl/webwn?s=complect

3:01 ah, dsrx beat me to it

3:01 jonathanj: tomjack`: which core.async blog post are you refering to?

3:01 tomjack`: the one you almost certainly read

3:01 clojure.org I think

3:01 I think a Promise interface is pretty similar to event callbacks as far as the comment in the blog goes

3:02 but I have thought about that comment for some time and still am not sure I understand it :)

3:02 jonathanj: yes, it is

3:02 promises are just a callback abstraction

3:02 in the promise/deferred world though, whenever you do something async you return a deferred/promise

3:02 and as such, promises/deferreds permeate almost every aspect of your software

3:03 tomjack`: ..so core.async isn't that, because it doesn't, uh, complect communication and flow of control

3:03 jonathanj: tomjack`: definitely, and i understand that part

3:03 tomjack`: I think I understand the question now

3:03 jonathanj: tomjack`: but why does irclj (to pick an example) not give me channels out?

3:03 tomjack`: does it even use core.async?

3:04 jonathanj: why do i have to put callbacks in?

3:04 tomjack`: not as far as i can tell

3:04 tomjack`: why would one not want to use core.async?

3:04 tomjack`: i feel like i've missed some crucial part of what core.async most definitely is not

3:04 tomjack`: I'd guess the explanation is probably more about the author than core.async

3:05 ddellacosta: jonathanj: are you wondering why more libraries don't use core.async, is that part of your question?

3:05 jonathanj: ddellacosta: yes

3:05 tomjack`: but if we assume that the author was familiar with core.async (and that all the new functions existed when irclj was written ?), it's an interesting question

3:06 ddellacosta: jonathanj: one simple answer is that it's relatively new, and a lot of libs haven't had time to adapt it to their needs--pedestal, for one, I recall being a perfect use-case--but they only started to integrate it this fall (I believe).

3:06 tomjack`: oh interesting

3:06 jonathanj: ddellacosta: hrm, weird

3:06 tomjack`: I can't wait to see what pedestal + core.async looks like

3:06 jonathanj: ddellacosta: i've been reading about it for quite a while (before i decided to find out what it was about)

3:06 ddellacosta: actually, I think that v.2 already integrates it

3:06 jonathanj: ddellacosta: but maybe my perception of time is a little... off.

3:07 ddellacosta: jonathanj: well, it's been proposed and in alpha for a while. But it was only in the latter half of last year that it was officially out, I believe.

3:07 dsrx: egghead: got context for all that?

3:07 ddellacosta: here's what I was looking for: https://groups.google.com/forum/#!topic/pedestal-dev/e8MzUH4K-T0

3:07 jonathanj: so would a library that uses core.async (and exposes a core.async interface for users) return channels from functions that produce results asynchronously?

3:07 egghead: sure dsrx

3:08 ddellacosta: jonathanj: ^ you'll note that that post is from July, and it mentions that "Rich Hickey announced core.async a few weeks ago."

3:08 jonathanj: ddellacosta: okay, that makes sense; thanks

3:08 dsrx: afaik om/build and build-all will only accept a cursor, which is created by om/root and passed subsequently to your rendering functions

3:08 ddellacosta: jonathanj: np, hopefully that puts some of it in context.

3:09 egghead: dsrx: https://www.refheap.com/26863

3:10 tomjack`: "Messages which tell other things to change"

3:10 https://github.com/pedestal/pedestal/blob/9f7879a6a6fdd5805cb22155d5589a36ae775152/app/examples/walkthrough.clj

3:10 so I can't tell how core.async affects a typical pedestal user's application code

3:11 didn't find any core.async requires in files that looked like demo code

3:11 oh, the app-template is where to look I guess

3:11 ddellacosta: tomjack`: yeah, I'm not knowledgeable about how it works to say, I think that it's pretty heavily integrated into the codebase at this point though (last I looked at it)--so I think it's more that it provides the wiring for the underlying parts. I think that a Pedestal application developer wouldn't necessarily have much need to touch it, as Pedestal provides a pretty thorough FRP pattern itself on top of it.

3:12 tutysara: ddellacosta: thanks :) will work no the pull requests and for putting the workflow together I have to see how I can do it

3:12 ddellacosta: tomjack`: I could be wrong about that...that statement is based on the last time I played with Pedestal, a few months back.

3:12 egghead: dsrx: I don't see how it could *not* be a cursor, since it was passed to the om component

3:12 ddellacosta: tutysara: great, thanks for all of your contributions!

3:12 egghead: app is the thing passed to om/root

3:13 ddellacosta: tutysara: btw, I'm not positive that it makes sense to have one workflow for all providers vs. one per provider...I'll have to think about it. In some ways it makes sense to consider a single provider a single workflow, but I'm just not sure about it yet. So if you think one makes more sense than the other, let me know why--thanks!

3:13 tomjack`: ddellacosta: sounds reasonable

3:13 dsrx: egghead: oh hrm

3:13 tomjack`: I haven't looked at pedestal in a long time either

3:14 but it seems you're right that core.async is used quite a bit in pedestal itself

3:14 not sure why it's used in the walkthrough but not user code

3:14 maybe the walkthrough is for developers?

3:14 ddellacosta: tomjack`: yeah, I've gotta check it out again myself...along with hoplon and a few other things...always more to check out!

3:15 tomjack`: huh, dunno--I wonder if that walkthrough is v.3 vs. v.2?

3:15 * egghead shakes his fist at om

3:16 tomjack`: dunno, will wait and see. won't be using cljs for a long time :(

3:18 ddellacosta: egghead: I'm still figuring out how this all works, but I've had the same problem, and solved it by passing the whole data structure to the component and deconstructing it within the component code (rather than before I pass it in). I believe it has to do with the structures that can be validly used as a cursor (https://github.com/swannodette/om/blob/master/src/om/core.cljs#L243 for example).

3:19 er, not sure if that code example is helpful

3:20 egghead: ddellacosta: what I don't understand is that it looks exactly like what dnolen is doing in his tutorial example

3:20 ddellacosta: egghead: which one? the to-do thing?

3:20 dsrx: most of the om examples and such pull out the state to be used with build-all before calling it

3:20 egghead: yeah thats why i'm confused too

3:21 egghead: maybe because it is a nested structure or something?

3:21 I mean it's a map of keys to sometimes strings sometimes lists of other maps etc

3:21 ddellacosta: nah https://github.com/swannodette/om/wiki/Tutorial#wiki-your-first-om-component this one

3:22 ddellacosta: egghead, dsrx: as I said I'm still figuring it out, but I believe it has to do with how to-cursor works, which is what happens when you create a component: https://github.com/swannodette/om/blob/master/src/om/core.cljs#L387

3:22 dsrx: right, it doesn't seem like to-cursor is recursive (heh)

3:23 fredyr: egghead: are you updating your atom outside of the om lifecycles?

3:23 dsrx: egghead: what version are you on?

3:24 fredyr: egghead: bc then you replace the cursor with a plain atom

3:24 egghead: dsrx: latest

3:24 and ya fredyr

3:24 I think basically I have a larger structure {:foo [:a :b :c]} and that is a cursor but apparently [:a :b :c] is not?

3:24 it makes no sense

3:25 fredyr: a cursor is a cursor

3:25 :)

3:25 dsrx: i don't think om/root ever actually swaps in a cursor to replace your state atom

3:26 egghead: fredyr: do you know what is wrong with my code? https://www.refheap.com/26863

3:26 i mean it'll work if everyone has full access to all the state i just want to know why it doesn't work

3:26 ddellacosta: dsrx: it explicitly does in root: https://github.com/swannodette/om/blob/master/src/om/core.cljs#L442

3:26 egghead: like if instead of (:supervisors state) I just say state like ddellacosta suggested

3:26 but that feels lame

3:29 dsrx: ddellacosta: i see it creating a cursor from the dereferenced state of the atom provided to it (which is then passed onto the render fns), but i don't ever see it updating the atom itself unless i'm missing something

3:30 fredyr: egghead: can you show the om/root code for creation, as well as the atom updates

3:30 egghead: bc i don't think the code you posted contains the problem

3:30 dsrx: this is the first time i've really dug deep into om so i very well might have no idea what i'm talking about :D

3:30 the first time i read om source code i didn't know what an atom was

3:31 egghead: sure thing fredyr

3:31 ddellacosta: dsrx: that's because you would be doing the updating yourself, using transact! or update!

3:32 egghead: fredyr: om root creation: https://github.com/eggsby/warden/blob/master/src/cljs/warden/core.cljs#L17

3:32 fredyr: egghead: also, i don't think you should update the atom outside of om, but use transact! or update!

3:32 egghead: swap updating https://github.com/eggsby/warden/blob/master/src/cljs/warden/net.cljs#L19

3:32 fredyr: the whole point of my use case is that I want to keep the ui state in sync with an external resource

3:33 so I kind of have to do it outside of the react component

3:33 fredyr: egghead: sure, but if you look at dnolen's examples, that's usuall done by setting up a channel inside of the will-mount of a component

3:33 egghead: where you have access to the cursor

3:34 egghead: hmm

3:34 fredyr: egghead: https://github.com/swannodette/om/blob/master/examples/counters/src/core.cljs#L43

3:34 egghead: something like that

3:36 egghead: i'll try kicking off the polling stuff inside of the will mount and using set-state! or update! instead of swap!

3:36 thanks fredyr

3:36 fredyr: np, let us know it you get anywhere

3:40 quizdr: why do I need to writing something like #(vector %2 %) rather than #([%2 %])? I know #() cannot be nested, but this is not a nested #(), or there another reason?

3:40 dsrx: quizdr: #(vector %2 %) desugars into (fn [x y] (vector y x))

3:40 fredyr: quizdr: its bc of how #() gets expanded

3:40 clgv: quizdr: because of the definition of the reader macro #()

3:41 dsrx: ,(fn [x y] ([x y]))

3:41 quizdr: so my erroneous would just get expanded as (fn [x y] [y x]) ?

3:41 clojurebot: #<sandbox$eval25$fn__26 sandbox$eval25$fn__26@1d290d1>

3:41 fredyr: #(%) -> (fn [x] (x)), not (fn [x] x)

3:41 clgv: quizdr: it expands to a function call and ([]) does only make sense with integers as in ##([4 5 6] 1)

3:41 lazybot: ⇒ 5

3:41 clgv: quizdr: no. (fn [x y] ([y x]))

3:42 fredyr: ,(macroexpand-1 '#([%2 % 1]))

3:42 clojurebot: (fn* [p1__52# p2__51#] ([p2__51# p1__52# 1]))

3:43 quizdr: i see

3:43 fredyr: ,(macroexpand-1 '#([%2 %1]))

3:43 clojurebot: (fn* [p1__78# p2__77#] ([p2__77# p1__78#]))

3:43 fredyr: quizdr: there's an extra parenthesis

3:43 clgv: ,(read-string "#([%2 % 1])")

3:43 clojurebot: (fn* [p1__106# p2__105#] ([p2__105# p1__106# 1]))

3:44 clgv: fredyr: it is not an actual macro ;)

3:44 fredyr: hah

3:44 quizdr: clgv macroexpand is quite useful for seeing inside syntax in general even for non macros

3:45 clgv: quizdr: not more useful then read-string, since that is where the non-macro is happening ;)

3:45 *non-macro magic

3:46 quizdr: ,(read-string "(#(%) 5)")

3:46 clojurebot: ((fn* [p1__131#] (p1__131#)) 5)

3:47 quizdr: (inc clgv)

3:47 lazybot: ⇒ 11

3:47 quizdr: (+ clgv 10)

3:47 lvh: Hello! How can I get the number of days in between two local-dates in clj-time?

3:47 clgv: quizdr: but macroexpand-1 is *the* tool when writing macros

3:48 quizdr: (* clgv clgv)

3:48 clgv: :P

3:48 fredyr: ~clgv

3:48 clojurebot: Excuse me?

3:49 clgv: fredyr: what did you expect as return?

3:49 CookedGryphon: lvh: Something like (in-days (interval date1 date2))

3:50 fredyr: clgv: some witty comment?

3:50 lvh: CookedGryphon: But interval doesn't work on two dates; because it considers them themselves intervals, not times

3:50 clgv: :P

3:50 lvh: CookedGryphon: so I also need a way to tack "noon" onto a date

3:50 CookedGryphon: lvh: how are you making the dates?

3:51 lvh: CookedGryphon: clj-time appears to do midnight, but even with my limited understanding of calendaring I'm pretty sure that's fragile unless you only use tz-agnostic types everywhere

3:51 right now, (local-date); but they will be read from a CSV file after

3:51 CookedGryphon: and it does, behind the scenes

3:52 if you put the tz data in, it'll use it. If you don't, I'm not sure what you want it to do?

3:54 lvh: CookedGryphon: When I use date-time, I appear to be getting Intervals in UTC (ISO timestamps ending in Z)

3:55 CookedGryphon: How do I tack on "noon" to something? I mean I guess I could do something like (apply local-time ((juxt year month day) my-date))

3:56 ehh except of course with the times added :)

3:56 CookedGryphon: lvh: I might be wrong, but I don't think it will make any difference

3:57 if both the dates are in the same timezone (utc) it'll surely just do the arithmetic on the date field and all will be well, I don't see the need to shift it to noon

3:57 and if you did, what good it would do

3:58 TheDude_: Hi, I'm new to clojure and trying to rename an uploaded file with a long timestamp, but for some reason the code is not working

3:58 CookedGryphon: the interval noon to noon is the same as the interval midnight to midnight

3:58 unless there's something fundamentally broken

3:59 especially as doing it at 00:00:00 is used all through the examples for jodatime/clj-time

3:59 lvh: CookedGryphon: It's probably a nitpick. If you have half an hour, I highly recommend http://pyvideo.org/video/1765/blame-it-on-caesar-what-you-need-to-know-about-d

4:00 TheDude_: Thanks, am checking it out

4:00 What would you recommend as a unique identifier for renaming an uploaded file?

4:00 CookedGryphon: lvh: yeah, but I trust jodatime/clj-time people have thought about this a lot more than I have, so trying to trick it by moving things to midday sounds like a bad idea...

4:01 lvh: CookedGryphon: In that talk, the author makes a cogent argument about exactly why it shouldn't ever be midnight.

4:01 CookedGryphon: (The answer is that not every midnight time instance exists.)

4:01 CookedGryphon: lvh: does this come up in your dataset?

4:02 have you tried putting them into jodatime

4:02 lvh: CookedGryphon: I have no idea, it's still being constructed. It does come up in real datasets, though.

4:02 CookedGryphon: i would be very surprised if it didn't work it out, or at least make a reasonable compromise

4:02 TheDude_: Hi, does anyone know of a lib to handle file uploads and renaming the uploaded file?

4:03 lvh: CookedGryphon: (There's people that can't check into certain Alitalia flights because they were born on the wrong day; that particular problem is related to Europe/Rome and someone being under the mistaken impression that doing everything in the same timezone would make it sort of work out.)

4:03 fredyr: clojurebot: clgv |is| (read-string "((.)$(.))")

4:03 clojurebot: You don't have to tell me twice.

4:04 fredyr: ~clgv

4:04 clojurebot: clgv is (read-string "((.)$(.))")

4:04 CookedGryphon: lvh: lol, yeah, it is a bit of a minefield!

4:04 clgv: ,(read-string "((.)$(.))")

4:04 clojurebot: ((.) $ (.))

4:04 clgv: :P

4:04 lvh: CookedGryphon: Anyway, times and calendars are incredibly complicated, and unfortunately not even Zulu time is as easy as we like to think it is (still has leap seconds)

4:05 clgv: clojurebot: forget clgv |is| (read-string "((.)$(.))")

4:05 lvh: also leap days

4:05 clojurebot: I forgot that clgv is (read-string "((.)$(.))")

4:05 fredyr: point free owl

4:05 clgv: ~clgv

4:05 clojurebot: It's greek to me.

4:05 fredyr: :(

4:05 lvh: Anyway, what I want is for something to tell me the number of days between 2014 01 01 and 2014 01 15.

4:05 clgv: clojurebot: clgv |is| usually very busy

4:05 clojurebot: You don't have to tell me twice.

4:05 clgv: ;)

4:06 TheDude_: Does anyone know of a good tutorial on file uploads? Am new to clojure and this one issue is throwing me sideways. Rest ref routing, crud, sessions easy peasy.

4:08 srruby: How do I create a global atom? Thanks.

4:10 noonian: (def my-atom (atom {})) ?

4:10 srruby: noonian: Thanks!

4:10 noonian: np

4:11 TheDude_: Hi, is anyone here avaliable to answer a question?

4:12 lvh: TheDude_: Lots of people. Probably not me.

4:13 noonian: just ask and if anyone knows the answer they will likely answer it

4:14 TheDude_: Thanks. Have made good progress with clojure but stuck on 1 issue, uploading a file via ring and renaming it either with a long timestamp or maybe userid + sessionid

4:14 Been trying to crack this nut for 2 days :)

4:17 noonian: where are you having trouble?

4:17 clgv: TheDude_: isnt a file upload just a HTTP POST request?

4:18 TheDude_: I am not sure about the browser side, but if it is just an HTTP POST request on your server you can just access the input stream of the request to get the contents of the file

4:19 TheDude_: Yes, I can get a file and save it to a folder, however where I'm having trouble is renaming the file with a unique identifier such as long timestamp or session userid

4:19 clgv: when you save it to a folder you specify the filename and thus can use an arbitrary one

4:20 quizdr: ok, i'm looking at a decurrying excercise. i think i must be brain dead. how is it possible to peer inside a curried function to see what arguments it is using internally?

4:21 TheDude_: I found some code, am trying it now by generating a random number via java

4:21 quizdr: or even to query the number of arguments a fn expects

4:21 TheDude_: Does anyone have an idea how I would append or prepend that unique random number to the uploaded file name?

4:22 clgv: TheDude_: can you upload a minimal gist of your file upload code so that we have some context to help you?

4:23 appending to strings is easily done via ##(let [existing-string "my-file.txt"] (str "prefix." existing-string ".postfix"))

4:23 lazybot: ⇒ "prefix.my-file.txt.postfix"

4:24 clgv: if you want to append before the ending you can just split the string at the dot

4:24 the clojure.string namespace is what you want then

4:25 TheDude_: Thanks guys, I will try that right now. My first time to IRC, how do I post the gist here?

4:26 ddellacosta: TheDude_: just paste it into refheap.com or gist.github.com (or whatever), and paste the link to that gist/refheap into the IRC window.

4:27 quizdr: ah, of course, use the curried function as a recursive function

4:29 TheDude_: Thanks, here's the sample code point where I'm at now https://www.refheap.com/26875

4:29 d11wtq: Hi guys. Looking for some input on DSL style choices in Clojure.

4:29 https://gist.github.com/d11wtq/8594436

4:30 I'm writing (for learning only) a cron style scheduler, that distributes work across a number of nodes. It has a schedule file that is written in Clojure, as in that Gist.

4:30 Does that DSL look like you'd expect, or would you abstract further/less with macros?

4:30 TheDude_: The first definition is handle-upload, not handle-upload-original

4:31 d11wtq: And would you put parentheses around each schedule entry, so it's more logically grouped?

4:31 (Sorry, I don't really know a better place to ask for peer review... stackoverflow not good for that)

4:31 CookedGryphon: d11wtq: definitely less with macros

4:32 d11wtq: I would make it data

4:32 quizdr: d11wtq programmers.stackexchange often boasts itself as a peer review site

4:32 CookedGryphon: d11wtq: for an amusing explanation of why, see this talk by stuart halloway http://vimeo.com/77199361

4:32 quizdr: actually there is this new beta site at stackexchange, fyi: http://codereview.stackexchange.com/

4:33 d11wtq: CookedGryphon: Yeah, so the angle was I going for there was, for example, avoiding Keywords and doing somethng like (every 5 minutes (println "Boo"))

4:33 But I don't like that.

4:33 Thanks for your suggestions on the other stackexchange sites!

4:33 I always forget about them :)

4:33 alandipert: d11wtq: looks cool to me, but yeah macros (if they get big) can be hairy. the only part i might change is to feed it functions instead of exprs for :every and :at; these functions could take the schedule as an arg perhaps

4:34 CookedGryphon: yeah, you should avoid macros if at all possible

4:34 clgv: ~gist

4:34 clojurebot: http://gist.github.com/

4:34 clgv: the bot knows ^^

4:34 but refheap as good as well

4:36 alandipert: d11wtq: also if you feed it functions isntead of exprs, defschedule doesn't need to be a macro anymore

4:36 d11wtq: Yeah, the macro will (obviously) ultimately construct a function that calls other functions. I think some level of macro usage makes writing something like a schedule cleaner though, so you don't need to wrap everything with lambda.

4:36 alandipert: (not that macros are bad, i personally think they rule and i write them all the time)

4:37 d11wtq: It's funny hearing people say to avoid macros. It wasn't that long ago (before I started in Clojure) that I read Let Over Lambda. That puts things in perspective. A little defschedule macro is nothing :P

4:37 CookedGryphon: d11wtq: DSLs are very rarely a good idea. You make it so people can't compose what you're doing easily, and obscure it so that if people want to do anything out of the ordinary, they will probably need to know something about what your macros are generating

4:37 and heaven forbid there's ever a case you didn't think of ahead of time

4:37 alandipert: d11wtq: imo clojure is a tighter/better designed system than CL, and macros are scarcer because they aren't needed to stitch together the language as much

4:38 tomjack`: a project for which a CL'er I know thought essential, in clojure, ended up needing virtually no macros

4:39 er, "for which a CL'er I know thought _macros_ essential"

4:40 d11wtq: Thanks guys. I'll do this with functions alone and finish off by providing a convenience macro. I think that's the way to go (and the way I'd naturally TDD this).

4:42 CookedGryphon: d11wtq: I really recommend that talk I linked to, which would suggest storing your schedule as data where possible. That way other tools can read your data, say you wanted to make a separate app to show you upcoming events rather than scheduling them, or allow you to reconfigure them graphically

4:42 that would be easy with data

4:42 hard with functions, and extremely difficult with a dsl

4:42 * d11wtq scrolls back to find talk link

4:42 CookedGryphon: http://vimeo.com/77199361

4:42 there you go again

4:42 TheDude_: Would it be possible to get some feedback on this code https://www.refheap.com/26879

4:43 d11wtq: http://vimeo.com/77199361 thanks

4:43 TheDude_: Am trying to rename an uploaded file

4:44 steckerhalter: how do I convert long to a byte array? I have found this where the question outlines how to do it with Java, but I'm not sure how to translate that in to Clojure: http://stackoverflow.com/questions/19791255/how-to-convert-byte-array-to-long-without-using-java-nio

4:45 CookedGryphon: steckerhalter: I would recommend a ByteBuffer instead of an outputstream if you know the length of your data vaguely

4:45 and don't need to stream

4:46 steckerhalter: CookedGryphon: ok, any examples how to use it for this purpose?

4:46 CookedGryphon: then you just do (doto (java.nio.ByteBuffer/allocate 8) (.putLong 123) (.putLong 321)) etc

4:47 and then .rewind to go back to the start of the bytebuffer if you want to overwrite, or read out one thing at a time

4:48 and look at the docs for how to get a byte array out of that

4:48 steckerhalter: thanks

4:48 CookedGryphon: .array i think

4:48 noncom: anyone using twitter-api, can show an example of a restful statuses-update call? what will be the :params?

4:49 CookedGryphon: steckerhalter: np, hope that's enough info to get you started

4:50 ddellacosta: TheDude_: you need to take a look at ring's multipart-params namespace: https://github.com/ring-clojure/ring/wiki/File-Uploads

4:51 TheDude_: http://ring-clojure.github.io/ring/ring.middleware.multipart-params.html

4:53 TheDude_: Thanks ddellacosta, am checking that right now

4:53 ddellacosta: TheDude_: try reading through some of the examples that exist first, because your code doesn't really seem to reflect how ring/compojure works. Google "file upload with ring/compojure" and you should find some good examples.

4:56 TheDude_: or at least, I'm not sure what's happen with all the functions that you are including from the pgapp.util namespace; could be they are doing the heavy lifting.

4:58 TheDude_: I got it working with file name as is and to a dynamically created directory for user

4:58 But I prefer to save em all in one folder with a unique identifier in the file name and store that in the db

4:59 I'll try a search with ring compojure, since I'm new to clojure not so familiar with all the plumbing in the various libraries

4:59 SQL Crud, views, sessions, all easy peasy, file upload and manpilating how file is name, where saved, etc, bit challenging :)

5:00 ddellacosta: TheDude_: ah, I see. I think the problem with your example is just that it's hard to see what stuff like upload-file and gallery-path are doing.

5:00 TheDude_: The functions in the utils namespace just supply the folder name where to save the file

5:00 gallery-path is just a reference to the actual folder to store

5:00 ddellacosta: TheDude_: it would probably be useful to put that in the refheap next time so people can see what they are returning and how they work.

5:01 TheDude_: upload file I myself am confused :) I don't see it in my utls file

5:02 ddellacosta: TheDude_: if you are just getting familiar w/Ring and Compojure definitely scan through the examples of argument de-structuring and read up on how the request map works--and you may get some of a sense of how it is by simply dumping out the request itself in your code, to start. That can be useful if it's not clear what is getting passed where.

5:02 TheDude_: Oh I got it, upload-file is a reference in the [noir.io :refer [upload-file resource-path]]

5:03 ddellacosta: TheDude_: ah, sorry--I see that referenced in the require form now, I missed it.

5:03 TheDude_: How long do you think it typically takes a newbie adpoting clojure from standard 00 langs like ruby or coldfusion?

5:03 lisp is def a diff paradigm, enjoying the journey so far

5:03 AeroNotix: so my co-worker is trying to set up cider, when opening a cider-jack-in repl and then loading code into it, it complains it cannot find classes. Printing out the class path suggests that it's not picking up the project at all.

5:04 ddellacosta: TheDude_: in that case, take a look at the noir docs: http://yogthos.github.io/lib-noir/noir.io.html#var-upload-file. I would suggest maybe leaving noir off at first and doing it via ring...just so you get how ring works at first.

5:05 TheDude_: Is lib-noir created by yogothos?

5:05 ddellacosta: TheDude_: re: how long it takes? If you've done ruby or python and are familiar with wsgi or rack, then you should get a sense of how ring works pretty quickly.

5:06 TheDude_: Yes it seems to work same way as middleware

5:06 ddellacosta: TheDude_: lib-noir is maintained by yogthos, but grew out of code from the-framework-formerly-known-as-noir by Chris Granger

5:06 TheDude_: er, not just yogthos I guess

5:06 TheDude_: yogothos is the man, he's been v helpful

5:08 I think the key here is reading up the docs and getting more familiar with the plumbing

5:08 I'm just a week into it so far, looks v promising

5:08 ddellacosta: TheDude_: yep, definitely agree--I think you'll feel a lot more comfortable with it once you've gotten through Ring/Compojure docs, especially (if you want to do server-side web stuff).

5:09 TheDude_: I'm mostly doing server side stuff, about 99%

5:09 ddellacosta: TheDude_: and I definitely recommend looking at the codebase for those two projects as well, they are clean and well written, and the ring architecture itself is simple and logical.

5:10 TheDude_: Are you doing web dev stuff or you have a diff use case?

5:11 ddellacosta: TheDude_: I do web dev with Clojure, yep.

5:12 TheDude_: but there are a lot of folks using Clojure in a lot of different domains.

5:12 TheDude_: Using any framework or you write your own

5:13 ddellacosta: TheDude_: mostly just Compojure, with various libs here and there. I haven't yet found a framework that is as useful as simply composing libraries together.

5:13 TheDude_: Yeah, I like the simplicity of just putting together some libraries

5:13 fredyr: speaking of server side web in clojure, whats the way to setup user account logins and such, with email verification?

5:14 TheDude_: Thanks for your help, calling it a night for now. Goodnight and again thanks.

5:15 ddellacosta: TheDude_: cheers, good luck! :-)

5:15 fredyr: I've built two systems which do that, and they both have required a fair bit of code slinging, unfortunately. :-(

5:15 fredyr: ddellacosta: too bad

5:15 ddellacosta: fredyr: but, the one I built with Friend was a bit simpler. For that project, I used mailchimp + friend.

5:16 fredyr: I mean, it was a lot of code compared to how I used to set up Rails w/Devise back in my RoR days. But, then again, I had to use Rails. ;-)

5:16 fredyr: haha right

5:16 yeah, i guess i'm comparing to how i would've done it with django

5:17 ddellacosta: fredyr: the other way I did it was an even more customized version which uses safeguard (my company's lib: https://github.com/diligenceengine/safeguard)

5:17 AeroNotix: so my co-worker is trying to set up cider, when opening a cider-jack-in repl and then loading code into it, it complains it cannot find classes. Printing out the class path suggests that it's not picking up the project at all.

5:17 ddellacosta: fredyr: yeah, I think that friend is the closest thing we've got to anything rails or django could give us (not knowing what is possible with django, but I assume it is easier)

5:18 AeroNotix: is he starting it up in the project directory? I've only started up cider by starting a repl in a separate project dir, then connecting to that, which always works nicely for me.

5:19 god, that safeguard read me is f*cking terrible

5:19 forgive me for saying so boss. ;-)

5:21 fredyr: I've actually been meaning to write some sort of "get-going-quickly" thing for friend which wraps up some of the functionality that you get with something like devise in Rails.

5:22 fredyr: I should add, there is also going the Java route--there are wrappers for stuff like apache shiro I think

5:22 fredyr: https://github.com/inventiLT/Pocheshiro

5:22 fredyr: it's just...very Java-y

5:46 muhoo: i love that there's an oath-clj and a clj-oauth library, which are different but seem to do the same thing

5:47 steerio: at least there's a different word in both (if that's really oath there)

5:47 in both = in each

5:47 i can't english

5:52 katox: is there a simple way in sider to run (macroexpand-1 'form) instead of default (macroexpand-1 form)?

5:57 what do I do now is to expand all macros from the top level form to get to the proper level - or - just copying the stuff into the repl, adding pprint macroexpand-1 and quote, that seems silly

6:05 tim__: what is the difference between '(use 'a.b)' and '(:use a.b)'?

6:10 katox: tim__: the second is the form used in ns macro, the first is the actual call

6:11 tim__: Thanks

6:11 katox: tim__: np, that said, use is somewhat obsolete now that require has :refer option

6:13 tim__: thats a lot of help, i'm very new to clojure.

6:18 Morgawr: ,(int 1.999999999)

6:18 clojurebot: 1

6:18 Morgawr: ,(int 1.999999999999999999999999)

6:18 clojurebot: 2

6:18 Morgawr: welp

6:19 https://gist.github.com/tshauck/8591809 <-

6:22 hyPiRion: Morgawr: well

6:22 ,1.999999999999999999999999

6:22 clojurebot: 2.0

6:23 Morgawr: ,1.999999

6:23 clojurebot: 1.999999

6:23 Morgawr: I see

6:23 still fun

6:23 arcatan: even clojure knows that 1.999... = 2

6:25 locks: nothing is true, everything is permitted

6:25 Morgawr: but then how come (apply + (range)) doesn't return -1/12? :D

6:27 hyPiRion: because range isn't infinite

6:29 ,(doall (range (- Long/MAX_VALUE 1000) Double/POSITIVE_INFINITY))

6:29 clojurebot: #<ArithmeticException java.lang.ArithmeticException: integer overflow>

6:32 AeroNotix: org.apache.commons.io.IOUtils where does this package/class live? Do I need to download it?

6:33 alew: I find it very curious that (take 2.5 x) returns 3 elements instead o f2

6:34 ,(take 2.5 (range 5))

6:34 clojurebot: (0 1 2)

6:34 hyPiRion: AeroNotix: add [commons-io/commons-io "2.4"] to your dep vectory

6:35 AeroNotix: hyPiRion: cheers

6:37 TEttinger: ),(take 2.4 (range 5))

6:37 ,(take 2.4 (range 5))

6:37 clojurebot: (0 1 2)

6:37 TEttinger: seems to round up

6:37 alew: If you look at the implementation

6:38 it's actually just dec'ing each iteration

6:38 and checking if positive

6:38 so you get down to 0.4

6:38 Still seems like odd behaviour

6:39 TEttinger: rand-int can take a fraction or float param too. it's even weirder

6:40 ,(frequencies (repeatedly 1000 #(rand-int 2.5)))

6:40 clojurebot: {2 201, 1 368, 0 431}

6:41 TEttinger: note how 2 shows up about half as frequently as the others

6:41 alew: what the fuck..

6:47 TEttinger: alew, that probably has to do with just dividing (rand) by the arg to rand-int

6:48 or multiplying?

6:49 CookedGryphon: or it could be that int is truncating, doing a floor

6:49 so 0 and 1 buckets are both twice as big as the 2.5 bucket

6:49 hyPiRion: CookedGryphon: yeah, rand-int is essentially just (int (* n (Math/random)))

7:18 lvh: Hi

7:19 is there a way to tell group-by what to put items into

7:19 I want them also *sorted* by (f elem), not just grouped by.

7:22 CookedGryphon: (into (sorted-map) (group-by f coll))?

7:23 or sorted-map-by

7:23 as your keys are already the values you want to sort by

7:25 hyPiRion: I think lvh means that the lists inside the maps are sorted

7:25 lvh: nope, CookedGryphon had it right

7:25 the keys of the map have to be sorted

7:26 is there some kind of convention for a memoized function and its unmemoized variant?

7:26 Sorry, I mean for the *names* of them.

7:26 CookedGryphon: lvh, i usually call the unmemoized variant blah*

7:26 lvh: And then (def blah (memoize blah*))?

7:29 CookedGryphon: lvh: yeah

7:30 I think I've seen it in a few other libraries too

7:30 only issue with that

7:30 is that the def there isn't going to pick up the docstring from blah*

7:30 and the arglist

7:31 not sure what to do about that other than manually attach the metadata

7:35 hyPiRion: lvh: we do alter-var-root'ing in Leiningen. Consider doing that if you never use the unmemoized version

7:46 john2x: can I 'unload' a namespace I use/refer/required in the repl?

7:57 noidi: ,(doc remove-ns)

7:57 clojurebot: "([sym]); Removes the namespace named by the symbol. Use with caution. Cannot be used to remove the clojure namespace."

8:02 locks: ,(doc doc)

8:02 clojurebot: "([name]); Prints documentation for a var or special form given its name"

8:12 lvh: Hi

8:12 is there a more efficient "intersection?"? Maybe just intersection is already doing what I want

8:12 Basically I have a 2-set and an N-set; if either element is in the N-set, give up

8:13 I think the way to spell that is (if (seq (intersection s1 s2)))

8:13 llasram: lvh: You can do way better than that

8:13 If you know s1 is smaller than s2,

8:13 (if (some s2 s1) ...)

8:13 lvh: llasram: Nope. The N-set starts out empty.

8:14 llasram: Maybe I should explain what I'm trying to do

8:14 I'm trying to solve a hotel-pairing optimization problem

8:14 llasram: Maybe :-)

8:14 lvh: I've figured out how to produce candidate pairs in terms of decreasing preference

8:14 alandipert: check each element w/ contains?

8:14 lvh: if either of the people in the candidate pair is aready assigned, obviously I can't assign them again

8:14 so, I'm keeping a set of already assigned people.

8:15 Does that make sense?

8:15 (That's the big N-set. It obviously starts empty.)

8:15 maybe that still means some, though.

8:16 llasram: Totally. And my suggestion still holds -- I just made it overly-strong. And you can always generalize. The important part is that you only care that there is an intersection vs the content of the intersection

8:16 lvh: because it doesn't actually matter if the set is bigger

8:16 right?

8:16 right

8:16 llasram: Thanks!

8:16 llasram: np!

8:16 hyPiRion: lvh: as far as I understand, you can just do (not-any? #(contains? s2 %) s1)

8:17 well heck, llasram's solution is way better. I'll go away now.

8:17 llasram: hah

8:17 Actually *I'll* go away now!

8:17 That'll show ya

8:17 lvh: actually, rethinking my algorithm, it may be necessary to actually have the intersection anyway

8:18 hyPiRion: I guess I am terrified of nil and write code to defend against them at any momemt.

8:18 lvh: hmmm, maybe not, because I have every combination

8:18 I need a whiteboard

8:18 alandipert: some is o(n) worst case though, vs. just using 2 contains? checks

8:19 hyPiRion: alandipert: not if you know that s1 contains 2 elements only

8:19 lvh: yeah, I can guarantee they're only pairs.

8:19 because they come from (combinations all-users 2)

8:20 alandipert: hyPiRion: oh, right! i had my s1 and s2 backwards

8:24 lvh: are nested loop/recurs okay?

8:25 hyPiRion: lvh: I would recommend to split the function up into more functions if that happens

8:25 But it's doable, sure, just a bit convoluted :)

8:25 lvh: I'm having a hard time making function names sane

8:25 (defn pair-least-unmatched-days-within-subgroup)

8:26 is there a refactoring thing for emacs that understands clj projects

8:26 that can rename function names?

8:26 CookedGryphon: lvh clj-refactor

8:26 is probably the closest thing

8:26 lvh: oooh!

8:26 CookedGryphon: you can do nice things like rename file which will update all the references to your namespace too

8:27 and unwind/wind threaded expressions

8:27 lvh: awesome

8:27 CookedGryphon: but mainly I use it for shifting namespaces around

8:27 lvh: there's a few things I'm writing that I'm pretty sure can be rewritten with reducers

8:27 CookedGryphon: if you open a new .clj file, it'll fill out your ns declaration for you too which is nice

8:31 alew: CookedGryphon: thanks for the tip

8:32 lvh: yep

8:32 mind blown.

8:32 CookedGryphon: if you think that's good, wait till I get round to updating latest-clojure-libraries

8:33 my first foray into elisp, which unfortunately doesn't work at the moment thanks to the nrepl->cider thing

8:33 for looking up and inserting teh latest version of a thing into your project.clj, then uses pomegranate to load it into your running repl with no restart if you want

8:42 katox: another dozen or so hours lost on a dynamic binding

8:43 reminds me dependency injection - it feels good at first ;)

8:55 lvh: hey

8:56 ... wait, I just figured it out.

8:56 Sorry :D

9:16 steckerhalter: it seems that using a ByteBuffer and then doing .putInt in a map does not operate on the original ByteBuffer? the ByteBuffer stays empty at least

9:18 andyf_: map is lazy. Try doseq around things that you want for side effects

9:19 steckerhalter: andyf_: ok, will do

9:20 andyf_: katox: binding and dorun/doall - 2 things that often go well together

9:22 katox: andyf_: true enough, this time nil crept in sometimes though

9:45 mikerod: empty? is a fn; not-empty? is not a fn; not-empty is a fn ;= fn naming fail

9:45 afhammad: what am I missing: I am requiring [monger.core :as mg] within a namespace, however get this: java.io.FileNotFoundException: Could not locate monger/core__init.class or monger/core.clj on classpath

9:45 I have this in my project dependencies: [com.novemberain/monger "1.7.0"]

9:46 AeroNotix: any httpcs to recommend?

9:46 http-kit/aleph?

9:47 mikerod: maybe `not-empty` was named like that, to make people hate it and just use `seq` instead

9:50 gfredericks: mikerod: not-empty? would suggest it's a predicate which returns a boolean, which would not be true

9:50 ,(not-empty {:a 2})

9:50 clojurebot: {:a 2}

9:51 gfredericks: similarly we have some instead of any?

9:51 ,(some #(when (pos? %) (inc %)) [-2 -1 0 1 2])

9:51 clojurebot: 2

9:52 mikerod: gfredericks: that's fair enough, but it *should* be a predicate that is analogous to `empty?`

9:52 gfredericks: presumably rhickey disagrees

9:52 mikerod: some, is useful to not be a predicate; it can serve as a "get first" fn

9:52 CookedGryphon: ugh, midje

9:52 sorry, that was meant to be qualified with a complaint :P

9:53 quizdr: some can return more than just true or false, therefore it is not a predicate

9:53 CookedGryphon: midje isn't reloading when i change my source, just when i change the test file

9:53 any ideas?

9:53 mikerod: I'm just coming from the standpoint of helping some people write some clj code. They don't quickly accept `seq` as a "not empty" check. They understand "empty?" of course, but then they always get confused when it comes to "not-empty" - no ? mark.

9:53 I meant, new people to clj.

9:53 anyways, just a little nit pick really.

9:54 gfredericks: clojure is a constant pile of confusion and surprises to new people

9:54 mikerod: :P

9:54 fair enough

9:54 afhammad: gfrederick: yes it is

9:55 gfredericks: docstrings are often helpful

9:55 it's nice that they're so integrated

9:55 rather than having to google to find them

9:56 I think I had the idea of curating a list of clojure gotchas before

9:58 ,(doc not-empty)

9:58 clojurebot: "([coll]); If coll is empty, returns nil, else coll"

9:58 jcromartie: somebody help me decipher net.cgrand.reload

9:58 gfredericks: does anybody have a solution for cleaning up resources associated with a ring response after the inputstream has closed?

9:58 jcromartie: where do the ::deps metadata come from? do I have to add that to the ns myself?

9:59 the documentation in the README here is clearly insufficient https://github.com/cgrand/enlive

9:59 it just says call (net.cgrand.reload/auto-reload *ns*)

9:59 llasram: gfredericks: I just got a PR merged into ring which allow using the CollReduce protocol instead of a seq of strings

9:59 You can reify that protocol with your own setup/cleanup surrounding the actual reduce behavior

9:59 gfredericks: llasram: I'm using cheshire; is there a way to combine those?

10:00 I guess if I serialized the top-level array myself...

10:00 llasram: gfredericks: I may have misunderstood. Do you have public code, or more details?

10:01 Ooops -- gotta scrum. bbiaf

10:01 gfredericks: k

10:06 llasram: it's not public; I'm currently using piped-input-stream to start another thread that uses cheshire.core/generate-stream

10:07 I'm having trouble figuring out how CollReduce is useful at all, much less for my particular use case

10:07 I must be missing something

10:08 clgv: where is piped-input-stream from?

10:08 gfredericks: ring.util.io

10:10 I had the impression that pjstadig's scoped library could help with this but then I read through it this morning and I don't think that's true

10:11 mmitchel_: stuartsierra: I'm looking at using your component lib for a new web app. Would you consider it to be stable enough for a prod app? Also, do you know who might be using it?

10:11 clgv: anyone used graphstream from clojure, yet? is it easy to use for visualization?

10:11 mmitchel_: stuartsierra: oh well, i see the README - alpha, beta etc :)

10:11 stuartsierra: mmitchel_: It's quite simple, so yes I consider it stable. I am currently using it on a large client project.

10:11 mmitchel_: nice

10:12 stuartsierra: Where "stable" means "doesn't have any obvious bugs."

10:12 mmitchel_: It does look quite simple +1

10:12 stuartsierra: But I still reserve the ability to change the public API between 0.x versions.

10:17 shep-home: Is there a way of telling if putting onto a core.async channel will block?

10:17 tbaldridge: shep-home: no, but you can make sure it never blocks

10:18 shep-home: and you can use alt! with :default (or timeout) to do something else if it tries to block

10:18 shep-home: tbaldridge: thanks. I was thinking of something like a webservice that gets a request and puts it into a channel

10:19 it could be preferable to return an HTTP busy code right away, and not do the work

10:19 I think this is called backpressure, but I'm still learning my way around :-)

10:20 tbaldridge: shep-home: yeah, use a channel with a larg-ish buffer and then do (alts!! [[c val]] :default :busy)

10:20 that'll instantly return :busy if the channel is full

10:20 shep-home: Yeah, that makes sense. I was looking at put, but couldnt see how that would help

10:20 thanks!

10:20 AeroNotix: any httpcs to recommend?

10:22 llasram: gfredericks: Yeah, you'd need to change your code so that it somehow produces a "collection" of strings instead of writing to an input stream

10:30 andyf_: stuartsierra: I didn't look thoroughly, but does tools.namespace or any other lib you know implement a check that source file names and namespace symbols in ns forms are consistent with each other?

10:31 stuartsierra: And if not, would such a thing be a useful addition to tools.namespace?

10:31 stuartsierra: andyf_: I'm not sure I understand the question. If ns forms don't match their files, Clojure won't even load them.

10:31 andyf_: stuartsierra: But someone can create them and get no errors

10:32 CookedGryphon: andyf_: in emacs clojure mode you can do (clojure-update-ns) which will replace it with the appropriate namespace

10:32 andyf_: stuartsierra: I am testing Eastwood on many projects, and sometimes I run across oddball things like this. They can be hard to debug the exceptions that get thrown

10:32 CookedGryphon: and clj-refactor automatically fills in the right one when you open a file

10:32 gfredericks: llasram: what's the advantage over a lazy seq?

10:33 stuartsierra: andyf_: Sounds like something for a linter like Eastwood to check, then.

10:33 andyf_: I am planning on adding an easy-to-understand message: Hey, this file contains a namespace foo.bar, but it should be bar.baz based on its name.

10:33 stuartsierra: Oh, it will. I'm just asking if tools.namespace is a reasonable home for a function that finds such things or not.

10:34 stuartsierra: andyf_: Not sure. I'll think about it.

10:34 hipsterslapfight: express : node :: xxx : clojure ... is there an xxx?

10:35 andyf_: I have read an article about someone in academia who took a C lint tool commercial, and the crazy things they found out in the wild in real C code. I am starting to get a tiny idea of 1% of the stuff that they must have come across :-)

10:35 tim__: are there any tools like checkstyle / findbugs / pmd etc available for clojure?

10:36 andyf_: tim__: I do not know exactly what those tools do, but you may want to look at kibit and Eastwood, both on github

10:38 llasram: gfredericks: You can have set-up / tear-down code :-)

10:46 tim__: @andy_f thanks, they are exactly what i'm after.

10:47 gfredericks: llasram: where does the teardown code go? the edge-case is when the socket is closed so the whole thing doesn't get sent

10:53 ambrosebs: dnolen: do I have to maintain my own cljs.env atom when analyzing CLJS forms? And should I always initialise it by loading core.cljs with my env as cljs.env/*compiler* ?

10:53 llasram: gfredericks: The client socket? So like, your service is streaming a chunked response, and the client just closes the socket as some point?

10:53 jita: Is IntelliJ good IDE for clojure programming ?

10:55 saolsen: jita: with the cursive plugin it's pretty great

10:55 http://cursiveclojure.com/

10:55 jita: saolsen: there is la clojure too how does it compare to that ?

10:55 saolsen: I use it a lot, especially if I have to do anything with java interop.

10:55 blrm: saolsen: i haven't seen that, looks nice. i just knew of la clojure

10:56 saolsen: This one is newer and I think they built it because of some frustrations they had with la clojure

10:56 I haven't used la clojure though.

10:56 locks: for some reason I was under the impression that cursive and la clojure were by the same people

10:57 or at least people in common?

10:57 saolsen: they might be

10:57 I don't really know who's behind it

10:57 locks: they changed the name to break backwards compat and etc

10:57 jita: saolsen: cool, and when you are not working for java interop what do you use? emacs ;)

10:57 locks: this is mostly guessing tho

10:57 saolsen: but they're really good, super responsive on twitter and github issues and seem to ship a new version every week or so

10:58 I bounce back and forth between emacs and cursive.

11:00 llasram: saolsen: Have you tried eclim?

11:01 saolsen: llasram: nope, never heard of it

11:01 llasram: saolsen: https://github.com/senny/emacs-eclim

11:01 Essentially runs Eclipse as a background service, then lets Emacs talk to it

11:04 saolsen: interesting

11:04 is there clojure integration?

11:04 jita: saolsen: do you use cursive plugin or IDE?

11:04 saolsen: the ide isn't out yet

11:04 just the plugin

11:04 and it's still in alpha so you have to add their repository

11:05 jita: saolsen: does it work with intelliJ 13ce?

11:05 saolsen: the site covers how to get set up

11:05 jita: yep

11:05 jita: saolsen: thanks

11:06 llasram: saolsen: Oh, no. I misunderstood. It's definitely for writing Java from Emacs, which is for some reason is what I'd taken you to be talking about

11:10 lvh: my tests appear to have hit an infinite loop.

11:10 how do I stop them? I'm using run-tests in the repl

11:10 arrdem: mash C-g?

11:11 lvh: Doesn't appear to be working.

11:11 clgv: Ctrl+C in lein repl

11:11 kzar: C-c?

11:11 oo too slow

11:11 lvh: nREPL connection closed: connection broken by remote peer

11:11 I think that means java gave up

11:11 maybe?

11:12 clgv: lvh: killall -9 java ;)

11:13 cark: or more mashing on the box itself

11:14 lvh: hehe :)

11:14 if anyone has a second to give me some style advice, I think https://github.com/lvh/pairing/blob/master/src/pairing/core.clj#L81 can use plenty

11:14 pair-days is what I'm calling and what's doing what appears to be an infinite loop

11:14 maybe it's actually just really really slow

11:15 Anderkent: well, I don't see pair-days ever going out of the loop

11:15 it always recurs

11:16 lvh: ah, yes, that would be bad.

11:16 Anderkent: pair-subgroup-days seems ok, one thing I'd do is put pairs and paired on separate lines in 0 and 1 cases, so that it looks exactly like the 2 case

11:16 but it's a very minor issue

11:17 in pair-days you just want to check if you have any subgroups left, I guess?

11:17 lvh: yeah; I added the (if (seq

11:18 jstew: If I have a collection [[1 2] [3 4]], what's a nice way to split them by column so that they're [[1 3][2 4]]? My solution is ugly, and I know there's an elegant way.

11:18 lvh: it appears that I always get [[] []] back from it though

11:19 Anderkent: this is another super minor thing, but I prefer to have the terminating case first, since it's so short. saves scanning down to see what the other case is

11:19 compare https://www.refheap.com/26994

11:19 AeroNotix: https://gist.github.com/AeroNotix/eecf8d63aa307381bfff anything more idiomatic than this?

11:19 Anderkent: lvh: do you know if pair-subgroup-days works? :P

11:20 lvh: Anderkent: Nope, writing tests

11:20 clgv: AeroNotix: there was a lib for byte array and such mentioned on the ML some time ago

11:20 AeroNotix: clgv: I was looking for something like this, decided to just start it myself.

11:21 Anderkent: AeroNotix: what's it trying to do, split a byte array into two around the first occurence of c?

11:22 AeroNotix: Anderkent: like string/split for byte-arrays

11:22 Clome: is there a way to work with java primitives? A java fun returns an int, but in clojure I get an Integer object. Is there a way to tell clojure that I want a normal int.

11:23 Anderkent: why use BAIS instead of areduce?

11:23 clgv: Anderkent: +1

11:24 Anderkent: Clome: you can tag the arg sometimes. But in general I'd accept boxed stuff most of the time

11:24 if you really need performance, look into https://github.com/ztellman/primitive-math ?

11:26 Clome: Anderkent: A method in java returns an int, and then I use this int in a (case ) form which returns always the default, since integer is an object and it test the memory reference?

11:27 Anderkent: Clome: that doesn't sound right, it should automatically unbox it if your case is int-based

11:28 ,(case (Integer. 0) 0 :yes :no)

11:28 clojurebot: :yes

11:28 Anderkent: Clome: ^

11:29 Clome: Anderkent: it is not int based, since in the casess I use static java int fileds, but they too get boxed in Integers. Any easy solution?

11:30 Anderkent: Clome: I don't follow. If your cases are ints (literal numbers) then it should be int based. can you post your code?

11:31 clgv: Clome: no. the problem is that case needs compile time constants

11:32 Anderkent: ('case' has three modes of operations - either ints, where it uses numerical dispatch, or keywords (where it's objects identity), or other stuff (object hashes)

11:32 Clome: Keyboard/KEY_W here is an case example, which is a normal int but in clojure gets boxed in Integer

11:32 clgv: Clome: the symbol which resolves to the static integer is no compile time integer constant

11:32 Anderkent: Ah. That won't work, you need constants. Use condp

11:33 clgv: Clome: there was a question on the ML recently. where someone solved it via writing a macro on top of case such that static constants are resolved

11:34 Anderkent: clgv: does marking a def as ^:const make it work with case?

11:34 clgv: Anderkent: never tried

11:34 Clome: Can`t I for example say something like this (def ^:const ^int key-w Keyboard/KEY_W), so that clojure dos not box this int?

11:34 lvh: so, there's a thing I don't get

11:34 map is lazy right? but when I put it in a repl expr, I see the full result

11:34 is it lazy, but being instantiated for the repl?

11:35 Anderkent: lvh: the map gets realized when the repl prints it

11:35 if you do (def result (map ...)) it won't be realized

11:35 Clome: alas, I don't think you can

11:36 clgv: Clome: well, easy enough to try and see

11:36 Anderkent: I think case won't even try to resolve symbols

11:36 i.e. if you say (case x foo :yes) it's checking if x == 'foo

11:36 clgv: macroexpand-1 on the case-form might be handy

11:36 Anderkent: ,(cse 'foo foo :yes :def)

11:36 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: cse in this context, compiling:(NO_SOURCE_PATH:0:0)>

11:36 Anderkent: ,(case 'foo foo :yes :def)

11:36 clojurebot: :yes

11:36 clgv: ah right^^

11:37 Anderkent: so you can't use symbols to refer to their values

11:37 Clome: ok, thanks

11:37 clgv: you cant use lists either if I remember correctly. but vectors work since they are in the same equality partition

11:38 ,(case '(1 2) (1 2) :yes :no)

11:38 clojurebot: :no

11:38 clgv: ,(case 1 (1 2) :yes :no)

11:38 clojurebot: :yes

11:38 Anderkent: Clome: in general. Don't use case unless you really need the performance of javas switch

11:38 clgv: ,(case 2 (1 2) :yes :no)

11:38 clojurebot: :yes

11:38 clgv: ^^

11:39 Anderkent: I suppose writing a macro that evaluates case args then produces (case) with literals shouldnt be that hard?

11:39 clgv: Anderkent: humm I think that statement is not true. case is compiled to jvm code using hashing

11:39 Anderkent: clgv: not for int or identity matching afaik

11:39 Clome: why did (case 2 (1 2) :yes :no) returned :no?

11:39 clgv: I'd think switch is a primitive jvm byte code op, is it?

11:39 borkdude: what is the fastest/easiest (not necessarily best) way of building a crud web app with datomic as storage nowadays?

11:39 clgv: Clome: it did not ^^

11:39 Anderkent: I'm like 80% sure that (case x 1 :yes :no) compiles to switch

11:39 clgv: ,(case 2 (1 2) :yes :no)

11:40 clojurebot: :yes

11:40 Clome: sorry, I meant :yes

11:40 why is that

11:40 clgv: Anderkent: switch with hashing I think

11:41 Clome: should not (1 2) return an error, since 1 is not a function

11:41 what am I missing here

11:42 Anderkent: Clome: case is a macro, it gives special syntax. In there, a list means 'one of these elements'

11:42 clgv: Clome: no. in `case` that's a notation fur alternative values that are matched

11:43 Clome: oh right, sorry

11:44 borkdude: I have used case exactly once

11:44 until now

11:45 (* amount (case time :month 1 :quarted 3 :year 12)) something like that

11:45 Anderkent: clgv: so it's either TableSwitch or LookupSwitch depending on whether your keys are sparse or not

11:46 I can't excactly find where it's emited in the compielr though. ..

11:47 clgv: Anderkent: just compile a function with `case` and use a decompiler to look it up

11:49 borkdude: Ah, the amount of users has grown with about 250 since I last paid attention to it

11:49 here

11:51 Anderkent: clgv: https://www.refheap.com/27009 yep, tableswitch

11:54 eyepatch: I'm looking at (take-while #(<= % 4000000) (fib))) I understand the whole bit except for # and % I'm not familiar with those characters. Where could I look them up in docs?

11:55 Obviously you could tell me what they mean in a few seconds. I'm guessing % is a replacement for some unknown value in a predicate that doesn't know what i'll work on and # will return the value of % when the predicate is true.

11:56 But I'd be surprised if this was the last time that I ran into unfamiliar characters.

11:56 borkdude: eyepatch it is the notation for anonymous functions

11:56 ,(#(+ % 10) 1)

11:56 clojurebot: 11

11:56 borkdude: eyepatch it's just fancy notation for ((fn [x] (+ x 10)) 1)

11:56 llasram: ,`#(expando! %)

11:57 clojurebot: (fn* [p1__52__53__auto__] (sandbox/expando! p1__52__53__auto__))

11:57 llasram: A "reader macro", in the parlance

11:57 Anderkent: eyepatch: but yes, googling for special symbols is really hard

11:58 eyepatch: I recommend spelling out symbol names, so try for example "clojure hash symbol" or "clojure pound symbol" (depending on wehre you're from :P)

11:58 gfredericks: llasram: yes the client closes the socket in the middle; also some other server-side error could happen to interrupt

11:59 eyepatch: Out of curiosity where is do people say pound and where do they say hash?

12:00 So it it similar to a lambda.

12:00 llasram: gfredericks: Ok. So with the CollReduce-based version, any error like that will cause an exception to be thrown within the dynamic scope of code you control

12:00 So as the stack unwinds, you can perform clean-up

12:00 eyepatch: oh silly me, it was in the "clojure in 15 minutes" thing.

12:00 Which is handy as a reference.

12:01 ok. Everything makes sense now.

12:01 Anderkent: eyepatch: I think europe says hash, usa says pound?

12:01 eyepatch: oh, ok.

12:01 Anderkent: for me pound is £ :P

12:01 llasram: eyepatch: What about senseless things? Do those now make sense?

12:01 eyepatch: I have the tendency to say British slang as an American.

12:01 llasram, senseless?

12:02 llasram: Anderkent: I say "hash" and am American

12:02 Anderkent: eyepatch: beause everything

12:02 eyepatch: Oh. right. I didn't qualify everything.

12:02 Hah, hah.

12:02 Anderkent: llasram: that's because you're a decent person!

12:02 llasram: heh

12:02 Anderkent: eyepatch: llasram: related: the only reason I use 7zip for everything is that it tells me 'Everything is OK' on each run

12:02 uplifting!

12:03 eyepatch: lol

12:04 Anderkent: AeroNotix: did you figure out how to do your split thing with areduce?

12:06 AeroNotix: Anderkent: sorry, no. I was updating my gpg key

12:06 llasram: gfredericks: The existing options for using a piped input stream or a seq are both fubar'd. With the input stream, nothing closes it, so your threat just fills the output stream buffer then blocks forever

12:06 gfredericks: With the seq option, you not only don't have any way of doing clean-up code, but

12:07 gfredericks: It turns out PrintWriter (which is what the servlet API uses) has this *insane* detail that it promises never to throw an exception after construction

12:07 gfredericks: So if the client connection closes, the ring-servlet loop just keeps pumping your seq into the void

12:11 TimMc: eyepatch: Hash, pound, sharp, number, octothorpe.

12:11 eyepatch: Some of those are actually different characters, but they are all sometimes written as "#".

12:13 locks: little-jailcell-window-bar-thingie

12:15 llasram: I just know that it has to be called "hash" so that Common Lisp's "#|" syntax is "hash-pipe"

12:16 locks: pound pipe is… yeah.

12:18 tbaldridge: "hash-pipe" wow, I need to find a reason to use that phrase

12:19 llasram: tbaldridge: Write more Common Lisp?

12:19 technomancy: that's asking a lot

12:19 tbaldridge: and seeing how the winds have changed in Colorado lately, I'm now much less likely to be arrested for using the phrase.

12:20 llasram: Oh, yeah -- I guess smoking more marijuana would also increase your number of opportunities for that phrase

12:20 locks: "no no, I meant an ASH pipe. they vintage son"

12:21 tbaldridge: I plan on using the phrase, not using the device the phrase suggests.

12:21 llasram: Just exploring the linguistic possibilities!

12:24 lvh: Hi

12:24 how can I do destructuring binding in my repl?

12:24 gfredericks: ,(let [[a b] (range 10)] [b a])

12:24 clojurebot: [1 0]

12:24 lvh: I want (let [[x y] (f)]), except with keeping the names around

12:24 like def

12:25 gfredericks: (defmacro defs [form expr] (let [syms (->> form flatten (filter symbol?))] `(let [~form ~expr] ~@(for [sym syms] `(def ~sym ~sym))))

12:25 Anderkent: (let [[a b] (f)] (def x a) (def y b)) :P

12:26 gfredericks: I think I left out a paren at the end there

12:26 but that lets you (defs [a b] (range 10))

12:26 Anderkent: #clojurelastwords

12:26 rasmusto: gfredericks: whoa, I've always assumed it wasn't safe to do defs like that, am I wrong?

12:26 gfredericks: rasmusto: in what respect?

12:26 rasmusto: not sure, for code reloading or something?

12:27 gfredericks: it just expands to what Anderkent suggested

12:27 rasmusto: oh, maybe I was trying to "def" something in a function as a means of having a mutable variable

12:27 Anderkent: non-top-level defs are discouraged, but as long as you don't do unsane things it's okay

12:27 gfredericks: oh yeah that's terrible

12:27 Anderkent: yeah exactly don't put that ina function

12:27 just top level

12:27 rasmusto: (I remember asking about it before I knew a damn thing about clojure)

12:27 s/clojure/fp

12:28 gfredericks: looks like that defs doesn't cover map destructuring

12:29 due to ##(flatten {:a [1 2 3]})

12:29 lazybot: ⇒ ()

12:29 rasmusto: ,(seq {:a [1 2 3]})

12:29 clojurebot: ([:a [1 2 3]])

12:30 lvh: hm

12:30 rasmusto: ,(flatten (seq {:a [1 2 3]}))

12:30 clojurebot: (:a 1 2 3)

12:30 lvh: how can do I step by step debugging? there seem to be a bunch of articles on google with few currently usableconclusions

12:32 rasmusto: ,(let [a [1 2 3], _ (prn a) b (map inc a), _ (prn b)] 'foo)

12:32 clojurebot: [1 2 3]\n(2 3 4)\nfoo

12:32 rasmusto: is how I debug step-by-step

12:32 lvh: probably not the answer you are looking for

12:33 `cbp: suddenly I go back to python and I'm at a total loss on how to do recursive traversal algorithms without persistent data structures

12:34 Anderkent: lvh: debugging is pretty flaky still. Eclipse with counterclockwise can somewhat do it

12:34 clgv: lvh: you can do that in counterclockwise

12:34 Anderkent: I usually just deftrace

12:34 rasmusto: `cbp: use += on mutable lists (and then quit in disgust)

12:34 Anderkent: and write tests :D

12:35 `cbp: sys.setsetrecursionlimit(10000) # yeahhhhh

12:35 TimMc: I tried writing a Python program recently.

12:36 mmitchel_: what happened?

12:36 rasmusto: here's how I write python nowadays: ^I^I(range) # syntax error

12:36 TimMc: It was going well until I had to figure out how to work with "unicode strings", and I was all http://replygif.net/i/310.gif

12:37 mmitchel_: lol

12:37 that's the best

12:37 rasmusto: TimMc: use bytearray

12:37 er wait, no that's even more confusing

12:37 Anderkent: .. I've caught myself doing (. delegate callMethodStuff) while writing java ..

12:37 `cbp: unicode strings, the GIL

12:37 the spanish inquisition was in the habit of burning python books

12:38 TimMc: All I wanted to do was to convert some strings to NFD, but nooOOOOoo

12:38 lvh: Cool, I fixed it by using more REPL.

12:39 rasmusto: lvh: how do you use the REPL, which environment?

12:39 lvh: rasmusto: cider

12:39 rasmusto: lvh: cool, I liked what I used of nrepl.el, but I'm a vim guy personally :D

12:40 lvh: if anyone feels like giving a newbie code review, https://github.com/lvh/pairing/blob/master/src/pairing/core.clj#L81 could use some

12:40 particularly the function on that line I think

12:40 Anderkent: I'm pretty happy with foreplay for vim

12:40 wait, it's called something else now isnt it

12:40 fireplace

12:40 rasmusto: Anderkent: fireplace, the public isn't ready for a plugin named foreplay

12:41 `cbp: lvh: would you paste an example input/output please?

12:41 rasmusto: well, not until we've had a good dose of cider

12:41 wink: is there a better way to get a mimetype of an image than this? (nio.file.Paths/Files) http://www.rgagnon.com/javadetails/java-0487.html

12:45 rasmusto: oh, I can't do :if-let in a for/doseq, right? should I nest another form?

12:46 or just a :let [blah (if ...)]] (if blah ...))

12:46 `cbp: you can have a :let and you can have a :when that filters

12:48 rasmusto: `cbp: hmm, I have a var thats bound to either each thing in a seq of things, or just once to nil, I'm not sure if :when helps

12:51 lvh: `cbp: Did you see the test file?

12:52 rasmusto: oh, I didn't know you could do ##(let [[a b] nil] [a b])

12:52 lazybot: ⇒ [nil nil]

12:52 `cbp: lvh: no I just saw your fn

12:52 rasmusto: ##(let [[a b] '()] [a b])

12:52 lazybot: ⇒ [nil nil]

12:53 rasmusto: is this a lisp-1/2 thing about nil being an empty list of sorts?

12:55 fredyr: ,(int 1.999999999999999)

12:55 clojurebot: 1

12:56 llasram: rasmusto: "nil punning"; orthogonal to lisp-1 vs -2

12:56 fredyr: ,(int 1.999999999999999)

12:56 clojurebot: 1

12:56 fredyr: ,(int 1.999999999999999999)

12:56 clojurebot: 2

12:56 noncom: fredyr: magic

12:56 fredyr: ^^ did you guys see this rounding thing on twitter?

12:56 i guess its a java thing

12:56 but im not really sure why

12:57 aperiodic: it's not a java thing, it's a fixed-point thing

12:57 `cbp: ^

12:57 Wild_Cat: what rounding thing?

12:57 `cbp: does the same thing in most languages

12:57 llasram: rasmusto: In CL, `nil` *is* (`identical?` to) the empty list. In Clojure, the seq API is to *treat* `nil` as an empty sequence

12:57 Anderkent: ,1.999999999999999999)

12:57 clojurebot: 2.0

12:57 fredyr: oh right

12:58 Anderkent: it worked with that paren, wat

12:58 `cbp: ,(

12:58 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

12:58 fredyr: on twitter it was

12:58 metellus: ,213354908fdjk

12:58 clojurebot: #<NumberFormatException java.lang.NumberFormatException: Invalid number: 213354908fdjk>

12:58 fredyr: ,(nth [1 2 3 4] 1.9999999999999)

12:58 clojurebot: 2

12:58 fredyr: ,(nth [1 2 3 4] 1.999999999999999999)

12:59 clojurebot: 3

12:59 rasmusto: ah yeah, saw that

12:59 fredyr: which threw me off a bit

12:59 rasmusto: ,1.999999999999999999

12:59 clojurebot: 2.0

12:59 rasmusto: ah ok, it's just a cast-to-int thing

12:59 Wild_Cat: more like IEEE floating point oddity.

12:59 fredyr: yeah

13:00 rasmusto: ,(nth [0 1 2 3] 1.999999999999999999)

13:00 clojurebot: 2

13:00 Wild_Cat: and not JVM-specific, for that matter.

13:00 rasmusto: illustrates it a bit more clearly

13:00 fredyr: yeah ofc its for any ieee floating points

13:01 (dec fredyr)

13:01 lazybot: You can't adjust your own karma.

13:01 fredyr: :s

13:01 Wild_Cat: funny how even when aware of the IEEE floating point imprecision thing, I always tended to assume that they were always erring downwards

13:02 (that is, that the number you get is always <= to the literal you typed)

13:02 when there's no such guarantee, as we just saw.

13:02 and I should have known better.

13:02 strijkijzer: So ehh

13:02 People here don't hate a lisp-like syntax but like it more I assume?

13:03 fredyr: lol

13:03 BullSherd: Wow, Google is making really strange things http://goo.gl/YEkaMA

13:03 funny haha xD

13:04 `cbp: ~guards

13:04 clojurebot: SEIZE HIM!

13:04 strijkijzer: fredyr, are you laughing at me?

13:04 Wild_Cat: strijkijzer: kinda hard to like Clojure and hate the Lisp syntax at the same time

13:04 ...although as far as I'm concerned, I like *Clojure*'s syntax -- that is, I find all the additions it made to the Lisp syntax great.

13:05 `cbp: I like it the most because of stuff like paredit

13:05 Wild_Cat: simple stuff like vector, map and set literals make it so much more readable.

13:05 `cbp: and paredit + multiple cursors = yes plz

13:05 fredyr: strijkijzer: sorry, but yes it is a reasonable thing to assume, that lispers don't hate lisp

13:05 strijkijzer: fredyr, maybe they see it as a lesser evil.

13:05 Syntax is typically the last concern for me to judge if I like a language, I can get around bad syntax if the semantics are sound.

13:05 Like, I hate Haskell syntax but apart from that the langauge is fine.

13:06 Wild_Cat: strijkijzer: bad syntax is hard to get around.

13:06 strijkijzer: So I was wondering if maybe people see the lisp like syntax as a lesser evil or something?

13:06 `cbp: bad syntax is I have to google for how to write the stupid thing but oh guess what the whole thing is ungoogleable

13:06 strijkijzer: Well, it's one of the least important parts of programming language design insofar that most languages just re-use the same syntax that was used before and slightly modifiy.

13:06 Wild_Cat: I liken it to typing on an uncomfortable keyboard -- sure, you can do it, but it always gets in the way.

13:06 strijkijzer: THere are basically 3 big syntax families in use. C-style, Lisp-style and ML-style.

13:07 But apparently people don't see it as a lesser evil

13:07 technomancy: you can tell when someone's new to lisp; it's the people who aren't totally keen on homoiconicity

13:07 strijkijzer: I hear a lot from people that they don't like it though which confuses me.

13:07 It's not as much the homo-iconicity that I like as much as the consistency and simplicity and explicitness.

13:08 Wild_Cat: strijkijzer: I can see how "bare" Lisp syntax can be a pain. I mean, like I just said, I don't like it when a language goes too far in the minimalism direction.

13:08 strijkijzer: If you see something like x %% y *# z in Haskell you're just going to guess what the praecedence is.

13:08 Hmm, I don't like "special rules" too much.

13:08 Wild_Cat: vector/map/set literals make Clojure far more readable than most Lisps I've been exposed to.

13:09 strijkijzer: Like ehh, in Haskell, a year back I was trying to define a (..) operator for double function composition (.) is single function composition, turns out I can't do this because it has [n..k] syntax which is basically (range n k)

13:09 Wild_Cat: ...for that matter they make any language that has them more readable.

13:09 strijkijzer: I really wonder why on earth [n..k] is necessary, surely range n k suffices?

13:09 Wild_Cat: (yes Java, I'm glaring at you)

13:10 (and I'm also glaring harder at C++ which doesn't even have *string* literals)

13:12 strijkijzer: Wild_Cat, well, the point is it is arbitrary in languages which allow you to define arbitrarily complex new algebraic datatypes.

13:12 `cbp: strijkijzer: for the same reason you need to put a comma between every item in a data structure

13:12 strijkijzer: You can't define new datatypes in clojure can you?

13:12 `cbp, what is that a reply to?

13:12 Anderkent: strijkijzer: define datatype. defrecord might be what you want?

13:12 Wild_Cat: strijkijzer: new datatypes as in new literals, or as in new data structures?

13:12 `cbp: syntax that seems to be designed for people that write with pen and paper

13:13 Wild_Cat: because if it's the latter, you absolutely can.

13:13 `cbp: strijkijzer: the [n..k] thing

13:14 strijkijzer: Wild_Cat, well is it possible in clojure to create a myList whose interface in every way is identical to the current list

13:14 jita: Which is better ide eclipse or intellij idea ?

13:14 strijkijzer: or a my-vector.

13:14 Wild_Cat: strijkijzer: sure.

13:15 strijkijzer: Wild_Cat, ah I wasn't aware of that.

13:15 And this runs with the same performance internally?

13:15 Wild_Cat: strijkijzer: it's even necessary to be able to do that, due to the fact that Clojure interops with Java

13:15 `cbp: strijkijzer: it's usually best to write high performance data structures with java

13:15 then write a clojure wrapper

13:16 strijkijzer: Well, I'm asking about the possibility.

13:16 Wild_Cat: strijkijzer: I'm guessing the performance will be inferior because Clojure's vector is implemented in Java at a lower-level.

13:16 strijkijzer: At least, my point with loads and loads of special syntax for data structures is that it's arbitrary.

13:16 I think (vector a b c d) suffices for [a b c d] really.

13:16 Wild_Cat: strijkijzer: of course it is. But that's not a good enough justification to not add in literals for the most commonly-used data structures.

13:17 tbaldridge: Wild_Cat: the funny thing is, the java version of vectors is almost exactly like what Clojure would spit out if you used deftype, protocols and type hinting.

13:17 Wild_Cat: the square brackets jump out at me, making it easier to identify the vector.

13:17 (likewise {} for maps)

13:17 tbaldridge: Wild_Cat: so there may not be a performance difference at all.

13:17 strijkijzer: Well, at one point this does some pretty convoluted things wityh the language syntax, OCAml definitely has this problem that the language syntax deifnition becomes too overloaded because of all rthis and typos often result in it not becoming bad syntax but something you didn indend.

13:17 Wild_Cat: especially when you take into account the fact that Clojure uses vectors and maps *a lot*.

13:18 technomancy: ocaml's precedence rules =(

13:18 llasram: Raynes: ping

13:18 Raynes: Hello, this is Raynes.

13:18 llasram: Raynes: https://github.com/Raynes/bultitude/commit/68491b281a5de760fc44e087fffdca2e03b2ef6b

13:18 Wild_Cat: strijkijzer: language design, at that point, becomes a matter of taste and restraint: how many special cases do you add?

13:18 llasram: THe `(second form)` -> `form` commit changes the public interface

13:18 Is this known?

13:19 Wild_Cat: (that's an open question that every language designer will answer differently. I think Clojure hits a sweet spot, or pretty close to one)

13:19 (I also think Python hits another one)

13:19 Raynes: llasram: The commit specifically states that it shouldn't break existing functionality. If it does, then I will promptly release a new major version and beat Grayson up.

13:20 And by 'promptly' I mean at like 10PM tonight PST.

13:20 :P

13:20 llasram: I'm confused why no one has noticed until now, because it breaks the Leiningen test, but yeah -- `ns-form-for-file` used to return just the ns symbol, but now returns the full form

13:20 strijkijzer: Wild_Cat, well yeah, obviously it's super subjective.

13:21 If I designed a syntax, I would probably make numbers default to hexdecimal and read from lefty to right.

13:21 teslanick: Are there any guides for building an om/clojurescript app side-by-side with a clojure app?

13:21 strijkijzer: Note that we currently read numbers from right to left ina script that coes from left to right

13:22 llasram: s,the Leiningen test,a Leiningen test,

13:27 fredyr: teslanick: do you mean with a clojure backend or something?

13:28 teslanick: fredyr: Yeah. With the possibility of logic-sharing across the two stacks.

13:29 fredyr: teslanick: ah right, i haven't seen anything with om/cljs to that end

13:30 teslanick: but there has been alot of buzz about cljx for code sharing between cljs and clj lately

13:32 teslanick: Interesting, thanks!

13:36 llasram: Raynes: To clarify, you are planning on bumping the version vs restoring the old interface, yes?

13:36 Well, I guess bumping w/o restoring vs bumping + restoring

13:40 Anderkent: FWIW, the change makes sense to me, and something like 'ns-symbol-for-file' could be added for the old functionality

13:41 llasram: Anderkent: Yeah, I don't honestly care. I just want to fix Leiningen in a way that won't need to be changed again right away :-)

13:41 Anderkent: :D

13:41 (let [ns-sym (if (symbol? ns-form) ns-form (second ns-form))]) ex!

13:41 *ez!

13:41 :P

13:42 * llasram looks askance

13:42 gfredericks: (cond-> ns-form (symbol? ns-form) (second))

13:42 or the other way

13:43 llasram: Better, but I'm looking for a social solution :-)

13:49 Raynes: llasram: Bumping the version number.

13:49 The change was necessary for a Leiningen feature

13:49 llasram: Raynes: Awesome

14:03 DomKM: If you were going to read SICP, On Lisp, Lisp in Small Pieces, and Let Over Lambda, in what order would you read them?

14:03 That's the order I'm reading them but I'm interested in what someone who has already read them thinks

14:04 jcromartie: I'd read half of SICP first, then give up, and then do the same with the rest in any order you'd like.

14:04 :P

14:04 that's just what I've done

14:04 DomKM: lol

14:04 deadghost: I have a terrible tendency

14:04 to stop reading books half way through

14:04 halfway is enough for me to be dangerous

14:04 then I go be dangerous

14:05 and say I'll go back to finish eventually

14:05 (hasn't happened yet)

14:07 DomKM: yeah that's a distinct possibility

14:09 jcromartie: you usually get your dopamine hit (for me, when SICP demonstrated how you can build any data structure with closures) about halfway through these books

14:12 fredyr: i've never found let over lambda particularly engaging, so never gotten far

14:13 tbaldridge: DomKM: to be honest, in the older lisp books, the lisp being used is so primitive, I wonder if it's worth reading those before the Clojure books.

14:13 I went back and read some Scheme code the other day, and my reaction was "why on earth would you code this way...oh yeah, you don't have types, or literal hash maps, or immutable vectors or....."

14:14 bbloom: tbaldridge: i'm trying to write some C right now... my brain hurts

14:14 tbaldridge: but it's not the memory management or the low level anything...it's just like... wait... why the fuck are structs in different namespaces from other types?

14:14 DomKM: tbaldridge: I've already read most of the clojure books, I consider these readings to be more foundational than instructional

14:14 bbloom: and how come i can't add a new namespace without prefixing symbols?

14:15 tbaldridge: bbloom: what are you writing?

14:16 bbloom: tbaldridge: all kinds of fun/terrible stuff :-P

14:19 deadghost: is there a list of cool stuff written in clojure I can peruse?

14:20 Anderkent: deadghost: https://github.com/trending?l=clojure ? :D

14:21 deadghost: that works

14:22 though I'm looking more for a whole project than libraries

14:22 Anderkent: right, don't know about that, projects by nature don't get as much visibility

14:24 I mean I guess it depends on what you'd call a project. Maybe just read through sources of tools that you can use? lein, lein plugins (cloverage! except code be ugly) etc.

14:24 but in general reading sources of real projects is not actually that constructive

14:25 deadghost: Anderkent, I was more looking for the purpose of hyping myself up


14:25 Anderkent: oh

14:25 llasram: Code in a non-library project is just code you don't expect to be able to reuse :-)

14:25 deadghost: CLOJURE!!!1!!11!

14:25 Anderkent: right, and because you don't expect to reuse it and just want to get shit done it tends to not be as pretty :P

14:25 deadghost: I dunno, lighttable?

14:25 is pretty cool

14:26 algernon: deadghost: core.logic, kibit are two things that are jawdropping (and are reasonably understandable)

14:26 Anderkent: core.async is pretty cool too

14:26 algernon: also, overtone. never forget overtone and what Sam Aaron does with it.

14:26 deadghost: oh right

14:26 I've been meaning to play with overtone

14:37 lvh: Hi :) if anyone is willing to scan some newbie code and give feedback, I'd be much obliged: https://github.com/lvh/pairing/blob/master/src/pairing/core.clj#L81

14:44 cark: lvh: a cursomary glance, and it looks quite neat

14:44 lvh: cark: Cool! Thanks :)

14:45 cark: lvh : tho i personally prefer being a bit more explicit about the data

14:45 stompyj: Just want to canvas the community here, for those running clojure web apps, whats your deployment vehicle? immutant? jetty + apache, jetty + nginx? beanstalk/

14:45 lvh: cark: How do I do that?

14:45 Anderkent: lvh: the one thing I've mentioned before - I'd swap around the order in if statements, so that you don't have to scan through 15 lines to find the else clause

14:45 cark: lvh : I like having constructor functions for my data

14:45 llasram: stompyj: jetty in an uberjar fronted by apache right now. Want to move toward immutant though

14:46 stompyj: llasram: any reason why apache over nginx? I only ask because I haven't used apache in so long, I'm curious if there's something I'm missing there

14:46 lvh: cark: Ah. I have not done that yet because the data will be coming from gnlary csv data so I will need to write an explicit munging layer :)

14:46 cark: lvh : and let it be known that i disagree with Anderkent =)

14:46 llasram: stompyj: And these are all internal Web service -- nothing public facing

14:46 lvh: Anderkent: Sorry I missed that before

14:46 llasram: stompyj: Because we have tiny team who all knows how to make Apache dance :-)

14:46 lvh: Anderkent: So (if (not (seq x ...?

14:46 stompyj: llasram: haha, fair enough

14:47 Anderkent: lvh: (if-not

14:47 lvh: oh, I didn't know about if-not

14:47 stompyj: llasram: how do you deploy?

14:47 cark: don't do that ><

14:47 it's harder to understand

14:47 Anderkent: stompyj: the one clojure webapp I've used was on aleph, which I believe is powered by netty. Then just pushed as an uberjar to heroku

14:48 cark: how come it's harder to understand?

14:48 llasram: stompyj: jenkins builds .deb packages and pushes them to an APT repo, from where puppet then deploys them

14:48 stompyj: llasram: wow

14:48 cark: Anderkent: negation is harder on the brain, at least I think it is

14:48 Anderkent: huuuh

14:49 I'm so confused right now but I'll accept that you don't like negation

14:49 llasram: stompyj: What sort of "wow" was that? :-)

14:49 Anderkent: for me (if-not (seq)) is completely idiomatic and automatically parses as 'empty seq'

14:50 and having the short branch first makes it much easier to scan the code

14:50 indentation's not reliable over 20-lines

14:50 cark: ahwell that's a fine point anyway

14:50 Anderkent: I suppose the other solution is to just pull out the long body into a helper fn

14:50 bhauman: confused about how to determine if an instance implements a Protocol in cljs

14:50 cark: can't do that with the recur

14:50 stompyj: llasram: it was a "another deployment strategy I've not heard of yet" wow

14:51 llasram: I've been working in ruby since 2004, and .NET/Java before that... so while I 100% love clojure, I'm still trying to find the right level when it comes to deployment

14:51 llasram: stompyj: It was inspired by this: https://hynek.me/articles/python-app-deployment-with-native-packages/

14:51 Anderkent: bhauman: satisfies? protocol object) I think?

14:52 stompyj: the ruby in me tells me just to deploy via beanstalk / heroku. But the old enterprise programmer in me wants to invest time in immutant or jetty and do a ansible deploy, etc

14:52 bhauman: Anderkent: thanks will try that :)

14:52 Anderkent: llasram: I did something similar in python but only because we had a 2gb dependency (xelatex)

14:53 cark: lvh : The one thing I don't like is that the shape of your data is not directly apparent. But on the other hand the code is neat. So if it works with you it's all good

14:53 llasram: stompyj: Yeah, it depends on your use-case. If I were starting from scratch for a public service on cloud infrastructure, would probably do it entirely differently

14:54 Anderkent: I did it because we have stuff in Python, Ruby, and Clojure, and our previous system was a mess.

14:54 bhauman: Anderkent: thanks, that bit of basic knowledge goes a long way. And now I see it there on the protocols page.

14:54 Anderkent: yeah, got it

14:54 bhauman: no worries, pretty used to googling stuff for people ;>

14:55 llasram: Anderkent: Following the same model for everything got deployment entirely automated, and with atomic packages using the language-appropriate tools

14:55 bhauman: Anderkent: I google the crap out of that and it just wasn't surfacing for me

14:55 Notte: Hi, is it possible to have a function with two vector parameters that destructures the second one into head (which i don't care) and tail?

14:56 jcrossley3: llasram: when the time comes, we'd like to help get debian init scripts hardened for immutant, too.

14:56 cark: (defn vecs [vec1 [h & tail]] ...)

14:56 bhauman: Notte: ^

14:56 rasmusto: ,(let [a [_ & tail] [[1 2 3] ['foo 4 5]] [a tail])

14:56 clojurebot: #<RuntimeException java.lang.RuntimeException: Unmatched delimiter: )>

14:57 Notte: cark: thanks. I was writing it wrong.

14:57 llasram: jcrossley3: I have to confess that I personally just use runit :-)

14:57 rasmusto: whoops, missed something

14:57 ,(let [a [_ & tail] [[1 2 3] ['foo 4 5]]] [a tail])

14:57 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: let requires an even number of forms in binding vector in sandbox:>

14:57 jcrossley3: llasram: cheater ;)

14:58 lvh: cark: Would a defrecord fix that

14:58 cark: lvh : don't sweat it. Your code is idiomatic enough. What matters most is to get the product done !

14:59 Anderkent: bhauman: my query was 'clojure implements protocol' FTR, which brings up clojure.org/protocols, which mentions extends? and satisfies?

14:59 bhauman: genius!

15:00 esancho: llasram: do you use something like Rundeck to orchestrate deployments with puppet?

15:01 llasram: esancho: Not yet, but we just finally got an ops person who knows this stuff, and he's got plans

15:01 Anderkent: queue evil sysop laugh

15:01 llasram: esancho: For now we just have our internal packages set to be 'latest' and do an `apt-get update` (against internal repos only) on each run

15:02 danneu: What's a good way to create a config.edn file that lets you change things on the fly in production? slurp + a ttl cache?

15:04 lvh: is there a refactoring lib that can rename a function across a project

15:04 clj-refactor.el

15:04 I have that; but it only has file renames.

15:06 esancho: llasram: gotcha, the tricky part is when you need to orchestrate deployments across multiple servers... I'm working on something similar right now and it was funny to read about it in #clojure

15:07 llasram: esancho: Ah, yeah. That's rare enough for us that it's still manual. Perfect, enemy of the good, etc :-)

15:09 stompyj: llasram: back, catchingup

15:10 llasram: I might wimp out and go with clojure to start. the thing is that I want to use fluentd or something like that to capture pretty detailed logging events, etc

15:10 llasram: and if I decide to do apache / jetty, then I need to build a chef script that deploys all that stuff (chef is what we currently use), but what I really want to do is use ansible,

15:10 Im being wishy washy atm :)

15:11 llasram: You can only find better ways by trying new ways, but you can only get stuff done by doing things which work. Always a dilemma!

15:13 stompyj: yeah, its further complicated by the fact we are 85% done with this project, and we have about 3 months before it has to launch

15:13 so lots of naval gazing time

15:13 if I don't keep myself on track

15:13 heh

15:17 gfredericks: I'm seeing some spooky dependency resolution involving lein plugins

15:17 llasram: Spooooooooky

15:20 stompyj: llasram: another question, do you guys write tests? and if so, which lib are you using

15:21 llasram: stompyj: For deployment?

15:21 stompyj: oh no, TDD type testing

15:21 Anderkent: midje for functional tests, junit for integration

15:21 stompyj: i'm using midje right now

15:21 as well

15:21 dima_: any quick ideas on how to get lein work with some java code using "lombok"? lein pom; mvn compile works, lein compile and lein javac fail with ClassNotFound for "com/sun/tools/javac/processing/JavacProcessingEnvironment"

15:21 gfredericks: project has dep [A 2] and plugin [C 1] -> [B 1] -> [A 1]

15:22 stompyj: I'm finding that unit tests aren't as important due to the functional nature of clojure + the repl

15:22 llasram: stompyj: Oh, we use clojure.test for all our Clojure testing.

15:22 We used midje for some Cascalog projects, because of midje-cascalog, but the level of magic got too intense for me

15:22 Plus my experience is that the way midje wants to run tests when compiling a namespace cramps the typical Clojure workflow

15:23 stompyj: llasram: Anderkent: thanks

15:23 Anderkent: llasram: yeah thats why our facts are deftest wrapped ;p

15:23 my pain with midje is mostly that factoring stuff out is really hard

15:23 because fact is a macro, you cant just call a function that makes some assertions

15:23 llasram: Anderkent: I remember trying that and running into some sort of issue -- don't recall exactly what

15:23 stompyj: do you guys have any experience with mocking out third party services in midje? This is the one thing I can't wrap my head around re: tests

15:24 Anderkent: stompyj: if you have a clojure api for them, just (provided (third-party/request :arg1 "foo") => {:response :body})

15:24 gfredericks: oh I think this is speclj's fault somehow

15:25 stompyj: Anderkent: that makes sense. then where do you stick all the gnarly responses? inside the test suite itself? or do you load them from a file? currently I have a bunch of (def something <INSERT GNARLY JSON HERE>)

15:25 I will say, I've only ever done TDD in ruby (and a smidge in C#) so outside of the ruby world, I have a ton of "where does this go" questions

15:26 egghead: dnolen: am I correct in my observation that om doesn't support lists (only vectors) ?

15:26 ddima: nobody? :/

15:27 Anderkent: stompyj: so you probably want to separate this into two layers. One that transforms the gnarly responses into nice data structures. In there you can just put the model responses in test-resources and load from file

15:27 then on the business layer you just mock your interaction layer and return maps with whatever you expect

15:27 stompyj: interesting. makes sense

15:28 test/resources is an idiomatic clojure directory structure for such things? (I've never heard of it)

15:29 Anderkent: I believe it's test-resources in lein

15:31 Notte: ,(do (defn t [coll1 [_ & coll2]] (cond (and coll1 coll2) 0 (and coll1 (not coll2)) 1 :else 2)) (t [] []))

15:31 clojurebot: 1

15:32 Notte: Would anyone explain me why is it happening, please?

15:33 ,(true? (and [] (not [])))

15:33 clojurebot: false

15:33 edbond: ,(not [])

15:33 clojurebot: false

15:34 edbond: ,(and true false)

15:34 clojurebot: false

15:34 edbond: ,(true? [])

15:34 clojurebot: false

15:34 RickInAtlanta: ,(if [] true false)

15:34 clojurebot: true

15:34 edbond: Notte, ^^^

15:34 Notte: ow

15:35 egghead: Notte: because coll2 doesn't exist?

15:35 logic_prog: is there a way in clojure code to say: "fire off a nrepl at this point" ?

15:35 i.e. a nrepl which has (1) the local environments, (2) I can evaluate forms, and (3) pick a value to return?

15:35 egghead: Notte: why do you expect coll2 to exist?

15:36 ,(and [] (not nil))

15:36 clojurebot: true

15:36 Notte: egghead: i don't know. Sorry.

15:36 egghead: Notte: it's the way destructuring works, if it can't find a match it binds 'nil'

15:37 Notte: ok

15:37 thank you, edbond and egghead

15:37 egghead: if you have [] as your data and [_ & x] as your match, then it will try to break [] into first and rest, binding x to rest

15:37 if you try to get (rest []) you get nil

15:38 hope this helps Notte

15:39 Notte: i'll remember it

15:40 gfredericks: when a lein plugin has :dependencies, those should never get on the app's classpath, correct?

15:41 egghead: hopefully gfredericks are you seeing otherwise?

15:42 hiredman: some plugins will inject things in to the projects deps

15:44 gfredericks: hiredman: this one doesn't obviously

15:44 https://github.com/slagyr/speclj/blob/2.9.0/src/leiningen/spec.clj#L23

15:44 I am seeing otherwise

15:44 about to post a minimal reproducing project

15:46 here it is: https://github.com/fredericksgary/bad-deps

15:46 actually this is quite weird because it's one plugin causing another unrelated plugin's dep to be used

15:47 `lein deps :tree` does not pick up on this

15:48 danielglauser: gfredericks: did you try `lein shadowdeps :tree`?

15:48 :)

15:48 gfredericks: :P

15:49 migratus-lein is a plugin that depends on migratus which depends on an old java.jdbc

15:49 speclj is a plugin that runs tests

15:50 Anderkent: gfredericks: when I try running that project I can't even `lein with-profile speclj repl`

15:50 gfredericks: Anderkent: what's it do?

15:50 Anderkent: crash saying nrepl is not on classpath

15:50 gfredericks: me too; I wonder why

15:51 something about how with-profile works maybe

15:51 all that profile does is change the :test-paths

15:52 Anderkent: crazy. that's even if I remove the plugins

15:52 gfredericks: you should be able to avoid with-profile by setting test-paths at the top level and using `lein spec`; but then `lein test` won't work for normal reasons

15:52 I think you're describing a different [non-]problem

15:52 sdegutis: Quick design question. I have a macro that basically does (if ~condition (do ~@body) (handle-error)) and I want to replace it with non-macro code. But I'm finding that `body` is often multiple things, so I need to wrap it in (do), which can look a little ugly inside an (if) but can't be replaced with a (when) on account of the else-clause. What would you do in this case?

15:53 llasram: sdegutis: Just use the macro

15:54 gfredericks: so where is the classpath actually constructed?

15:57 leiningen.core.classpath probably

15:58 Anderkent: gfredericks: yeah, you get both jdbcs on your classpath with that profile

15:59 gfredericks: Anderkent: how did you figure that out?

15:59 Anderkent: printed out the classpath from main

15:59 :D

15:59 sdegutis: llasram: hmm, that's one idea, but I can't help feeling like it's non-idiomatic to have (with-some-effect some-arg ...) in my code.

15:59 Anderkent: (println (seq (.getURLs (java.lang.ClassLoader/getSystemClassLoader))))

16:00 gfredericks: good to know

16:01 sdegutis: This macro mainly exists to hide a (do) and the else-clause, and I'm not sure that's a good enough reason for it to be a macro.

16:01 gfredericks: Anderkent: wait are you doing that without running the spec task?

16:01 Anderkent: I get the normal deps using `lein with-profile speclj run`

16:02 at least it prints the normal version

16:02 Anderkent: no, I mean with the spec task

16:02 so I assume it's the speclj plugin messing things up

16:02 gfredericks: right

16:03 I can't figure out how though because it seems like the task gets to eval-in-project pretty quick without touching anything weird

16:03 Glenjamin: the speclj plugin does something really odd

16:03 i ran into this the other week, 1 min

16:03 sdegutis: gfredericks: why did you choose speclj?

16:03 gfredericks: sdegutis: I didn't

16:03 am debugging for a coworker

16:04 Glenjamin: i chose it because i like the RSpec test spec style

16:04 Anderkent: gfredericks: but the speclj plugin adds spelcj to your classpath somehow right?

16:04 I don't see where it happens but it must

16:04 Glenjamin: in a recent version of speclj they stopped using a second jvm process

16:04 and ran tests in the lein process itself

16:04 gfredericks: waat

16:05 Anderkent: that'd do it

16:05 Glenjamin: you can fix by adding ":speclj-eval-in :subprocess" to your project.clj

16:05 https://github.com/slagyr/speclj/pull/67

16:05 hiredman: https://github.com/slagyr/speclj/blob/2.9.0/src/leiningen/spec.clj#L33

16:05 Glenjamin: thats the one.

16:05 took me a good hour or so to track down

16:06 sdegutis: Wow.

16:06 (re: the pull request)

16:06 gfredericks: huh

16:06 Anderkent: gfredericks: so you basically want a dependency on speclj instead of :plugins speclj

16:06 rasmusto: i had nil pudding for lunch

16:06 Glenjamin: you need both if you want to do "lein spec"

16:07 sdegutis: (inc rasmusto)

16:07 lazybot: ⇒ 3

16:07 gfredericks: Anderkent: or both? how does `lein spec` work if it's not a plugin?

16:07 Glenjamin: "just run it in the same JVM to save 3 seconds" seems like a reasonable idea, apart from the part where it isn't

16:08 Anderkent: you're right it's both

16:08 Glenjamin: gfredericks: you need both so you can do lein spec, but adding ":speclj-eval-in :subprocess" should fix classpath weirdness

16:08 Anderkent: Glenjamin: actually it kind of is, but you want to fire off a new classloader

16:08 hiredman: it is a plugin that runs code in the projects process, so it injects a speclj dep into the project

16:09 Glenjamin: Anderkent: i don't know enough about java/jvm to deal with classloaders, but i would love to be able to run stuff with siloed dependencies

16:09 defeat callback hell and all that

16:09 sorry, dependency hell

16:09 gfredericks: I'm having trouble getting this to work after adding :subprocess

16:09 Glenjamin: gfredericks: when i ran into the issue, it was because speclj and lein itself clashed on some dependency

16:10 pcn: Are there libraries that make file handling easier? I'd like something that implicitly manages a file using with-open, and provides an split. And that buffers reads and writes.

16:10 Anderkent: lein trampoline was a thing wasnt it

16:10 Glenjamin: lein trampoline is a funky hack

16:10 the lein shell wrapper reads a file that the lein jvm left behind and execs it

16:11 but shouldn't make a difference vs subprocess

16:11 gfredericks: Glenjamin: thanks for figuring this out :)

16:11 Glenjamin: got it working?

16:11 Anderkent: ah. I thought trampoline was reusing the same process, just doing classpath magic

16:11 but I guess it's not

16:12 hlship: Curiousity: when extending a protocol onto Clojure maps, it seems like you could extend APersistentMap, IPersistentMap, or even Associative. What is the best choice, or what do you need to consider to make a choice.

16:14 gfredericks: Glenjamin: no but I'm not surprised it doesn't work anymore :)

16:14 Glenjamin: http://www.flyingmachinestudios.com/programming/lein-trampoline/ : "How Clojure Babies are Made: Leiningen's Trampoline"

16:14 gfredericks: downgrading to speclj 2.8 is probably not unreasonable

16:14 Anderkent: Glenjamin: yeah I found it now

16:14 gfredericks: I got it to run tests, it just crashed on checking the exit code ;p

16:14 I'd raise a bug with speclj

16:15 make them worry about it

16:15 Glenjamin: yeah, i might see if they'll change the default back - it doesn't seem like a good idea

16:15 gfredericks: yeah I saw the exit code thing too

16:15 Glenjamin: the solution to slow jvm startup with speclj is to use --auto

16:15 gfredericks: so leiningen has a feature where if you say :eval-in :leiningen it... how the hell does it get your normal dependencies in that case?

16:15 Anderkent: as to classpath isolation, yeah, I'd like a nice thing for it too

16:16 right now I'm also sharing the classpath with environment project in my plugin (cloverage)

16:16 llasram: gfredericks: That's intended for plugins and the like, for the plugin code itself. The speclj plugin doing this is totes counter-purpose

16:17 Anderkent: the current idea to fix it is to switch to subprocess evaluation, but that means I have to make intrumentation produce files rather thane val things, and bleh in general

16:17 technomancy: gfredericks: :eval-in :leiningen turns :dependencies into :plugins

16:17 Anderkent: *than eval

16:17 technomancy: effectively

16:17 gfredericks: technomancy: how does it do that after the process has already started up?

16:17 Anderkent: technomancy: does it attempt resolution or just takes project classpath and appends it to current one?

16:18 technomancy: gfredericks: pomegranate classloader tricks

16:18 Anderkent: it does a new resolution

16:18 Anderkent: then a duplicate classpath entry is probably a bug there

16:19 oh unless it did a new resolution, got a differnt version... Can you remove things from classpath?

16:19 OscarZ: i have a vector x of maps and i want to return the same vector but without a specific map that i can find with (apply min-key :value x).. whats the best way to do this? probably something simple that im missing again :)

16:19 Glenjamin: gimme 2 mins i can tell you what i conflicted on...

16:20 AimHere: OscarZ, filter sifts a collection by a predicate

16:21 technomancy: wow wait... speclj runs project code in leiningen by default?

16:21 OscarZ: oh i thought i tried filter.. so predicate like #(not= y %) should work ?

16:21 technomancy: ._.

16:21 Anderkent: technomancy: yep, because it saves 3 seconds!

16:22 AimHere: OscarZ, well that's one example of a predicate

16:22 technomancy: http://p.hagelb.org/10no.gif

16:22 AimHere: You'll have to craft the appropriate one for your problem!

16:22 Anderkent: technomancy: https://github.com/slagyr/speclj/pull/67 go and post that there :

16:23 Glenjamin: right, yeah

16:24 the problem I had was speclj wanting a newer version of clj-stacktrace than the one that leiningen had already loaded

16:24 which was resolved by telling it not to do :eval-in :leiningen

16:25 * technomancy refrains from using a gif

16:25 Anderkent: I mean okay, what they did before was also insane

16:26 they spawned off their own jvm

16:26 rather than using eval-in-project

16:26 technomancy: pretty weird

16:26 Anderkent: yeah I don't even

16:26 technomancy: http://p.hagelb.org/comfort.jpg

16:27 Anderkent: How many pics do you even have there. Damn you for not having an index

16:27 sturner: Anyone familiar with http://www.prismtech.com/opensplice and worked with DDS in general from Clojure?

16:27 technomancy: mwahaha

16:28 gfredericks: I bet he has an emacs function that searches his images directory to make sure he gets the url right

16:29 he can send a gif url in an avg of 4 keystrokes

16:29 technomancy: I've stopped trying to save keystrokes since getting a mechanical keyboard

16:29 Anderkent: he just has a mapping from emoticones to gifs on outgoing text

16:29 technomancy: since each keystroke is so crisp and satisfying

16:29 I no longer want to minimize that feeling

16:30 seangrove: technomancy: Is there a way to specify host on the command line when starting a repl?

16:30 bbloom: technomancy: aw yeah, mmm mechanical. love it

16:31 technomancy: seangrove: LEIN_REPL_HOST I think

16:31 bbloom: cherry MX blues; I heart them so much

16:31 jkj: steampunkical keyboard

16:31 teslanick: keyboard nerds are the worst. ;)

16:31 pcn: technomancy: you must have your own office. I had to take away the keyboard from an intern when he got one a couple of years ago.

16:31 Glenjamin: wow, this speclj task stuff is really weird now

16:31 Anderkent: pcn: there are silent mechanical switches

16:31 pcn: Oooooh.

16:31 seangrove: pcn: My coworker made me give up the kinesis for the same reason

16:31 bbloom: technomancy: kenesis man myself

16:31 Glenjamin: i'm gonna have to dig in and see if i can make this sensible again

16:31 technomancy: pcn: https://secure.flickr.com/photos/technomancy/tags/laboratory yeap

16:31 Anderkent: oh sorry didnt see cherry mx

16:31 seangrove: technomancy: That did it, thank you

16:32 technomancy: it's not an office; it's a laboratory =)

16:32 Glenjamin: there's one guy in our office with a mechanical

16:32 pcn: That's nice.

16:32 Glenjamin: lucky for us he's a manager now, so doesn't type much

16:32 technomancy: seangrove: psh; the kinesis is silent compared to this

16:33 pcn: Where'd you get the desk from?

16:33 also: is it normal for leiningen to give the error "Checksum validation failed, no checksums available from the repository" only the *first time* the dependency is fetched?

16:33 technomancy: pcn: ikea jerker, I think

16:33 seangrove: technomancy: You could just wire your keyboard to play machine-gun fire sound effects whenever you're typing if you're going for a visceral, loud effect

16:34 teslanick: What's the idiomatic way to loop over something with an incrementing index? loop/recur?

16:34 AimHere: You want to *feel* the machine gun effects too

16:34 gfredericks: Glenjamin: coworker pointed out that `run -m speclj.main` works

16:34 Glenjamin: heh

16:34 Anderkent: teslanic map-indexed ?

16:34 technomancy: seangrove: supposedly having audio feedback in the switch itself can help train you to reduce force to the exact amount required for activation rather than bottoming out every time

16:34 Glenjamin: gfredericks: it's possible to use in a repl too, but a bit fiddly

16:34 pcn: Ah, they don't make taht any more

16:34 technomancy: not really something you can do in software

16:35 pcn: I think they just renamed it

16:35 teslanick: Anderkent: thanks. don't know how I didn't see that.

16:35 Anderkent: that's okay

16:38 pcn: technomancy: I think it's dead and gone. The replacements aren't reputed to be as good.

16:39 logic_prog: has ritz been ported to cider, or is it still nrepl only?

16:39 technomancy: pcn: ah, shame

16:39 big fan of standing desks

16:41 Raynes: technomancy: Can you tell that Python tooling frustrates me? https://www.refheap.com/27051

16:41 technomancy: Raynes: my deepest condolances

16:42 bbloom: virtualenv is a massive pain

16:43 technomancy: "at least it's not rvm"

16:43 seubert: virtualenvwrapper is fine..

16:43 bbloom: ugh.

16:43 Raynes: Well, my problem is that virtualenv.el expects me to just have a single directory for all my envs.

16:43 I'm fine with virtualenv.

16:43 bbloom: doesn't python have PYTHON_PATH or something?

16:43 Raynes: It's also not gonna matter because Python has replaced it in core.

16:43 pyvenv yo

16:44 Anderkent: technomancy: +1

16:44 unless you were being sarcastic

16:44 Raynes: Presumably at some point people will grow nads and switch to Python 3 across the board...

16:44 bbloom: meanwhile, plan9 got this right however long ago: union directory mounts > various virtualenv nonsense and PATH variables

16:44 Glenjamin: does it handle multiple pythons, or does it still just do different package loading dirs per app?

16:44 sdegutis: I think Take Me Out should be the official Clojure song, it epitomizes everything Clojure's about, from FP to abstracting sequences: https://www.youtube.com/watch?v=Ijk4j-r7qPA

16:46 pcn: Raynes: python 2 won't dissappear until all of numpy and scipy work

16:48 Anderkent: pcn: it won't dissapear from enterprise even then

16:48 http://www.robg3d.com/?p=1175 etc.

16:49 gozala: dnolen: tbaldridge do you have little bit of time I have some questions in regards to core.async

16:50 pcn: Sure, but by the same token once you only have it in enterprises, it's dead.

16:50 tbaldridge: gozala: sure

16:50 rasmusto: :<

16:50 that's not true of humans, is it?

16:51 pcn: My recollection of being in big enterprises is that all learning stopped when I walked in the door

16:51 logic_prog: tbaldridge: if I want uber clojure debugging tools, do I want ritz or cider?

16:52 http://www.youtube.com/watch?v=sA5zOLCa3Xw <-- anyone know a link for this talk, where, starting at 11:25, the slides aren't suffering from parallax ?

16:53 tbaldridge: logic_prog: there really isn't a good debugger for clojure. You can use JVM debuggers if you want. Most people just get comfortable with smaller functions and the repl

16:53 not to mention that the Clojure compiler does some stuff that makes debugging with a debugger really hard. For example it clears locals after its done (so the data in the locals can be GC'd)

16:54 gozala: tbaldridge: I’m trying to wrap node IO libs for cljs

16:54 logic_prog: tbaldridge: so the notion of "when an exception happens, fire me up a repl (1) with access to local vars (2) lets me evaluate forms and (3) pick what value to return" is not part of stadard clojure workflow ?

16:54 gozala: and expose channel based APIs

16:54 logic_prog: tbaldridge: the compiler argument makes sense

16:54 tbaldridge: logic_prog: no, and I'm not even sure such a tool exists for clojure

16:54 gozala: tbaldridge: one thing that I çant figure out is what’s idiomatic way to report and handle errors

16:55 technomancy: getting access to locals is not that tricky if you set the point beforehand

16:55 https://github.com/technomancy/limit-break

16:55 gozala: tbaldridge: two options I considered were

16:55 tbaldridge: gozala: what I recommend is having a dedicated "error" channel. Report exceptions to that channel and have that channel log them or something.

16:55 technomancy: logic_prog: the difficult part is a stepping debugger

16:55 gozala: 1. Make apis that return records with output channel and error channel

16:56 sdegutis: technomancy: ffvii!!

16:56 gozala: 2. Make Error protocol an put them on the same result channel

16:56 sdegutis: <3

16:56 logic_prog: tbaldridge , technomancy: this makes sense, I can see how this is easy in "interpreted scheme" but hard in "clj compiled to java"

16:56 technomancy: sdegutis: necessarily

16:56 sdegutis: oh?

16:56 technomancy: logic_prog: the other thing is you have to be in pretty deep in the guts of some nasty stateful code to actually need a stepping debugger in clojure

16:57 due to referential transparency everywhere

16:57 logic_prog: technomancy: I can't belive limit-break is just 32 lines of code: https://github.com/technomancy/limit-break/blob/master/src/limit/break.clj

16:57 technomancy: logic_prog: it's pretty, errr... limited

16:57 Anderkent: badumtsss

16:57 danneu: I'm just faking it til I make it with my VPS. If I start a datomic-pro SQL transactor on a remote server, then my local peer connects to the jdbc connection with <remote-ip>:4334 (default port), right?

16:57 gozala: tbaldridge: ok the only inconvenience is that then I end up with ton of APIs that return two channels and on each read one needs to alt! between error and data

16:58 tbaldridge: I felt like it would be nice to have something built-in

16:58 technomancy: logic_prog: however, its simplicity makes it good for understanding what's really at the core of locals-inspection and possibly building something better from that, should anyone be so inclined

16:58 hint hint

16:58 logic_prog: technomancy: yeah, exactly why I'm reading it beacuse it's more instructional than production quality

16:59 gozala: tbaldridge: another question was on how would one communicate back

16:59 logic_prog: technomancy: is there a good nrepl tutorial somewhere where I can play with integrating limit-breka into repl-y, instead of only with stdin repl>

16:59 technomancy: sdegutis: dang now you got me listening to http://ff7.ocremix.org

16:59 Anderkent: logic_prog: reply can do standalone, i think?

16:59 technomancy: logic_prog: unfortunately afaik the details are scattered

17:00 beyond just the nrepl readme I mean

17:00 gozala: tbaldridge: what I mean is let’s say (fs/read path) returns a {:output (chan) :error (chan)}

17:00 tbaldridge: what if consumers want’s sot stop reading from output at some point

17:00 tbaldridge: Ideally file descriptor should be closed

17:01 tbaldridge: but how should one communicate intent that it’s done consuming channel

17:01 tbaldridge: I guess what I’m asking for is something like (take-while p c)

17:01 tbaldridge: gozala: the problem is that the person reading from the channel is very rarely able to do something about the error.

17:02 gozala: have you read Joe Armstrong's papers on this sort of thing

17:02 logic_prog: tbaldridge , technomancy : I am considering spening today + weekend studying ritz. Is there anything I should know before hand? (Or is this even a good investment of time -- are there known flaws with ritz?)

17:02 gozala: tbaldridge: I have not (do you have a link by a chance)

17:03 sdegutis: technomancy: dang now you got me listening to https://www.youtube.com/watch?v=LfB3aEOWAlk

17:03 gozala: tbaldridge: sure reared will rarely handle errors

17:03 tbaldridge: but in my frp lib for example I had an error type

17:03 technomancy: logic_prog: the main complaint is that it's difficult to set up and get working, and it's incompatible with cider. I haven't tried it myself.

17:04 tbaldridge: gozala: the first part of this paper is good: http://www.erlang.org/download/armstrong_thesis_2003.pdf

17:04 gozala: so values put on signal if they of error type would thread through high order functions

17:04 tbaldridge: it follows the actor model, but many of the ideas work well in core.async

17:04 gozala: and there were functions like catch that could be used to handle those casess

17:05 sdegutis: technomancy: True story, this is the playlist that runs 8+ hours a day for me: https://www.dropbox.com/s/zyf3814c2tey0oh/bahamut.png

17:05 * sdegutis is kinda nerdy

17:05 gozala: tbaldridge: I’ll take a look at the paper

17:05 technomancy: sdegutis: there is no shame

17:06 sdegutis: Also I designed that app. I think like 3 people know it exists.

17:06 gozala: tbaldridge: I think it would be good to have some examples with suggestions on how to handle this kind of stuff though

17:07 Raynes: I swear by pebble for wrist notifications, but I've gotta say, the notification load of this new job and bitemyapp's tweets is going to cause my arm to be perpetually vibrating.

17:09 gozala: tbaldridge: also how about the other question of letting reader communicate with writer that it’s done

17:10 tbaldridge: gozala: when its done it normally will just close the channel.

17:10 gozala: tbaldridge: so you mean reader should (close! input) ?

17:10 tbaldridge: is that observable for the writer ?

17:11 tbaldridge: so that it could close error channel and free up resources ?

17:11 teslanick: sdegutis: That's a handsome music player

17:11 sdegutis: teslanick: thx. src: https://github.com/sdegutis/bahamut

17:12 tbaldridge: gozala: yeah, if you're looking for resource type stuff, then yes, there probably needs to be a 2nd channel involved that the writer alts over. When the "shutdown" channel is closed it frees the resources and exits.

17:12 but it's hard to say without seeing a usecase

17:12 Notte: Would you help me with this function? http://hastebin.com/minuxibira.lisp It should return a lazy-seq of tuples

17:13 I don't get why i can't realize it even with doall or similar

17:13 gozala: tbaldridge: how would you implement (fs/read path) ?

17:13 tbaldridge: assuming that content maybe large and there for you would wanna stream it

17:14 tbaldridge: that’s basically what I’m trying

17:14 jstew: If I have a collection [[1 2] [3 4]], what's a nice way to split them by column so that they're [[1 3][2 4]]? My solution is ugly, and I know there's an elegant way.

17:14 alandipert: Notte: you can use the fact that map takes n colls and do something similar with (map vector colls...), eg

17:14 hyPiRion: jstew: (apply map list ...)

17:14 ,(apply map list [[1 2] [3 4]])

17:14 clojurebot: ((1 3) (2 4))

17:14 jstew: wow... very nice!

17:14 gozala: tbaldridge: I can put my current code somewhere if you want to take a look

17:14 hyPiRion: eventually (apply mapv vector ...) if you want them on vector form

17:15 jstew: clojure is so elegant. My solutions thus far haven't been as sexy as they can be. Thanks :)

17:16 Notte: alandipert: i thought about it, but i don't want pair like (a a), (b b)

17:16 also i really want to understand what i'm doing wrong

17:16 alandipert: Notte: what's an example desired in/out?

17:16 hyPiRion: jstew: It comes with experience, it's hard at first if you've used imperative languages earlier :)

17:17 Notte: alandipert: (tuples [1 2 3]) ; -> [[1 2] [1 3] [2 3]]

17:17 jstew: It's starting to click. I can write clojure, just not "good" clojure yet.

17:17 Glenjamin: gozala: the node streams api is pretty well formed and offers approaches for most of the problems you just mentioned

17:18 Notte: jstew: what docs are you using?

17:18 Glenjamin: i'm not sure channels alone are rich enough to be streams in the node sense

17:19 jstew: hyPiRion: Could you be so kind as to explain how that works? map list makes a list out of hte vector, but apply will do what in that context? I thought apply just sort of flattens a list so that it can be used as args?

17:19 Glenjamin: jstew: yup, it's like * in ruby or ptthon

17:20 jstew: Notte: docs for what?

17:20 Notte: jstew: to learn clojure

17:20 Anderkent: jstew: apply turns it into (map list [1 2] [3 4]). Map then takes the first element from each list, applies list to it (giving (1 3)), then does it again

17:20 Notte: i can't find much online, compared to other languages

17:20 jstew: Notte, 4clojure.org, clojure for the brave and true, and google code jam

17:20 hyPiRion: jstew: (apply map list [[1 2] [3 4]]) is just like (map list [1 2] [3 4]). Since map allow a variadic amount of lists, it works

17:21 jstew: Got it! Thank you both, Anderkent and hyPiRion. you;ve been helpful

17:21 Glenjamin: Notte / jstew http://aphyr.com/tags/Clojure-from-the-ground-up is good also

17:21 technomancy: (inc aphyr)

17:21 lazybot: ⇒ 1

17:21 technomancy: ...!

17:22 I guess he's not on IRC much, but styll

17:22 still

17:22 Glenjamin: i suspect lazybot needs some spit/slurp

17:22 hyPiRion: (inc aphyr)

17:22 lazybot: ⇒ 2

17:22 hyPiRion: $seen aphyr

17:22 lazybot: aphyr was last seen talking on #riemann 2 hours and 25 minutes ago.

17:22 jstew: technomancy: your nick looks familiar for some reason. Were you a rubyist in the past?

17:23 technomancy: jstew: hush not so loud

17:23 jstew: hah, knew it. :)

17:23 insamniac: It looked familiar to me when I got here, but then I realized it was because of github.

17:23 Notte: Glenjamin: thanks

17:24 rasmusto: technomancy += 1

17:24 Glenjamin: mutable state!

17:24 technomancy: http://thisotplife.tumblr.com/post/63360807823/mutable-data-structures

17:27 Anderkent: OTP?

17:27 Open Telecom Platform? Seems weirdly specific

17:28 ro_st: dnolen: howdy

17:28 technomancy: the reference implementation of erlang is often called OTP

17:28 Anderkent: right. Didn't realize it's all about erlang

17:29 I guess that'll join security reactions and plt life in my rss reader..

17:30 ro_st: what does the t in PLT stand for?

17:31 Anderkent: you know I thought it was theory, but now I figure itmight be a reference to racket?

17:33 gozala: Glenjamin: node streams are like set of channels

17:33 and they are far from ideal

17:33 not to mention there’s no syntax support

17:33 hyPiRion: ro_st: theory, theorists

17:33 gozala: that’s why I’m trying to wrap them in core.async flavoured API

17:34 ro_st: aha

17:34 Glenjamin: gozala: i think it's worth exploring, but you'll need quite a few channels

17:34 streams form a pipeline, to handle backpressure correctly - they're actually more similar to Seqs than core.async i would say

17:35 gozala: Glenjamin: Not necessarily there are two approaches

17:35 one is more haskelly where you deal with different messages types with actual types

17:35 or you use multiple channels

17:36 I’ve done implementation of both approaches in js in a past

17:36 and kind of prefer former

17:36 ro_st: http://this-plt-life.tumblr.com/post/36425247242/when-i-hear-of-a-lisp-success-in-industry this one

17:36 Glenjamin: in node nowadays it tends to be more common to define things as streams, and use pipe()

17:36 gozala: but I’m not sure how well it maps to core.async

17:36 Glenjamin: i'm unsure which of those categories it fits into

17:37 gozala: Glenjamin: none, they basically have one channel in form of event emitter

17:37 and event types serve as a channel / message type

17:37 Glenjamin: the client-side examples i've seen from rich have been to attach a single channel to one event listener

17:37 but i can see how one channel would be simpler

17:38 gozala: Glenjamin: I also think core.async has a lot more saner approach to IO coordination than node’s hard coded backpressuer

17:38 Glenjamin: do channels do backpressure?

17:38 gozala: channel is sync point

17:39 you can’t write until other end reads

17:39 and you can make buffered channels

17:39 Glenjamin: right, yes

17:39 gozala: that would allow to buffer

17:39 Glenjamin: so you probably want to work with the .on('readable') api

17:39 can a channel be closed?

17:39 gozala: Glenjamin: yes

17:40 Glenjamin: then that fits a single channel pretty well, and you just have to deal with errors - i think i've caught up with where you started?

17:40 can you make a channel throw?

17:40 gozala: tbaldridge so here is a code I’ve being working on https://github.com/Gozala/clojurescript.node/blob/master/src/node/fs.cljs#L149

17:40 mmitchel_: technomancy: For :repositories setting in project.clj -- Is there a way to provide a password for each :repository from the environment?

17:41 gozala: Glenjamin: you don’t throw, but you can make (Errro. message)

17:41 technomancy: mmitchel_: yeah, check out `lein help deploying` under "credentials in the environment"

17:42 gozala: and reader can (if (error? message) (handle error) (do-something message))

17:42 mmitchel_: technomancy: excellent thanks!

17:42 gozala: tbaldridge: in this implementation I box errors in error type

17:43 rather than implying second channel for errors

17:43 Initially I tried using two channels instead but felt a lot more hassle

17:44 tbaldridge: so net module actually uses two channel approach

17:45 but as you can see from example on readme https://github.com/Gozala/clojurescript.node#examples

17:45 API tends to become a lot more complex that way

17:46 that’s why I’m leaning towards elm like approach of using types to distinguish data & errors

17:47 but then map, filter and all high orders functions would ideally pass through errors otherwise user will need to do it manually

17:48 tbaldridge: another thing is that consumer is forced to handle errors since it’s on the same channel

17:49 while with two channel approach it felt like it’s easy to forget you to even handle error channel

17:49 tbaldridge: does any of my reasoning makes sense to you ?

17:53 tbaldridge: gozala: so this is a rare example where I'm going to recommend something I don't normally recommend.

17:54 1) box errors and then write a macro that I prefer to call <?, this will create a take and if the value is a boxed error, then re-throw it.

17:55 gozala: tbaldridge: but don’t you think there should be something alike in core.async itself ?

17:55 I feel like it’s not very exotic use case

17:56 most of node APIs will have a same concerns

17:56 tbaldridge: what you suggest actually is very similar to what Task.js does

17:56 tbaldridge: http://taskjs.org/

17:57 tbaldridge: 2) if you use the latest version of core.async >! now returns falsey if the put happens on a closed channel.

17:57 So with that you can easily write a with-open macro that calls close! when control escapes the current block.

17:58 That will allow the file reader to detect that the channel is closed and free up resources.

17:58 gozala: tbaldridge: but that means producer will have to waste one read until it knows no writes are possible

17:58 ideally it would happen prior to that

17:59 tbaldridge: also ideally producer will still confirm close

17:59 since there still maybe an error on attempt to free resources

17:59 tbaldridge: gozala: why do you need to confirm freeing of resources?

18:00 what are you going to do if freeing fails?

18:00 Anderkent: that seems excessive. IF there might be an error, the producer should handle it

18:00 otherwise it's something you cant handle, so why tell the consumer

18:00 tbaldridge: (inc Anderkent)

18:00 lazybot: ⇒ 5

18:01 gozala: tbaldridge: Anderkent I see your point, but freeing up resources may take a time

18:01 so I feel like it’s awkward to pretend that it’s already closed

18:02 that being said I don’t think it’s a big deal in my case so I can ignore it until I have a better use case

18:03 tbaldridge: Anderkent don’t you think suggested <? should just be a !<

18:04 although to be honest I prefer handling cases via cond rather than catch

18:04 tbaldridge: gozala: that's an entire other argument, lol

18:05 see arguments over Go's error handling (or lack of it)

18:05 gozala: specially since error propagation is not that useful with async code

18:05 Anderkent: I do like cond over catch, but also prefer silent error propagation. I.e. monads!

18:05 tbaldridge: gozala: true, so it's not a bad idea to just box everything into a hashmap and then do cond on it.

18:05 Glenjamin: the node core has a "if you subscribe to error you can have it, if you don't then i'll throw" - is there a parallel to be drawn here?

18:06 gozala: Anderkent: tbaldridge that’s what I’m suggesting though

18:06 tbaldridge: {:op :more-data :value "4444"}

18:06 gozala: if high order functions would just propagate errors

18:07 Glenjamin: node has domains, and please don’t get me started on them

18:07 tbaldridge: gozala: well there's another argument to be made here. Let's say I have a chain of (-> read-file map filter map output-data)

18:07 Glenjamin: domains are awful

18:07 tbaldridge: each of those being a go block doing some processing

18:07 Glenjamin: even the core devs agree

18:08 tbaldridge: gozala: some would say that an error in any of those should cause read-file to close it's channel, map filter, etc then all close, propagating the close. Then report the error to a single reporting channel.

18:09 gozala: tbaldridge: I think it’s more reasonable to have another control structure to handle that

18:09 tbaldridge: So output-data alts on the error channel and the response. If the response channel closes without sending a response the error channel is read and that generates a 500, or something like that

18:09 gozala: (-> read catch map filter map …)

18:09 or (-> read map filter map catch)

18:10 that way user can decided where to handle errors and how

18:10 tbaldridge: gozala: this follows the erlang pattern of "let it die". When things error out you crash the entire request/response chain and report the error to a central channel.

18:10 gozala: that how most reactive libs deal with that

18:11 tbaldridge: now that I think about it’s fine

18:11 it’s actually the same

18:11 as long as you have something like catch control structure to deal with recovery

18:12 tbaldridge: so only diff is weather channel should be closed on errors or not

18:13 I’d be fine with either option

18:14 Glenjamin: i don't think you should be taking data off a stream that has errored, so i would vote for closed

18:15 gozala: tbaldridge: Anderkent so are there any chances to incorporate something like this into core.async ?

18:16 tbaldridge: like what?

18:18 gozala: tbaldridge: like incorporate some error support

18:18 catch style control structure

18:18 and special handling of errors

18:18 which can abort tasks and report errors as you suggested

18:19 ms rx has such catch like control structure

18:20 tbaldridge: the problem is, this use case doesn't really fit well with how core.async is normally used. The idea behind core.async is to turn deep call stacks into linear data flows. This sort of error propagation doesn't really fit with that model.

18:20 the adaption of node.js to core.async is a very interesting use case, but I'm not convinced what we've come up with here is the best solution.

18:21 The better route is something were we can add monitoring of go blocks. Erlang does this via supervisor trees, where you can say "if this block dies, kill me" or "if this block dies, let me know".

18:21 gozala: tbaldridge: to me core.async is lower layer to reactive programming like ms rx

18:22 tbaldridge: That allows you to turn your entire HTTP request/response chain into a single dataflow that will crash/cleanup if a single error occurs, which is exactly what you want most of the time.

18:23 gozala: tbaldridge: that’s fine too

18:23 but some way to communicate errors is necessary, is kind of my point

18:23 tbaldridge: at the moment if producer has an error there’s nothing in core.async to support that

18:24 tbaldridge: gozala: sure there is, the producer sends an error to a channel. build whatever you want on top of that.

18:25 It's a design decision for the library to not go any further than that. We don't want to dictate how errors should be handled.

18:25 gozala: tbaldridge: ok

18:26 tbaldridge: only issue with that is built in control structures won’t do anything on errors

18:27 so libraries will have to build their own control structures to support errors

18:27 which may be ok too

18:28 tbaldridge: for example generators in JS sort of solve the same problems as core.async

18:28 buth they allow user to throw in exceptions

18:29 I kind feel this is what missing

18:29 tbaldridge: If I were building a node.js interface, I would probably sit and think for about a month on how I might want to handle exceptions. Should they be handled, by whom? Why do we need to handle exceptions, etc. When code starts to get ugly, I like to go back and re-think my assumptions. If the code doesn't "feel right" perhaps I'm wrapping the API in the wrong way.

18:30 Glenjamin: i always thought that core.async was to solve the problem of decoupling bits of your application, and the callback soup was a handy side benefit

18:30 the problem with reading from a stream is that you are actually somewhat coupled to the stream's state

18:30 gozala: tbaldridge: I have being thinking about it for 2 years now :P

18:31 tbaldridge: Glenjamin: agreed

18:31 gozala: started with https://github.com/Gozala/streamer

18:31 then moved to https://github.com/Gozala/streduce

18:31 Glenjamin: this is why Node.js has "evolved" a whole new set of libraries and abstractions around streams, separate from callbacks - it's still young and experimental

18:31 gozala: and then to https://github.com/Gozala/elmjs

18:31 Glenjamin: but there's people playing with lots of approaches

18:32 gozala: plus explored all the other reactive things that came up like ms rx, elm

18:32 dnolen: gozala: generators are even more low level than core.async, and you can throw exceptions in core.async too.

18:32 gozala: dnolen: how can producer of channel communicate error with a consumer ?

18:33 dnolen: gozala: many ways exactly the same as generators

18:33 gozala: dnolen: I agree generators are more low level

18:33 dnolen: gozala: generators don't dictate anything

18:33 gozala: dnolen: generators have g.next and g.throw

18:33 later throws in exception into routine

18:34 how one can throw in exception into go routine ?

18:34 dnolen: gozala: yes really low level, you gotta do something different if you want to use promises + generators, or channels + generators

18:34 Glenjamin: gozala: are you familar with caolan as in caolan/async?

18:35 gozala: dnolen: I really just want a channels, but with some error reporting support from the data producer side

18:35 dnolen: gozala: as people have already said, dictating something is pretty unwise given differing needs for different applications

18:35 gozala: there are some adhok ways

18:36 dnolen: gozala: I've done error channels stuff and supervisor stuff, both are appropriate sometimes

18:36 gozala: dnolen: maybe seeing those examples would help

18:36 dnolen: gozala: or try it yourself :)

18:37 gozala: dnolen: also adding some error reporting support does not prevents supervisor stuff I think

18:37 dnolen: I did that, that’s why I’m trying to get more input from people like you :P

18:39 ok I guess I’ll try to finish version with boxed errors on a channel & we’ll see from there

18:39 Glenjamin: yeas I’m aware of async not a fan

18:39 tbaldrid_: gozala: also remember that core.async channels are multi writer, unlike rx which is (for the most part) single writer

18:40 gozala: tbaldridge: although you can mix multiple channels in rx so it’s really just defaults

18:40 tbaldridge: Imagine your surprise if you have two producers writing to a single map channel. One producer errors, and sends an error to map. Map then passes the error on and exits.

18:41 Now the 2nd producer tries to write but the other end is dead.

18:41 Glenjamin: gozala: well caolan has been working on trying to implement decent map/filter/reduce type functions for node streams lately, and strugging with these same issues

18:41 bbloom: tbaldridge: the Rx source is available & i looked at it closely. i was like "holy crap. so much error propagation logic!"

18:41 Glenjamin: i wasn't suggesting async.js was helpful for this problem :)

18:41 gozala: tbaldridge: tbaldridge other end maybe dead either way though no ?

18:42 if consumer closed it’s end it’s kind of dead

18:42 bbloom: tbaldridge: Rx existed prior to async was in C# too, so there's tons of manual state machines. it's pretty horrific in hindsight

18:42 egghead: dnolen: ping

18:42 dnolen: egghead: saw your question earlier, only associative data structures in the app state for Om

18:42 gozala: Glenjamin: https://github.com/Gozala/reducers are monadic

18:42 and they do work with node streams

18:43 if you import https://github.com/Gozala/streduce

18:43 egghead: dnolen: ya I didn't know that '() wasn't associative but [] was, I figured because you could *nth* on both of them

18:43 tbaldridge: gozala: actually, the core.async code in master is written to shutdown when the channel the writer is producing to is closed. So closing channels the the "idiomatic" way to terminate processes in core.async.

18:43 gozala: Glenjamin: all of the back pressure etc is preserved

18:43 egghead: om is awesome but I was so frustrated last night trying to figure out why om was saying my data wasn't a valid cursor :p

18:44 dnolen: egghead: i've documented this restriction in several places

18:44 egghead: my fault then

18:44 gozala: tbaldridge: sorry I did not quite got the last comment

18:44 you mean idiomatic way to close channel is from producer side you mean ?

18:46 egghead: dnolen: I see it now here: https://github.com/swannodette/om/wiki/Documentation#wiki-root -- I was just unaware that for example the result of 'map' isnt something that is associative

18:46 or the result of a for comprehension or something similar

18:46 dnolen: egghead: Clojure documentation says they return lazy seqs

18:47 tbaldridge: gozala: in the code in master, it's idiomatic to do it from either side. Both sides should be watching for the channel to close, and shutdown when it happens.

18:47 dnolen: egghead: other people have encountered this before, but there's not much I can do about it. I wan't to enforce associative data structures for future perf reasons.

18:49 dsrx: ,(doc bean)

18:49 clojurebot: "([x]); Takes a Java object and returns a read-only implementation of the map abstraction based upon its JavaBean properties."

18:49 egghead: dnolen: I'm not against the restriction, maybe the docs could be more explicit and say 'For practical purposes this means you can only use vectors and maps, but not lists or lazy seqs'

18:49 dnolen: egghead: sure can do that.

18:49 gozala: tbaldridge: is core.reactive is a thing ? maybe core.async is too low level for what I’m trying to do

18:50 tbaldridge: Asking because I noticed your repo

18:51 tbaldridge: gozala: oh, that repo is super old.

18:51 it predates core.async by a few years.

18:52 gozala: as to my point, onto-chan is a producer that shuts down when the channel closes: https://github.com/clojure/core.async/blob/master/src/main/clojure/clojure/core/async.clj#L615

18:52 dsrx: ,(instance? clojure.lang.Associative (map identity [1]))

18:52 clojurebot: false

18:53 egghead: dsrx: obvious when you know it :p

18:54 rasmusto: dsrx: ##(associative? (map identity [1]))

18:54 lazybot: ⇒ false

18:57 Glenjamin: is there a better way to get it back into a vector than just calling (vec) on the Seq?

18:57 rasmusto: ##(associative? (mapv identity [1]))

18:57 lazybot: ⇒ true

18:58 Glenjamin: aha

18:59 rasmusto: Glenjamin: assuming you're doing a map

18:59 Glenjamin: mm

18:59 found the related variants

19:00 rasmusto: is there one for hash-maps?

19:00 Glenjamin: (mapv identity {:a :b})

19:00 ,(mapv identity {:a :b})

19:00 clojurebot: [[:a :b]]

19:02 rasmusto: ,(let [a {:a :b}] (into (empty a) (map identity a)))

19:02 clojurebot: {:a :b}

19:02 Glenjamin: (into {} (map identity {:a :b :c :d}))

19:02 ,(into {} (map identity {:a :b :c :d}))

19:02 clojurebot: {:a :b, :c :d}

19:02 rasmusto: Glenjamin: hi5

19:02 Glenjamin: o/

19:04 which is basically what mapv does \o/ https://github.com/clojure/clojure/blob/c6756a8bab137128c8119add29a25b0a88509900/src/clj/clojure/core.clj#L6232

19:05 rasmusto: mine gives you back the same coll type that you started with, which might be useful? Maybe mapv is moreso because you know what you're getting out

19:05 Glenjamin: mapmap would be a rubbish name, i guess

19:05 rasmusto: mashmap

19:06 technomancy: mapmap would be a great name

19:06 rasmusto: yeah, map vs hash-map is a hard thing to explain

19:06 Glenjamin: add it to core! that's easy to do, right?

19:06 rasmusto: mapmap is a good name, assuming you're OK with map as a coll name

19:06 technomancy: in mapmap it's at least clear you mean both meanings =)

19:06 rasmusto: true

19:06 but in which order?

19:07 dsrx: oh i know, call it collectmap[

19:07 :p

19:07 rasmusto: mapm, alternatively maph

19:08 maph.numeric-tower

19:08 Glenjamin: i guess it's too late to rename Map to Dict :p

19:09 bbloom: Glenjamin: heh, i've had that thought too, but for some reason "dict" implies to me that the keys are strings

19:09 *shrug* dunno why

19:09 Glenjamin: ah, i can see that

19:09 technomancy: "Dictionary" is too many syllables

19:10 bbloom: technomancy: that's why python people just call them "dicts"

19:10 technomancy: "Dict" invites too many jr. high jokes

19:10 Glenjamin: Mapping perhaps?

19:10 bbloom: factor calls a map an "assoc"

19:11 but i've found that awkward to say, since my brain reads "assoc" as a verb

19:11 rasmusto: (assoc (dict :a 1))

19:11 bbloom: association vs associate

19:11 btcNeverSleeps: Hey all... I've got a question regarding the kinda "long" stacktrace, and this question and its answer: http://stackoverflow.com/questions/14297079/ ("Why are Clojure stacktraces so long?")

19:12 Glenjamin: i blame the map function

19:12 i suppose they both do the same thing, so that's the main issue

19:12 btcNeverSleeps: Isn't the way the Clojure code (and Clojure Java code) decided not to use many checked exception a major reason for the long stacktraces?

19:13 (btw this isn't a criticism of runtime exceptions: I'm just asking if "doing without checked exception" is, or not, a big reason for long stacktraces)

19:13 bbloom: btcNeverSleeps: whether or not exceptions are checked has nothing (theoretically) to do with the length of a stack trace

19:13 Anderkent: btcNeverSleeps: not really. it's just that because of its dynamicity (ww?) the stacks are necessarily deep

19:14 bbloom: however, in practice, checked exceptions tend to cause a lot of re-throwing and exception swallowing, both of which will shorten visible stack traces, but are generally a bad idea

19:14 Anderkent: and recursion doesnt help either

19:14 bbloom: eh, they just separate the stack trace into X (20 lines) caused by Y (40 lines) cause dby ...

19:14 unless you eat the cause in which case you're evil

19:14 bbloom: Anderkent: indeed

19:15 btcNeverSleeps: (semi-related): when you code in Clojure (on the JVM), are there any checked exceptions that can happen and that you'd then be forced to catch?

19:16 bbloom: btcNeverSleeps: no. checked exceptions are an illusion of the java compiler. they are not a JVM byte code feature

19:16 btcNeverSleeps: and what happens in Clojure if I do Java interop and use a Java method that, in a .java, would refuse to compile if I didn't catch the exception?

19:17 bbloom: btcNeverSleeps: only the java compiler checks exceptions. neither the JVM nor the clojure compiler checks exceptions.

19:18 btcNeverSleeps: so if the checked exception is thrown, I end up with a checked exception manifesting itself as a runtime exception?

19:19 bbloom: btcNeverSleeps: if by "manifest" you mean "be raised at runtime" then yes. if you mean "magically becoming a subclass of the RuntimeException class" then no

19:21 socksy: not exactly a clojure question, but does anyone know how to speed up infoq videos? Rich Hickey can talk quite slowly

19:21 bbloom: socksy: use the extra time between words to reflect on what he's saying :-)

19:22 rich isn't some awful professor whose class you skip and watch later at 2X speed just to make sure you know what's going to be on the test

19:23 every one of his talks are worth the time to watch and then some

19:23 socksy: I have the attention span of a gnat, and inevitably my mind starts to wonder and I end up having to rewind and watch the same sentence again and again. I don't get that when the video is sped up :)

19:24 *wander

19:24 bbloom: heh.... ok

19:24 technomancy: socksy: you can download infoq videos if you change your browser user-agent

19:24 bbloom: does it wonder to things related to what he's talking about?

19:25 if your wandering mind is at least somewhat on topic, that's probably fine to rewind a bunch :-)

19:25 socksy: I'm not sure...

19:25 technomancy: useful info, thanks

19:26 btcNeverSleeps: ,(.getBytes "a" "non-existing-encoding")

19:26 clojurebot: #<SecurityException java.lang.SecurityException: denied>

19:29 ivan: socksy: there are three infoq downloaders, but none can put the slides next to the video

19:29 one can replace the video with the slides

19:29 https://github.com/cykl/infoqscraper https://github.com/mtayseer/infoq-downloader https://github.com/rg3/youtube-dl

19:37 steckerhalter: any idea why reading a file with (slurp "file.txt" :encoding "UTF-8") that contains one 4-byte utf-8 character prints a string with 4 characters?

19:40 alxlit: ivan: infoqscraper can, get it from master

19:41 ivan: steckerhalter: maybe you've got a double-encoded UTF-8 file?

19:42 alxlit: ivan: infoqscraper presentation download --type h246_overlay or something like that

19:43 steckerhalter: ivan: not sure what double encoded means, but I created the file myself containg just that utf-8 character in 4 bytes

19:44 ivan: steckerhalter: does ls -l confirm that it's 4 (or 5) bytes?

19:44 steckerhalter: ivan: yes, 4

19:44 ivan: alxlit: thanks. will try after I figure out the python 2/3 mess within

19:45 steckerhalter: xxd -b file >>> 0000000: 11110101 10100111 10111101 10110101 ....

19:46 maybe it just can't deal with 4 bytes or something?

19:49 ok, hmm... emacs displays one character, gedit says it's invald

19:49 õ§½µ

19:50 ivan: Python says

19:50 UnicodeDecodeError: 'utf8' codec can't decode byte 0xf5 in position 0: invalid start byte

19:54 steckerhalter: well, that is 0xf5 should be valid looking at https://en.wikipedia.org/wiki/UTF-8

19:55 s/that is//

19:58 ivan: steckerhalter: that table refers to some obsolete original design

19:58 steckerhalter: ivan: yeah, it could be the restriction kicking in

19:59 AeroNotix: what can I do if I want to run a test suite with profiling enable?

19:59 enabled*

19:59 is there a plugin with lein test?

19:59 Anderkent: AeroNotix: what kind of profiling?

19:59 timbre?

20:00 AeroNotix: Anderkent: memory, cpu, call tracing

20:00 Anderkent: never used timbre

20:00 Anderkent: oh, some jvm agent?

20:00 AeroNotix: jvm agent?

20:01 Anderkent: well, what are you going to use to profile it

20:01 there's jvm profilers like yourkit etc

20:01 AeroNotix: ok

20:01 Anderkent: these work by attaching an agent ot the jvm, they will tell you what options to add to a process

20:01 then you just pass these to :jvm-opts in lein

20:01 AeroNotix: gotcha, ok

20:01 Anderkent: or alternatively oyu can use a native clojure profiling lib like timbre

20:02 AeroNotix: Thanks for the info

20:02 Anderkent: that works by wrapping your code

20:02 no worries :)

20:02 AeroNotix: timbre looks like it can do individual form profiling, which is cool

20:02 steckerhalter: ivan: ok, got it, it's out of bounds after RFC 3629. thanks

20:04 Anderkent: steckerhalter: yeah it says 'octet values c0 c1 f5 to ff never appear'. I wonder what purpose that has

20:06 steckerhalter: Anderkent: the limitation?

20:33 akurilin: Is it generally a poor idea to cache data on (def) calls because of the potentially varying order in which this can happen?

20:34 e.g. I have a very static table in the db which I want to cache into a var on my app's boot. Doing it in a def seems potentially risky.

20:35 Or I guess not necessarily. Should I consider exporting this to some kind of "init function"?

20:44 Morgawr: how would I test if a vector contains an element?

20:45 I could write my own function with empty? and filter but there probably is a function that does that...?

20:46 arrdem: what SQL layer(s) are people using?

20:46 all I'm really finding is korman and java.jdbc..

20:48 akurilin: I'm using both. Korma for the boring crud or any time I need to translate something procedurally to a query, and cjj for complex queries.

20:55 dee5: What's the normal way of running a leiningen task in the background?

20:58 hiredman: don't?

20:58 dee5: :(

20:59 hiredman: if you want to run some lein uberjar up an uberjar and run that

20:59 something

20:59 dee5: Alright thanks

21:16 x^2: im reading through the O'Reilly clojure book

21:16 and i understand a lot of the syntax of this now

21:16 but im just tryingg to better understand

21:16 does Clojure completely abandon the idea of anything object/struct like, and instead carry on through functions passing data to other functions?

21:16 or can anyone give me some insight on this

21:16 i am kind of reading through, and i understand how to do basic things

21:17 but i dont feel like i "get" the big picture on this yet

21:17 maybe someone here can shed some light on that

21:19 dnolen: x^2: there are object/struct like things in the language - but it's common to encourage people to not reach for them unless they really need it.

21:20 hiredman: dnolen: maps are used all the time

21:20 x^2: it depends what you mean by object/struct

21:21 x^2: i mean like

21:21 hiredman: generally clojure code tends to pass around values (immutable data) and call functions on them

21:21 er

21:21 x^2: enclosure of data basically

21:21 hiredman: call functions with them as the arguments

21:21 x^2: i know about vectors and stuff

21:21 like

21:22 i feel i can write some very basic things right now

21:22 but i want to make them in the clojure way

21:22 hiredman: yeah, so vectors and maps and seqs and functions

21:22 that is how you do it

21:22 x^2: i dont want to be writing java or C++ using clojure if you know what i mean.

21:22 okay

21:22 this seems like a really wonderful language

21:22 i get bored reading about ones that are so similar

21:22 but all of these new ideas have me really excited

21:23 i am just trying to think of something now i could write to put the ideas of clojure to good use

21:23 Morgawr: try writing a LightTable plugin :P

21:23 it's fun

21:23 and not that hard

21:23 x^2: im not sure what that is, and ive only written a couple very basic programs before. so i might want to start at something above a 'hello world'

21:23 but not much above

21:23 lol

21:23 Morgawr: https://github.com/mdhaney/lt-plugin-template <-- a template for LT plugins

21:24 LightTable is an editor written in Clojure (for clojure and other languages)

21:24 but yeah, just get familiarized with the language, I guess a plugin might be too complex

21:24 x^2: ooo

21:24 yeah for now i think

21:24 dnolen: Morgawr: well ClojureScript :)

21:24 Morgawr: it's a pretty neat editor, really extensible, I'm loving it

21:24 x^2: i am developing using lein- do you think this is a good idea?

21:24 teslanick: I spent a few weeks banging around in LightTable just to get acquainted with the language.

21:24 Morgawr: dnolen: well, still Clojure :P

21:24 teslanick: Lein is definitely the thing for development in clojure.

21:25 x^2: alright well im off to a start then lol

21:26 also - i have one question of logistics, i guess

21:26 in my lein project directory

21:26 or rather

21:27 let me start over: i have a directory called "hello" for a basic hello world project

21:27 and in the /src folder, i have:

21:27 i have a "hello" folder, with core.clj

21:27 that reads:

21:28 (ns hello.core (:gen-class))

21:28 (defn greet[who] (println (str "Hello " who "!")))

21:28 (defn -main[who] (greet who))

21:28 so obviously in this core.clj, i have one regular function and my main functio

21:28 n

21:28 how do people usually lay these things out in lein?

21:28 like would someone put a bunch of other functions and main in the core.clj?

21:28 or would they usually split it up into different files

21:29 teslanick: A file contains one (or sometimes more) namespaces. But a file contains the same namespace as the file name.

21:29 s4muel: Like that. Look at project.clj you'll see a :main entry. Usually you split up files by namespace, like example if you have a client server app you'd have (ns foo.client) and (ns foo.server) in src/client.clj and src/server.clj

21:29 teslanick: So really you'd be dividing functions up across namespaces related to what they do.

21:30 By way of example, Clojure has clojure.core, clojure.string, clojure.zip, clojure.pprint, etc.

21:31 Where core has most of the common functionality, and each of the others have functions specialized to a particular task (strings, tree structures, and pretty-printing respectively)

21:32 s4muel: Indeedy. There's nothing preventing you from throwing it all in one giant file, either, per se. It is just a matter of style and organization. Take a look at some of the more popular libs to see how they are organized (or as teslanick points out, clojure itself)

21:32 x^2: YEhmmm, okay

21:32 i was going to do that, look at some of what is out there

21:33 teslanick: A lot of the popular libs are relatively easy to read; as you may have noticed, Clojure is very terse.

21:33 s4muel: Of course, file paths do come into play when you start adding test frameworks and working more with leiningen in terms of advanced build/compilation stuff. Depends, again, on what you're using.

21:34 x^2: yeah, that is all very confusing to me right now

21:34 now i would like to ask

21:34 for a beginning 'first' project, would it be okay to put everything (inluding main) in that core.clj and just work off of that?

21:35 for a relatively small project, of course

21:35 with just a few functions most likely

21:35 teslanick: Yeah. You can break it up into namespaces later if it grows.

21:35 x^2: okay, cool

21:35 teslanick: I've been writing stuff in little clj files scattered across my desktop and copy them into my project when I think they're done.

21:36 x^2: so you just write them in separate clj files, put them in the same directory, and build?

21:36 (simplifying, of course)

21:39 teslanick: Well, I write a bunch of related functions and test them together, then copy the file into the project and give it a namespace.

21:39 Because LightTable doesn't care about projects, you can just live-eval stuff as you're working to build things incrementally. The amount of boilerplate necessary is basically nil

21:40 x^2: hmm, okay.

21:40 i do really like the REPL environment, too

21:40 it seems very cool.

21:45 teslanick: I should say that I'm very much a Clojure neophyte myself

21:46 The REPL is pretty neat, though the thing that gets me is connecting to a running application and manipulating its state as its operating.

21:48 x^2: i've heard you can do that

21:48 i have no idea how yet

21:48 but i have seen that as a feature of clojure

21:48 which amazes me

21:48 it must tie back to the 'code as data' idea, right?

21:49 in that you can just feed some 'data' (being code) into an application, and it is evaluated like anything else.

21:49 teslanick: Also that mutable state is called out very explicitly.

21:49 x^2: oo

21:50 teslanick: And altering stateless components is relatively safe.

21:50 arrdem: if I wanted a doseq with a carry-forwards state that's for, right?

21:50 sorry. loop/recur

22:02 gfredericks: arrdem: I have no idea what that means

22:03 arrdem: gfredericks: I was refactoring a doseq and realized that I really wanted an eager reduce, which is just for with some destructuring.

22:03 gfredericks: that was as much me muttering to myself as anything :/

22:03 mklappstuhl: curious how the parsing of namespaced function calls like (string/split ...) works in clojure

22:04 hiredman: parsing?

22:04 mklappstuhl: is the parse looking for a slash and than splitting the string?

22:04 arrdem: mklappstuhl: fully qualified symbols are written ns.sub-ns.sub-sub-ns/symbol

22:04 hiredman: oh, how symbols are read?

22:04 mklappstuhl: hiredman: sorry — reading is probably more appropriate

22:05 ah

22:05 quizdr: this just blew my mind: #(reduce deliver f %&)

22:06 mklappstuhl: so basically if you use :require [clojure.string :as str] it basically maps str to clojure.str

22:06 hiredman: that has nothing to do with reading though

22:07 at read time foo/bar is just a symbol with namespace slot foo and a name slot bar

22:07 gfredericks: quizdr: what on earth is that useful for

22:07 hiredman: same with str/foo

22:07 ,(read-string "str/foo")

22:07 clojurebot: str/foo

22:07 gfredericks: ,(read-string "doesn't/exist")

22:07 clojurebot: doesn't/exist

22:07 quizdr: gfredericks it was amalloy's answer to a problem on 4clojure; I think pretty crafty. more elegant.

22:08 x^2: ,(read-string "testfunc")

22:08 clojurebot: testfunc

22:08 teslanick: quizdr: What was the problem?

22:08 gfredericks: quizdr: ooh he must be taking advantage of the impl

22:08 mklappstuhl: hiredman: I guess my terminology was wrong

22:08 quizdr: impl? what do you mean?

22:08 gfredericks: deliver is supposed to be for promises but functions as a generic call function

22:08 ,(deliver inc 42)

22:08 clojurebot: 43

22:09 gfredericks: ^ not what deliver is for

22:09 quizdr: oh i see.

22:09 gfredericks: there'd be no reason to even suspect it would do that without reading the source

22:09 which is what I meant by "impl"

22:09 quizdr: the doc mentions it as "alpha" anyway and "subject to change" so probably not a good idea to depend on it as habit

22:09 "impl" = "implementation" ?

22:09 gfredericks: no not for use in production 4clojure

22:09 yes

22:10 quizdr: it's amazing to see the paradigm shift among programmers on that site when reviewing others' answers. so many still use loop/recur with a single line alternative does the trick with 25% as much code. fascinating.

22:10 *when a single line alternative...

22:11 my main take away from those execersizes is that the vast majority of the time, when I approach a problem with a loop in mind, strong liklihood there is a more elegant way instead.

22:11 gfredericks: yep

22:14 bbloom: quizdr: i frequently write loops then look at them and say "now what does that actually do?" before refactoring it

22:14 sometimes, i know the algorithm & don't need laziness, but don't know what it is called until i *see* it

22:15 mklappstuhl: I'd love to see a blog that features small overly complex code snippets and then simplifies them reading that, quizdr

22:15 teslanick: Speaking of which, is there any clojure-oriented code review groups out there? The clojure tag on codereview.stackexchange is pretty dead.

22:16 I see the clojure a coworker can write, and I feel like Phillip Fry with a Holophonor

22:17 insamniac: lol

22:17 you're not alone

22:19 ivan: I can confirm that infoqscraper finally does the right thing, if you download a recent ffmpeg build and run PYTHONPATH=. python bin/infoqscraper presentation download --ffmpeg ./ffmpeg --type h264_overlay core-async-clojure

22:20 the aspect ratio on the video recording is slightly off but that is ignorable or fixable

22:25 quizdr: mklappstuhl just perusing the solutions at 4clojure will give you all you need to know and more, it's a fantastic learning resource

22:25 of course, you can't see the solutions until you've come up with one of your own!

22:27 mklappstuhl: quizdr: yeah probably thats better for learning, coming up w/ sth on your own first

22:28 quizdr: being able to mix map, apply, reduce all in a single line of code is really extraordinary, all these tools available for genuine creativity. if you ask a c++ person to write a particular function, most of them will do it more or less the same way, because there aren't as many options. but these lisps bring ideas to the surface and really open up the process in ways i've never seen before. i really had no idea what computer programming

22:28 could be until i discovered this stuff

22:30 i know i'm preaching to the choir, but not having to think about low-level details and also getting to increase the thinking/typing ratio when coding has really spoiled me quickly.

22:31 insamniac: Yeah I follow a bunch of people on 4clojure, and it's crazy to see the variety of ways one can approach a problem.

22:32 To be honest, I'm still uncomfortable with the freedom.

22:33 quizdr: insamniac i think that will change as you master the various functions. for me i simply don't know what a lot of those functions are, so I resort to basically implementing them on my own to solve a problem, hence why loop/recur ends up getting more air time than it deserves. then I see code on there that uses cool little built-in tools and i realize I should be memorizing the clojure.core API!

22:33 gfredericks: random function you don't know about yet: fnil

22:34 quizdr: ,(doc fnil)

22:34 insamniac: true story

22:34 clojurebot: "([f x] [f x y] [f x y z]); Takes a function f, and returns a function that calls f, replacing a nil first argument to f with the supplied value x. Higher arity versions can replace arguments in the second and third positions (y, z). Note that the function f can take any number of arguments, not just the one(s) being nil-patched."

22:34 quizdr: wow

22:34 insamniac: i remember when i first saw juxt and got all giggly.

22:34 gfredericks: ,(update-in {:foo 12} [:bar :baz] (fnil conj #{}) 42)

22:34 clojurebot: {:bar {:baz #{42}}, :foo 12}

22:37 quizdr: that's an eye-full

22:38 gfredericks: I've mostly only used it to add things to collections that might be nil

22:39 dsrx: ,(doc fnil)

22:39 clojurebot: "([f x] [f x y] [f x y z]); Takes a function f, and returns a function that calls f, replacing a nil first argument to f with the supplied value x. Higher arity versions can replace arguments in the second and third positions (y, z). Note that the function f can take any number of arguments, not just the one(s) being nil-patched."

22:42 teslanick: One thing I've noticed -- and maybe this is because I write clojure after work but before bed -- is that I have really weird dreams about homoiconicity

22:44 quizdr: telansick actually i kid you not so have i. when i first discovered common lisp, i was dreaming about it at night for several days.

22:44 almost like discovering a drug, to be honest.

22:44 technomancy: quizdr: I had a fever like that once

22:45 quizdr: technomancy ha i got the clojure fever every day, son!

22:45 technomancy: I dreamed I was implementing https://en.wikipedia.org/wiki/Puyo_Puyo_(series) in emacs lisp as a derived mode of M-x tetris

22:45 quizdr: really, you too? that's quite a coincidence

22:45 technomancy: it was a really high fever

22:46 quizdr: ...they always are

22:47 teslanick: I think my brain made the linguistic connection between homo-iconic and homo-sapiens, so I was dreaming of humans implemented as self-modifying s-expressions. I also haven't been sleeping well, so maybe there's a connection.

22:50 quizdr: i went to a lecture last night, the guy runs a company where they treat the brain as a computer that runs software programmed by nature over large stretches of natural selection, proposing that modern day problems already have solutions in the software. they use Haskell.

22:51 to uncover what the software actually is, they look at statistical analysis of historical problems and how they resolved, using that as evidence of what the inner implementations might be. almost seems like decurrying to me.

22:51 teslanick: That's a little arrogant, but then… haskell. ;)

22:51 technomancy: that sounds like one of the talks I heard at strangeloop

22:53 quizdr: check it out http://www.appliedcognitivescience.com/

22:53 well, looks like there isn't much there on the site

22:54 he used topology to showcase the ivention of functors

22:56 in which I discovered that the word "functor" in haskell has a completely different meaning than the same word in c++ :)

23:01 KeithPM: Good day all. I am trying to figure out why I am not receiving any input from the following function. (compute-winnings-for-a-trial n ) works on its own https://gist.github.com/kpmaynard/8611605

23:02 TEttinger: KeithPM, conj doesn't change acc

23:02 so you return the original acc, []

23:02 you need to just take out the acc after that compute-winnings call

23:02 quizdr: KeithPM yes remember all data is immutable. you should just pass the conj statemet to recur

23:03 or whatever is appropriate

23:03 KeithPM: TEttinger: Yes, yes… Bad error :)

23:03 TEttinger: err I think I read it wrong btw

23:05 KeithPM: TEttinger: I think I should perform the conj within the recur...

23:06 quizdr: KeithPM yes that would be a good way

23:06 alternately you could use a let form up top if you need the conj result more than once

23:07 KeithPM: quizdr: OK let within the loop right?

23:08 quizdr: only if you need the conj result more than once, you could put a let in there yes

23:08 TEttinger: oh and when I ran it the loop never terminated?

23:08 not sure what condition it should end on, but I'm guessing m <= 0

23:08 akurilin: Does anybody know of a guide for how to set up running unit test from the repl, including reloading the project if it needs to be.

23:09 KeithPM: TEttinger: Really? But I'm decrementing m each time… Hmmmm

23:09 TEttinger: Thanks, I will look in to that problem

23:10 quizdr: you are decrementing m each time, but where is the exit? the recur is outside of your if test

23:10 KeithPM ^

23:12 KeithPM you don't need a let because looks like you are only conj when you recur, so put your conj in the recur only.

23:12 you could replace your current conj form with the recur form to move recur inside the if test, and put the conj inside the recur.

23:13 TEttinger: try https://gist.github.com/tommyettinger/8611744 , KeithPM

23:13 KeithPM: quizdr: I agree, The idea is that I would loop to the loop point, with m decremented. If m becomes 0 the else-part should be executed, I think

23:14 quizdr: if you are going to recur, you a test inside the loop where the result is not a recur, or else you have an infinite loop.

23:14 KeithPM: quizdr: Yes, I am trying that, recurring in the then-part and returning acc in the else-part

23:14 quizdr: currently, recur is always getting called no matter what

23:15 KeithPM: quizdr: OK, let me take a look at it. Wow, amazing how easily one can blow one's foot off LOL… 5 lines of code!!!!

23:15 TEttinger: infinite loops are easy, fixing them not so much

23:15 KeithPM: TEttinger: Thanks, looking at it now

23:15 quizdr: for example you could have a line like this: (recur (dec m) n (conj acc (compute-winnings-for-a-trial n)))

23:15 KeithPM: TEttinger: :)

23:15 TEttinger: don't need the n actually, since it doesn't change

23:16 quizdr: put that as one of the if branches and you at least have a non-recurring branch to exit the loop

23:16 KeithPM: TEttinger: Rightm, right… The n is available already…

23:17 TEttinger: That's exactly what it should look like, thanks

23:18 joshuafcole: Hey folks, where do leiningen plugins get stored at?

23:18 I'm trying to patch cljsbuild but can't seem to find it.

23:18 quizdr: ha ha i just saw TEttinger gist, don't know why i was repeating it

23:18 could have saved some typing

23:18 :)

23:19 KeithPM: quizdr: Thanks anyway, I appreciate it

23:19 TEttinger: KeithPM, there's an easier way too

23:19 ,(defn multiple-trials [m n] (repeatedly m #(compute-winnings-for-a-trial n)))

23:19 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: compute-winnings-for-a-trial in this context, compiling:(NO_SOURCE_PATH:0:0)>

23:19 TEttinger: oh right

23:19 well it does almost the same thing, just as a seq not a vector

23:19 KeithPM: TEttinger: I tried that but repeatedly needs a no-arg function

23:20 TEttinger: it is, n is outside the closure

23:20 KeithPM: Oh OK, you used the anonymous function… I did not try THAT… That's neat

23:21 TEttinger: assuming your compute just returned a random number... ##(let [m 6 n 8] (repeatedly m #(compute-winnings-for-a-trial n)))

23:21 lazybot: java.lang.RuntimeException: Unable to resolve symbol: compute-winnings-for-a-trial in this context

23:21 TEttinger: dammit!

23:21 KeithPM: For any beginners out there, I am actually following an article which tries to introduce developing an entire clojure program which runs a heads and tails  (coin flipping) game. http://archive.eddology.com/post/14592579289/busy-persons-clojure?goback=.gde_1058217_member_5831664140367724547#!

23:21 TEttinger: assuming your compute just returned a random number FOR REAL... ##(let [m 6 n 8] (repeatedly m #(rand-int n)))

23:21 lazybot: ⇒ (7 2 7 6 1 1)

23:22 KeithPM: TEttinger: I will try again with the anonymous function

23:23 TEttinger: repeat and repeatedly have some interesting subtle differences... the anonymous fn syntax creates a no-arg fn if no % args are used in the body

23:24 KeithPM: TEttinger: Yes, I think you already bound the n so anonymous function is in fact no-arg

23:24 TEttinger: (that's a fun catch, you would expect it to at least have a % single arg, right? but it is smart about it)

23:30 KeithPM: TEttinger: repeatedly works wonderfully well :) … Fewer keystrokes extends programmers' lives :)

23:38 akurilin: Hey folks. Is there a way to (require) all the namespaced under a certain folder?

23:38 I'd love to be able to require all my test nses at once so that I can do (clojure.test/run-all-tests) on them.

23:40 Anderkent: akurilin: bultitude can tell you what is on the classpath

23:45 technomancy: akurilin: the fact that `lein test` can't be invoked from within your project itself is a big failing of the design there

23:47 hopefully we can fix it in 3.0

23:48 * mklappstuhl fun, I actually just tried that...

23:54 akurilin: technomancy: I was reading your guide for lein test and you say in there that we should use clojure.test/run-all-tests to test from the REPL. What's your recommendation for getting those namespaces loaded int he first place?

23:55 Should I use bultitude and require all of the test ones?

23:55 technomancy: akurilin: bultitude is about the only way, yeah

23:56 akurilin: Ok, will give that a try then.

23:56 Any guides for how to UT from one's REPL you might be aware of ?

23:56 I couldn't find anything in the "blogosphere"

23:57 Which is surprising because this is pretty basic.

23:58 technomancy: akurilin: I don't ever do a full test from the repl

23:58 I just est the specific nses that I'm working on

23:59 and then before merging or pushing or whatever run a fresh `lein test` from the CLI so I know that the JVM state hasn't been corrupted

23:59 personally anyway

Logging service provided by n01se.net