#clojure log - Apr 14 2014

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

0:01 martinklepsch: another question on futures... creating a future for reading, parsing, deleting a file for a few thousand files and return a list of futures — does that sound something what you'd do with futures?

0:04 amalloy: martinklepsch: you don't really want to create a thousand futures at once - that's a lot of scheduler contention

0:05 martinklepsch: amalloy, whats something I should look into then to read/parse/delete files paralelly

0:06 maxthoursie: sounds like a task for a queue

0:07 awalker: having a hard time wrapping my head around this destructuring behavior: https://www.refheap.com/75845

0:08 I'm expecting the 2nd example to work, but it fails.

0:08 turbofail: martinklepsch: take a look at the claypoole library, it's pretty sweet

0:10 martinklepsch: turbofail looks interesting thanks!

0:11 Raynes: awalker: (apply (fn [& {:as more}] more) (mapcat identity {:a 1}))

0:12 Ideally, if you have control over this function you'd just make it take a map instead.

0:12 Generally if you find yourself unrolling arguments for the sake of keyword destructuring, it's better to just pass a map.

0:15 awalker: thank you, but why does the 2nd ex fail? feels like it should work but is it intentionally not supported?

0:17 [Neurotic]: Anyone else noticed that clojars latest-version.svg is being aggressively cached by github? It doesn't seem to be updating in my README.md

0:19 amalloy: awalker: because when you seq {:a 1}, you get ([:a 1]), not (:a 1)

0:20 so when you apply f to ([:a 1]), it sees a single arg, [:a 1], rather than the two args :a and 1 you wanted to pass

0:20 bob2: pretty sure github doesn't touch it at all, and just tells your browser to load it

0:21 awalker: ah, thank you

0:21 [Neurotic]: bob2: was that to me?

0:31 bob2: [Neurotic], yes

0:32 [Neurotic]: bob2: I wish ;) nope, they now cache it on fastly cdn - it's no longer pass through

0:32 https://github.com/github/markup/issues/224

0:37 bob2: interesting

0:44 [Neurotic]: there is a Cache-Control: max-age=0 in the header, but doesn't look like it's respecting it

2:07 dissipate: how do you set up selectors with clojure.test? for instance, i want to tag a particular test as an 'integration' test, and only have it run when i want to select integration tests to be run

2:11 nevermind, looks like this is supported by lein

3:57 sm0ke: can macros be made private?

3:57 amalloy: yes, but there's not much point (as with functions, really). like, you prevent the user from...expanding into code they could have written themselves? what's the point?

3:58 sm0ke: point being hiding them from documentation

3:59 amalloy: mmm. well, you could see if your doc-generator supports some annotation other than ^:private, or you could put them into an "internal" namespace and ask it not to document that namespace

3:59 or document it as "bro, don't use this. you'll regret it"

3:59 sm0ke: :P

3:59 what if the bro is adventurous

4:00 amalloy: then...so what?

4:00 sm0ke: let me try attaching meta

4:00 amalloy: they used a function you told them not to, and it made them happy. if a future version of your software removes it, they only have themselves to blame

4:00 sm0ke: i am using codox

4:01 amalloy: https://github.com/weavejester/codox#skipping-individual-functions

4:01 sm0ke: ,(doc defmacro)

4:01 clojurebot: "([name doc-string? attr-map? [params*] body] [name doc-string? attr-map? ([params*] body) + ...]); Like defn, but the resulting function name is declared as a macro and will be used as a macro by the compiler when it is called."

4:01 sm0ke: where is the meta-map here?

4:07 oh its called attr-map?

4:08 ^:private works with codox

4:09 amalloy: as does ^:no-doc, sm0ke, which i linked to

4:12 sm0ke: yes yes

4:12 (inc amalloy)

4:12 lazybot: ⇒ 94

4:12 sm0ke: whoa!

4:12 thats a lot

4:16 kaw_: LSD ls -ltra

4:16 Oops, sorry

4:32 derek_c: does anyone know how to give ring a callback on exit?

4:32 so I want some code to be run when the web application terminate

4:32 *terminates(

4:34 beamso: https://github.com/weavejester/lein-ring#general-options (:destroy)

4:38 derek_c: beamso: thanks!

4:58 sveri: Hi, I am using datomic and I wonder if its common do use some uniqe id's for datoms like you do in relational databases? I have not seen an example for this so far

5:30 oskarth: What's a good pattern to remove the mental overhead of remembering if a resource should be called as function or not? For example (def users-url "foobar.url") and (defn user-url [id] (str "users-url" id)) I could do (defn users-url [] ...) but that feels silly, and putting (str "users-url" id) everywhere seems prone to mistakes. What does a _simple_ solution

5:30 look like?

5:31 *(str users-url "/" id)

5:41 Slighly silly question but it feels like must be a simple solution which doesn't involve overly long names like "make-user-url"

5:43 ucb: oskarth: if you're taking votes, I'd +1 (defn user-url [id] ...)

5:43 (without knowing anything else about your problem)

5:43 oskarth: ucb: what would you do with users-url then? def or defn?

5:44 cause it "should" be a def, but if it is at least I make the mistake of calling it as (user-url) since it has the same shape as (users-url id)

5:45 not a hard problem but feels like one that shouldn't exist at all if you are doing it right

5:46 (cause someone else might be doing a (let [user-url (str users-url "/" id)]...)

5:47 ucb: sure

5:47 so, is users-url a constant or could that change?

5:47 oskarth: constant

5:47 ucb: if the latter, it's common practise to name it *users-url*

5:47 which already gives it meaning

5:47 right

5:47 oskarth: yeah definitely

5:47 ucb: what'll be the most common usage?

5:48 wouldn't (defn user-url [id] ...) mas users-url anyway?

5:48 mask*

5:48 oskarth: nope

5:48 in the case of an API both would be used

5:48 ucb: sorry, not mask, but rather use users-url internally, implying users-url is private anyway

5:49 in danger of sounding silly, if you want consistency, then make (defn users-url [] "...")

5:49 oskarth: yeah I agree that's one one solution to enforce consistency, but as you say it's a bit silly to write (users-url) for a string

5:50 ucb: again, I don't have a good answer, but is users-url is bound via config

5:50 then an alternative is to have (defn users-url [config] ...)

5:50 where config could be a map, etc.

5:51 oskarth: in this case it would just be the same string all the time

5:51 I guess it could be hidden away in one or two functions with (get-user [...]) since that's the actual resource, and then let it be a bit ugly there

5:52 ucb: sure

5:52 sounds like users-url is an internal detail anyway

5:52 oskarth: bikeshedding problem perhaps, but feels like it should be a solved problem with good patterns, not something you spend mental cycles on

5:52 just tired of getting those types of errors

6:18 ssqq: In a function call, when I use let create a lexical binding, how to redefine its value?

6:19 nightfly: use a reference type

6:24 ssqq: nightfly: you means? (defn f [] (let [v (ref "s")] (dosync (ref-set v "v")))

6:25 llasram: ssqq: More typically, you just don't do that, or use e.g. recursion to get the effect of rebinding w/o actual mutability

6:25 ssqq: What in particular are you trying to achieve?

6:25 nightfly: or that :p

6:27 ssqq: llasram: I want a char cache in a function call. I use perl before.

6:27 llasram: What is a "char cache"?

6:28 ssqq: llasram: In a loop of char-list, push char to a vector one by one.

6:29 llasram: Yeah, you want the pattern of updating by recursion

6:30 Which is the essential nature of `reduce`: ##(reduce conj [] "string")

6:30 lazybot: ⇒ [\s \t \r \i \n \g]

6:31 llasram: Or manually: ##(loop [v [], s (seq "string")] (if-not s v (recur (conj v (first s)) (next s))))

6:31 lazybot: ⇒ [\s \t \r \i \n \g]

6:32 ssqq: llasrm: but have many branch when met a char. I want write a reader of clojure.

6:32 llasram: Like https://github.com/clojure/tools.reader ?

6:34 ssqq: llasram: yes, I need learn this project. thanks very much.

6:34 llasram: np

6:40 sveri: hi, i have a datomic schema with an instant attribute, now, when I initialize my database I load some data from an edn file, how would I add a valid datetime for that instant attribute? I cannot find an example for this

6:49 sm0ke: whats is the simplest way to have a f applied to a initial value, then again apply to the result, and return a lazy seq

6:56 gfredericks: ,(doc iterate)

6:56 clojurebot: "([f x]); Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects"

6:58 perses: hello

6:58 what is the best way to create a graph and then serialize it to a binary?

6:58 noidi: 12:44] < ucb> if the latter, it's common practise to name it *users-url*

6:58 perses: is there a native support for a graph in clojure?

6:58 noidi: I'm sorry but that's just wrong

6:59 the "earmuffs", as they're called, signify that the var is dynamically bound

6:59 ucb: noidi: isn't it the case that is a var is dynamically ... yeah

6:59 noidi: it has nothing to do with constancy

6:59 ucb: sure, apologies, words don't come out easy early in the morning :)

7:02 noidi: and apparently reading doesn't come easily to me either, I misread you and thought you suggested using the earmuffs for constants, so apologies to you as well :)

7:03 ucb: oh, heh, no :)

7:04 sm0ke: gfredericks: thanks

7:04 (inc gfredericks)

7:04 lazybot: ⇒ 52

7:06 noidi: oskarth, I think the right way to solve that problem is with a type system. In core.typed, your examples would have the types String and [String -> String].

7:07 oskarth: noidi: I think you might be right. I'm actually looking into it right now :)

7:07 (not for that specific problem, just in general)

7:10 noidi: I don't think it's quite polished enough to be recommended for general use (yet!), but it's already usable and useful if you don't mind reporting bugs and working around them :)

7:12 jonathanj: does it bother anyone else that (inc foo) shouldn't actually do anything permanent? poetic license? :P

7:12 vijaykiran: perses: Graph as in graph image ?

7:13 jonathanj: (i guess (swap! foo (inc foo))) is a bit of a mouthful?)

7:13 perses: vijaykiran: Graph: set of nodes + set of edges

7:13 noidi: ambrosebs keeps improving core.typed an impressive rate, so I'm sure it's only a matter of time until I'll feel comfortable recommending it without any disclaimers

7:14 (given the enormous size of the task that might take a couple of years, though)

7:15 gfredericks: jonathanj: it'd be (swap! foo inc)

7:16 jonathanj: gfredericks: err, right!

7:17 user=> (def foo 0)

7:17 user=> (swap! foo inc)

7:17 ClassCastException java.lang.Long cannot be cast to clojure.lang.Atom clojure.core/swap! (core.clj:2160)

7:17 Bronsa: jonathanj: foo needs to be an atom (def foo (atom 0))

7:17 pjstadig: jonathanj: you'd have to either (def foo (atom 0)) or (alter-var-root #'foo inc)

7:17 gfredericks: ,(def next-num (partial swap! (atom 0) inc))

7:17 clojurebot: #'sandbox/next-num

7:18 gfredericks: ,(next-num)

7:18 clojurebot: 1

7:18 gfredericks: ,[(next-num) (next-num) (next-num)]

7:18 clojurebot: [2 3 4]

7:18 jonathanj: ah

7:18 pjstadig: ,(take 50 (repeatedly next-num))

7:18 clojurebot: (5 6 7 8 9 ...)

7:18 perses: is there anybody here have used loom graph lib?

7:19 gfredericks: ,(next-num)

7:19 clojurebot: 12

7:19 gfredericks: pjstadig: ^ ha

7:19 jonathanj: haha

7:19 pjstadig: grr

7:19 gfredericks: ,(->> (repeatedly 10000 next-num) (reduce +))

7:19 clojurebot: 50125000

7:19 gfredericks: ,(next-num)

7:19 clojurebot: 10013

7:20 jonathanj: so i guess next-num is like Python's itertools.count, is this not defined in clojure somewhere already?

7:22 ("count" is a different thing and i'm out of names to try searching for)

7:27 ambrosebs: Bronsa: FYI you might have missed Aaron's latest comment on your GSoC proposal

7:27 Bronsa: uh, I sure did. I'm going to check now, thanks

7:35 gfredericks: jonathanj: only similar thing is gensym I think

7:35 ,(gensym)

7:35 clojurebot: G__27

7:35 gfredericks: ,(last (repeatedly 930848 gensym))

7:35 clojurebot: G__930899

7:35 gfredericks: ,(gensym)

7:35 clojurebot: G__930924

7:35 llasram: Well, or `range`

7:36 jonathanj: range, duh. i forgot to look for that one

7:36 llasram: Modulo the fact that Clojure doesn't do the stateful-iterator thing

7:36 jonathanj: llasram: yeah, obviously it doesn't map quite the same way

7:36 i was just curious

7:51 gfredericks: oh I thought statefulness was the essense of the question

7:51 global statefulness in particular

8:01 wunki: I found out that a multimethod is only found if I require the namespace where it is defined in my main. Is this correct?

8:03 gfredericks: wunki: it's the same as for any var

8:03 the multimethod lives wherever the `defmulti` is

8:04 wunki: gfredericks: I'm defining a multimethod in a namespace which is never referenced from the `:main`, so it's also not found

8:05 gfredericks: the defmulti is defined in an external library

8:05 gfredericks: right; requiring things is important, not just for multimethods

8:06 wunki: gfredericks: is there a way to require a multimethod?

8:06 gfredericks: or should I just use `:refer :all`

8:10 llasram: For the multimethod itself just `require` the namespace and refer to it like any other var.

8:10 For implementations, you just need to `require` the implementing namespace(s)

8:10 (no special details on the `require`, that is -- any `require`ing will do)

8:11 wunki: Rule of thumb: if you need to `:refer :all`, you've done something wrong

8:11 wunki: llasram: thanks, will keep it in mind

8:11 llasram: currently only using `:refer :all` in my tests

8:12 llasram: Cool. That's perfectly reasonable

8:30 ambrosebs: Bronsa: is it a good idea to assume tools.analyzer will preserve arguments to `do`, especially constants?

8:33 Bronsa: ambrosebs: hm, at the moment it does. In the future it will have a pass to remove no-ops like constants in statement position but that's going to be in a pass

8:33 so you can always remove that pass if you need that guarantee

8:34 ambrosebs: Bronsa: ok. `do` statements seem like a good place to jam annotations since we can preserve tag inference

8:34 (tc-ignore foo) => (do ::tc-ignore foo)

8:35 Bronsa: I see. Yeah, you should have no problems with that right now

8:36 ambrosebs: I'll let you know if/when this might change, but again, you'll always have the option to preserve the original behaviour

8:36 ambrosebs: Bronsa: thanks. Also folding nested `do`s would break my approach.

8:36 Bronsa: ambrosebs: uhm that might be a problem I think

8:36 dottedmag: Are there alternatives to Datomic? That is, other "accretion-based" DBs.

8:37 Bronsa: ambrosebs: nested top level `do`s need to be folded to address the Gilardi Scenario

8:38 ambrosebs: nevermind, that's not done in the analyzer

8:38 tbaldridge: dottedmag: not that I'm aware of, at least not any that have immutability + datom based storage + datalog + data locality

8:39 ambrosebs: Bronsa: I can deal with that possibility, good to know.

8:39 Bronsa: ambrosebs: you should be good to go on that. IIRC the only place where t.a removes some forms is (try foo) => foo which I believe Compiler.java does too

8:39 dottedmag: tbaldridge: Thanks, that's what I expected as well.

8:51 mdrogalis: dottedmag: My experience has been that you have to treat the data store as accretion-only yourself.

8:51 Nathan Marz's book that's coming out covers it pretty well, IMO

9:02 arrdem: ambrosebs: +1 for supporting symbol aliases

9:10 ambrosebs: arrdem: was it you talking about the > suffix a few days ago?

9:35 jonathanj: how would i write (re-find #"[^0-9]+" "ZAR123.45") without regexes?

9:36 (apply str (take-while-not digit? s)) is what i had in mind

9:37 but i'm guessing a bunch of these don't exist

9:40 `szx: ,(defn digit? [c] (Character/isDigit c))

9:40 clojurebot: #'sandbox/digit?

9:41 `szx: ,(apply str (take-while digit? "123abc"))

9:41 clojurebot: "123"

9:41 `szx: oh wait you want the other way around

9:43 ,(apply str (take-while (complement digit?) "ZAR123.45"))

9:43 clojurebot: "ZAR"

9:45 jonathanj: complement

9:45 i can never remember that damn name

9:45 `szx: thank you

9:46 hrm

9:46 Character/isDigit is not defined in my environment

9:48 TimMc: &(apply str (remove #(Character/isDigit %) "४२123"))

9:48 lazybot: ⇒ ""

9:49 jonathanj: user=> Character/isDigit

9:49 CompilerException java.lang.RuntimeException: Unable to find static field: isDigit in class java.lang.Character, compiling:(NO_SOURCE_PATH:0:0)

9:49 :/

9:49 TimMc: jonathanj: It's a static method, not a function.

9:49 You can call it, but you can't evaluate it.

9:50 s/static // more generally

9:50 jonathanj: user=> (Character/isDigit "a")

9:50 IllegalArgumentException No matching method found: isDigit clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:80)

9:50 TimMc: Oh, how old is your Java?

9:51 jonathanj: i have no idea how to find that out

9:51 java version "1.7.0_45"

9:51 Java(TM) SE Runtime Environment (build 1.7.0_45-b18)

9:51 Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)

9:51 TimMc: Oh, type issue.

9:51 &(Character/isDigit \a)

9:51 lazybot: ⇒ false

9:51 TimMc: Pass it a character, not a string. :-)

9:52 jonathanj: hur

9:52 TimMc: so what's going on with your example there? an empty result seems broken

10:11 arrdem: ambrosebs: neg

10:12 ambrosebs: arrdem: np

10:12 TimMc: jonathanj: Those ara Devanagari digits. :-)

10:12 http://www.fileformat.info/info/unicode/char/96e/index.htm

10:12 ambrosebs: arrdem: cheers for the input

10:12 arrdem: ambrosebs: usability++

10:12 jonathanj: TimMc: aha!

10:12 * arrdem feels bad for doing an in place update in #clojure

10:13 TimMc: &(.getPort (.toURL (java.net.URI. "http://google.com:६/&quot;)))

10:13 lazybot: ⇒ 6

10:14 TimMc: ^ Java mistakenly uses a broad definition of "digit" for some parsers.

10:14 ambrosebs: arrdem: just one of those things I played it safe on

10:15 arrdem: ambrosebs: I really appreciate the desire to make sure you get it correct, but I think there's a very reasonable element of "you'd expect it to work" at play with :require :as annotations.

10:16 hence my support therefor... the compiler should already be issuing warnings if you have an :as conflict.

10:17 ambrosebs: arrdem: yes I'll implement it. My reasoning for the decision didn't make sense in hindsight.

10:17 arrdem: ambrosebs: <3

10:17 ambrosebs: glad I'm adding alias support (non-breaking) than removing it :)

10:24 afgdf: in the /bin/repl (datomic) i cannot use the arrow keys, i get '^[[A'. D left, C right, , A up, B down. Anyone knows how i solve that?

10:34 btcNeverSleeps: I've got an issue and can't really produce a minimal test case so I'm asking for help here in case anyone had the same problem... I've got one test .clj file (using clojure.test) which fails when I try "cider-eval-buffer".

10:34 However that same test .clj file works fine from "lein test"

10:34 ToBeReplaced: btcNeverSleeps: persists after you restart cider?

10:34 btcNeverSleeps: ToBeReplaced: yup

10:35 ToBeReplaced: persists after I restart Emacs

10:35 however...

10:35 If I switch to the other .clj file (which I :require / :refer all from the test file) and do cider-eval-buffer, then back to the test .clj file then cider-eval-buffer now works from Emacs too

10:36 ToBeReplaced: btcNeverSleeps: sounds like a source path problem; are you using multiple profiles with leiningen?

10:37 btcNeverSleeps: I don't think so... No too sure what multiple profiles are. It's a regular lein project. I mostly call "lein test" and, once in a while, "lein run". The project directories were created using lein.

10:37 could it be some _ / - issue?

10:39 erf...

10:40 cannot easily do more testing because I'm under Emacs and I'm using erc to do IRC (silly me)

10:40 arrdem: damnit... I shoulda parsed lazybot's logs..

10:41 btcNeverSleeps: oh well, I take it I'll just cider-eval-buffer the other buffer(s) manually as of now. And then update everything (lein, cider, etc.) to the latest versions.

10:42 ToBeReplaced: btcNeverSleeps: absolutely could be a _/- issue... not sure what should be done to better document that; seems a lot of people stumble on it

10:43 btcNeverSleeps: I renamed the file, I'll restart Emacs and come back in the channel to tell if it works or not

10:43 justin_smith: load failure should check for - in the name and then add an extra output about munging

10:43 why would that require an emacs restart?

10:46 btcNeverSleeps: hmm still not working: it's still saying "Unable to resolve symbol: ... in this context" when I try to cider-eval-buffer that test .clj file even though the require is there and even though from "lein test" things work fine. Even though I removed the "-" from my test .clj filename / namespace. Not that much of a big deal: it's just a minor annoyance.

10:47 justin_smith: what about lein check?

10:48 sveri: hi, I am getting this instant type back from datomic: #inst "2014-12-01T00:00:00.000-00:00" and want to parse that in clojure script, how would I do that?

10:48 justin_smith: can't clojurescript just read that? it should

10:49 arrdem: you shouldn't have to read that... and besides #inst is a standard EDN reader form.

10:49 justin_smith: right, if you can read at all, that should be parsed no problem

10:49 guest234235: any advice on best way to grab (or examples) of Om (or vanilla cljs) fetching remote JSON data?

10:49 btcNeverSleeps: I just tried "lein check": throws an Exception for that one .clj file that my test doesn't want to :require : "java.lang.ClassNotFoundException: clojure.stacktrace"

10:50 sveri: arrdem: so I should have to convert it to a string before passing it to cljs?

10:50 justin_smith: btcNeverSleeps: that's a namespace, are you referring to it in some odd way?

10:51 btcNeverSleeps: justin_smith: let me check ^ ^

10:51 justin_smith: you should be able to require it no trouble, but if you accidentally referred to it unquoted you may see that error

10:51 btcNeverSleeps: it's on this line in my source file: (clojure.stacktrace/print-stack-trace t)


10:52 justin_smith: do you require the ns? that's probably the issue

10:52 btcNeverSleeps: oh I see

10:52 but why is it an issue? And why is "lein test" not chocking on it?

10:52 sveri: guest234235: as far as I can tell OM uses an app-state cljs variable, so all you have to do is replace that app-state contents with your JSON returned data

10:52 justin_smith: lein test runs tests, if you define them and put them under a test/ dir

10:53 lein check, on the other hand, loads every clojure file it finds, and reports any errors it sees

10:53 so lein test will never try to load an ns that is not required by a test ns

10:53 btcNeverSleeps: gotcha

10:54 I didn't know about "lein test" btw: thanks for the (great) info : )

10:54 guest234235: sveri: yep. was looking at using cljs-http to do a standard GET request; though that returns an async channel ... still learning ..

10:54 sveri: guest234235: I guess we all are :-)

10:55 guest234235: wondering if there's any example apps or repos that have already 'solved' this seemingly common thing: "get remote data; update display accordingly"

10:55 in elegant, succint cljs, of course ;-)

10:56 justin_smith: guest234235: bird's eye view: do an ajax call, the callback provided to the ajax call should update the data structure that om renders when it gets its result

10:56 this will make om re-render, et voila

10:57 http://stackoverflow.com/questions/8567114/how-to-make-an-ajax-call-without-jquery

10:58 `szx: guest234235: have you read the advanced tutorial? https://github.com/swannodette/om/wiki/Intermediate-Tutorial

10:58 * btcNeverSleeps shall brb

10:58 `szx: err, intermediate

11:01 guest234235: yeah. think https://github.com/yogthos/cljs-ajax is going to make things easier.

11:17 te: I am using clojure.data.csv. I have tuples like: ["foo", 1, "baz"]. I want to /append/ to a CSV file and not just write it wholesale.

11:17 Suggestions?

11:18 justin_smith: te: appending is a fiction, you write the previous contents, followed by new ones

11:19 seangrove: justin_smith offers new-comers no choice between red and blue pills

11:19 arrdem: justin_smith: really?

11:19 te: justin_smith: heh, seriously?

11:19 arrdem: justin_smith sits on a throne of lies...

11:19 justin_smith: arrdem: well some operating systems fake it :)

11:19 seangrove: clojurebot: justin_smith sits on a throne of lies

11:19 clojurebot: I don't understand.

11:19 arrdem: justin_smith: some operating systems aren't completely retarded :D

11:19 seangrove: clojurebot: justin_smith is sits on a throne of lies

11:19 clojurebot: Ack. Ack.

11:20 seangrove: ~justin_smith

11:20 clojurebot: justin_smith is sits on a throne of lies

11:20 arrdem: seangrove: lemme

11:20 seangrove: Grammar challenges aside, I like it

11:20 arrdem: clojurebot: justin_smith is <reply> justin_smith sits on a throne of lies

11:20 ~justin_smith

11:20 goddamnit clojurebot.

11:20 seangrove: Hahaha

11:20 te: so, assuming that's true justin_smith -- still, help me out here

11:20 arrdem: seangrove: would you do the honors?

11:20 since the bots hate me..

11:20 seangrove: ~justin_smith

11:20 clojurebot: justin_smith is sits on a throne of lies

11:21 te: I'm assuming I need something like (io/writer "foobar.csv" :append true)

11:21 but i dont know if I can use csv/write-csv if that's the case

11:21 seangrove: clojurebot: justin_smith is <reply> justin_smith sits on a throne of lies

11:21 clojurebot: Alles klar

11:21 seangrove: ~justin_smith

11:21 clojurebot: justin_smith sits on a throne of lies

11:21 cowinfantry: there we go

11:21 seangrove: justin_smith: That was a lot of work, hope you appreciate it

11:21 arrdem: How'd you upset the bots?

11:21 arrdem: seangrove: I have no idea...

11:22 te: so, anyway -- anyone want to offer help on this or just configure bots? ;)

11:22 arrdem: te: we're just here to play with the bots man :P

11:22 te: heh, fair enough

11:22 seangrove: te: Haven't used data.csv, but it seems straightforward enough

11:22 arrdem: te: you could probably use Java interop to open the file in append mode and then write the str of what you want to append...

11:22 seangrove: te: Presumably you have an atomic lock on the file, no one else is reading/writing?

11:23 te: It looks like you just use csv/write-file and give it whatever you've previously read from the file appended with whatever you want to add

11:24 justin_smith: seangrove: which is exactly my throne of lies

11:24 te: seangrove: i was thinking about using agents

11:24 seangrove: justin_smith: That's where I got my explanation form

11:28 arrdem: Bronsa: ping

11:28 Bronsa: arrdem: pong

11:29 arrdem: Bronsa: know of any projects do to test coverage analysis on the basis of t.a trees?

11:29 Bronsa: nope

11:29 justin_smith: it looks like you can in fact create the io/writer you pass to clojure.data.csv/write-csv with the args :append true

11:29 arrdem: good. I have a first project then :D

11:29 justin_smith: (what the OS does with that is another question of course)

11:29 te: hmm okay

11:29 let me give this a try

11:30 Bronsa: arrdem: afaik currently the only projects that are using t.a in releases are core.typed and eastwood

11:30 arrdem: huh cool!

11:30 te: thanks justin_smith

11:30 and company

11:30 arrdem: a merry band...

11:39 guest234235: does cheshire compile to cljs ? or can it only be required in a clj namespace?

11:39 gtrak: guest234235: cheshire is a wrapper over jackson

11:39 which is a java lib

11:39 dakrone: guest234235: no, cheshire uses Jackson which is a java library

11:39 Jabberz: the 'for' macro, is that idiomatic for doing transformation on lists, i.e. putting functions in :let, or are doing say, separate doseq's perferred?

11:40 justin_smith: Jabberz: for when you care about the result, doseq when you want to do something and return nil

11:40 Jabberz: justin_smith: cool, thanks

11:40 justin_smith: doseq has the some cartesian elaboration that for does

11:40 guest234235: dakrone: figured that was the case. best way to 'digest' and work with json in cljs namespace?

11:40 justin_smith: Jabberz: so it need not be nested

11:41 dakrone: guest234235: probably data.json then?

11:41 justin_smith: what about just using interop to turn the json into vanilla js data?

11:41 `szx: guest234235: you can just convert it to clojure data

11:41 justin_smith: and then do what `szx suggests next

11:43 guest234235: want to keep things simple. am a sucker for wrapper libraries that make anything easier, more terse.

11:43 justin_smith: guest234235: turning json into javascript data is very terse

11:43 stuartsierra: Use the G.Closure JSON parser; data.json doesn't have a ClojureScript version.

11:44 justin_smith: why not JSON.parse? that is part of the ecma standard

11:44 http://stackoverflow.com/questions/4935632/how-to-parse-json-in-javascript

11:44 stuartsierra: Or that. I don't know.

11:45 mpenet: JSON.parse is the way to go, and there are shims for when it's missing

11:45 justin_smith: JSON.parse("{foo : bar}")

11:45 `szx: i would assume closure's JSON parser delegates to JSON.parse

11:45 justin_smith: it's that simple

11:45 guest234235: do GET request; returns JSON; need to parse and present.

11:45 gtrak: love that we can grab everything in closure piecemeal. It's massive.

11:45 dnolen_: guest234235: go w/ stuartsierra's suggestion if you need to target <= IE7

11:46 guest234235: targeting mobile.

11:47 justin_smith: ie <= 7 will not run on mobile (that you care about at least)

11:47 correcting myself: JSON.parse('{"foo" : "bar"}')

11:47 (the previous was invalid json)

11:54 guest234235: stuartsierra: really? no clojurescript version to parse json

11:54 stuartsierra: guest234235: It's not needed. Some browsers have it built in and G.Closure libs handle the rest.

11:54 justin_smith: guest234235: JSON is a javascript serialization format, it's silly to write your own javascript json parser

11:57 (js->clj (JSON/parse "{\"foo\" : \"bar\"}")) <- this gives you native clojure data

11:57 it's pretty succinct

11:58 gtrak: guest234235: a fully-clojure impl provides no benefits for most use-cases.

11:58 I wonder the same about any lib that reimplements things that already exist..

11:59 guest234235: reimplements in a way that makes a given lib easier to work with.

11:59 gtrak: maybe once we get a fancy compiler, optimization might change things.

11:59 justin_smith: guest234235: explain to me what part of what I posted above is not easy?

11:59 guest234235: but yes, argument then is immediately, just improve that lib

12:00 justin_smith: it's a function call and a javascript method

12:00 gtrak: guest234235: or we can do idiomatic wrappers, but that's still dubious a lot of the time.

12:00 depending on the complexity of the wrapped project

12:01 guest234235: true. I'm not here advocating crafting dubious, redundant libraries.

12:01 gtrak: If it's not a trivial interface, like the JSON parser, often I'll end up learning more than I would've to use java interop.

12:01 AimHere: You don't need to; those libraries will happen, regardless

12:01 guest234235: just need to grab some remote JSON data, serve it up on a page ;-)

12:02 gtrak: for instance, clj-http and related projects can get really hairy when you do something like client-auth.

12:02 you end up learning more levels of abstraction b/c you're already committed to the idiomatic wrapper.

12:02 so it kind of just pushes the cost around

12:03 but clj-time I think is pretty nice to use, because it's more about surface area than depth.

12:03 guest234235: gtrak: yep. if the use-case is that "it just works" , then fine. costs offloaded.

12:03 AimHere: Most json is parsed by (read-string (replace foo #":" "")) anyways...

12:04 justin_smith: hah, fair enough

12:04 gtrak: AimHere: you're joking? haha.

12:04 justin_smith: in practice yeah that would mostly work I guess

12:04 AimHere: I might not be entirely serious, true ;)

12:05 gtrak: really, if we had better tooling, interop would be even easier.

12:06 and wrappers kind of fill the gap for now

12:15 Vfe: How can I get an entire vector as an argument? for example. (defn func [ [my-vec] ] {:key [my-vec]}) (func [“item1” “item2” “item3”]) gives my-vec a vector of just “item1”.

12:16 Is there some trick to the behavior I want?

12:16 rasmusto: ,(let [[a b :as all] [1 2]] [a b all])

12:16 clojurebot: [1 2 [1 2]]

12:17 `szx: Vfe: you're destructuring the vector, is that what you wanted to do?

12:17 rasmusto: Vfe: hm, maybe I didn't fully understand the question. Do you want the vector destructuring?

12:17 `szx: otherwise (defn func [my-vec]] {:key my-vec}) will work just fine

12:17 ugh

12:17 (defn func [my-vec] {:key my-vec})

12:18 Vfe: No, I just want to take a vector in that will add that vector to a map

12:18 If it’s destructing it that’s maybe where I’m confusing myself XD

12:18 `szx: ,((fn [v] {:k v}) [1 2 3 4])

12:18 clojurebot: {:k [1 2 3 4]}

12:18 rasmusto: Vfe: ah, then do as `szx suggested, don't bother with the destructuring bit

12:18 justin_smith: the extra [] pair introduces destructuring

12:19 Vfe: Gah, you’re right. Thanks for the help. I blame lack of sleep, I should know this, hah

12:19 Appreciate it guys :)

12:20 justin_smith: well, in some c-like language v[] may mean "v, which is a vector", so I could imagine guessing (wrongly) that [v] in an arg vector means the same thing.

12:20 I am probably overthinking that

12:21 `szx: probably :)

12:23 rasmusto: ,(clojure.set/intersection) ; why not #{} ?

12:23 clojurebot: #<ClassNotFoundException java.lang.ClassNotFoundException: clojure.set>

12:24 justin_smith: the intersection of nothing :) sounds pretty zen

12:24 rasmusto: justin_smith: union has a 0-arity case

12:25 justin_smith: rasmusto: if we are basing this on mathematics, I think "everything in null" and "intersection of null" are very different questions

12:26 if on intuition, yeah, generalize all the things to zero args

12:27 rasmusto: justin_smith: I'm doing an (apply intersection some-seq-of-sets), where some-seq-of-sets might be empty, I guess I can just wrap the thing in a cond

12:27 justin_smith: yeah, that makes sense, we really should have zero argument arities of everything defined for that kind of thing

12:28 ((fnil f #{}) sets) maybe?

12:28 rasmusto: justin_smith: yep, was just writing that :)

12:28 justin_smith: ((fnil println "default") nil)

12:28 ,((fnil println "default") nil)

12:28 clojurebot: default\n

12:29 justin_smith: ,((fnil println "default") "provided")

12:29 clojurebot: provided\n

12:29 rasmusto: ,((fnil count 'baz) ())

12:29 clojurebot: 0

12:30 rasmusto: ,((fnil count 'baz) nil)

12:30 clojurebot: #<UnsupportedOperationException java.lang.UnsupportedOperationException: count not supported on this type: Symbol>

12:30 justin_smith: ok, you should call seq

12:30 ,((fnil count "baz") (seq ()))

12:30 clojurebot: 3

12:30 justin_smith: unless there is an fempty

12:31 jonathanj: i'm trying to remember what term Clojure uses to describe the structures it uses for efficiently handling things like subvectors

12:31 rasmusto: justin_smith: I was assuming that nil? would work on '(), probably good that it doesn't

12:31 justin_smith: somehow fempty sounds like something lewis carrol would invent

12:31 jonathanj: (efficiently in terms of memory use)

12:31 technomancy: structural sharing?

12:32 justin_smith: persistent data structures?

12:32 gtrak: jonathanj: persistent array-mapped hash tries

12:32 tim__: jonathanj: trie

12:33 jonathanj: thanks, all of those were helpful

12:33 rasmusto: justin_smith: oh, how should I get 'apply and (fnil intersection #{}) to behave, I won't have a nil argument if I apply that fn to nil :p

12:33 justin_smith: oh wait

12:34 (fnil (partial apply intersection))

12:34 (fnil (partial apply intersection) #{}) that is

12:34 rasmusto: justin_smith: hah, gotcha!

12:34 thanks :)

12:34 justin_smith: (fnil (partial apply intersection) [#{}]) final answer

12:36 (defn intersect' ([] #{}) ([& args] (apply set/intersection args))) ; simpler

12:37 te: /whois te

12:37 AimHere: Youis te!

12:37 te: :D

12:37 justin_smith: oh, I just found out who te is

12:37 te: <-devn on a different client

12:39 justin_smith: "*** lazybot is logged in as Raynes" I should use whois more often

12:39 te: justin_smith: im going to bug you again about visiting. have you gotten a chance to talk to anyone?

12:40 justin_smith: I'll bring it up again

12:42 martinklepsch: any clever suggestion beside threadpools to write/read tens of thousands of small files?

12:42 te: just read? any processing?

12:43 justin_smith: martinklepsch: if they are on one disk, doing it in parallel threads will be slower than reading them one at a time

12:43 thread per disk

12:44 because seek time

12:44 martinklepsch: te, read = xml parsing in that context

12:44 justin_smith,ah thats interesting, also true for SSDs?

12:44 justin_smith: SSD has non-zero seek time

12:44 martinklepsch: I guess yes?

12:45 justin_smith: and reading files in parallel will not be faster than sequentially

12:45 and parsing xml is much faster than getting data from the disk

12:45 te: clojurebot: justin_smith?

12:45 clojurebot: justin_smith is sits on a throne of lies

12:45 justin_smith: hah

12:45 te: :)

12:45 rasmusto: heh

12:48 justin_smith: even ignoring seek time, most OS's will pre-cache, so things are faster if you go sequentially through files rather than in parallel

12:48 unless you are doing something CPU heavy, xml parsing is not CPU heavy

12:52 Jabberz: is there a way to get the index of the entry inside a for/:let ?

12:53 llasram: ,(for [[i x] (map-indexed vector [:a :b :c])] {:value x, :index i})

12:53 clojurebot: ({:value :a, :index 0} {:value :b, :index 1} {:value :c, :index 2})

12:53 amalloy: Jabberz: no; sometimes that notion isn't even well-defined, eg for a nested-loop. but you can use map-indexed at the level you're interested in

12:53 rasmusto: Jabberz: ##(for [[i x] (map-indexed vector [:a :b :c])] [i x])

12:53 lazybot: ⇒ ([0 :a] [1 :b] [2 :c])

12:54 llasram: (inc amalloy)

12:54 lazybot: ⇒ 95

12:54 justin_smith: man, and I was *this close* to saying map-indexed too :)

12:54 Jabberz: ah, thanks

12:54 llasram: Always thinking about the problem slightly deeper than the rest of us

12:54 amalloy: justin_smith: too slow, bro

12:54 justin_smith: heh

12:55 rasmusto: ah, thoughts too deep for me o;

12:56 martinklepsch: justin_smith, I'm essentially splitting a large file into smaller string chunks, save them, parse them, delete them

12:56 justin_smith it's a workaround for not being able to hand strings with paths to DTDs to xml/parse

12:56 justin_smith: martinklepsch: if it is all one file system, I don't think multiple threads will gain you much, given the linearity of storage devices

12:57 which is why I suggested a thread per disk

12:58 martinklepsch: justin_smith, I got that... I just wonder if there are any other ways I could do it. But again this is probably more related to xml parsing

12:58 Bronsa: ambrosebs: ping

12:58 ambrosebs: Bronsa: hi

12:59 amalloy: justin_smith: you could use threads a bit. like, read sequentially from the disk in one thread, putting jobs onto a queue, and have a threadpool to process items from the queue. only matters if processing is slower than disk read, of course, but that's the only case when anything at all matters

12:59 justin_smith: martinklepsch: you don't need to write them if you were going to delete anyway

12:59 martinklepsch: just make an in-memory reading source (ByteArrayInputStream)

13:00 the disk bounce is pointless

13:00 amalloy: yeah, I tried to say that above, but probably much less clearly (when I mentioned the issue of CPU bound processes)

13:01 martinklepsch: see first example here http://clojuredocs.org/clojure_core/clojure.xml/parse

13:01 martinklepsch: justin_smith, theoretically, but xml/parse takes either File, InputStream or a String naming a URI.

13:01 Bronsa: ambrosebs: I think I mentioned this to you some time ago, but I've been thinking about putting Symbols rather than Classes on the nodes, would this be a problem for core.typed?

13:01 amalloy: martinklepsch: that's why he said a ByteArrayInputStream

13:01 technomancy: bbloom: were you the one bugging me about tail calls in my forth instead of loops?

13:01 bbloom: technomancy: yup

13:01 justin_smith: martinklepsch: right, you can make an input stream out of a string, as shown there

13:01 bbloom: technomancy: did you make the switch? :-)

13:01 amalloy: technomancy: who else, eh?

13:02 Bronsa: ambrosebs: not going to do it anytime soon b/c it's a bit tricky to handle reify/deftype but if I figure out an easy way to do it it *should* be a performance win

13:02 technomancy: bbloom: no, but I just read an interview with moore about how he regrets loops in forth and how he got rid of them in his new dialect in favour of recur

13:02 http://www.ultratechnology.com/1xforth.htm

13:02 bbloom: technomancy: yup. it's not really recur tho. it's basically just "rewrite the previous word from a call in to a jump"

13:02 martinklepsch: justin_smith, amalloy, the issue is that the xml to parse contains <xml version ... > a few thousand times and this obviously breaks xml/[arse

13:03 bbloom: technomancy: operating at the machine level, of course

13:03 ambrosebs: Bronsa: which nodes?

13:03 justin_smith: martinklepsch: requesting permission to use xml/arse in future jocularity

13:03 martinklepsch: that's why you split the string, make streams of the parts, then parse those, right?

13:03 Bronsa: ambrosebs: everywhere I now store a Class, that would be replaced by a Symbol. e.g the :class field on :static-call etc

13:03 technomancy: my loop implementation is pretty terrible; it requires a bunch of nasty primitive stuff

13:04 I should probably get rid of it

13:04 amalloy: aside: am i the only one who thinks it's silly that clojure.java.io/reader interprets a string as a url, instead of creating a StringReader? like, we have java.net.URI and java.io.File to disambiguate, but if you want to treat the string as a source itself you just can't use c.j.io/reader at all

13:04 justin_smith: (inc amalloy)

13:04 lazybot: ⇒ 96

13:04 justin_smith: yeah, that has bugged me too

13:04 technomancy: haha "It would of course not be convenient to nest loops but nested loops are a very dicey concept anyway."

13:04 ambrosebs: Bronsa: ok, it'll probably blow up some preconditions.

13:04 bbloom: technomancy: heh, indeed. he's a crazy man

13:04 technomancy: amalloy: oinc

13:05 ambrosebs: Bronsa: which is fine.

13:05 amalloy: i just had an idea: i'll catch up to technomancy's karma by expression non-controversial opinions as if they were novel

13:05 justin_smith: hah

13:05 bbloom: technomancy: the other nice thing about implement ; as jump means you can do early exits of words & transfer of control

13:05 arrdem: amalloy: good luck with that...

13:06 Bronsa: ambrosebs: cool. I'll let you know if/when I make that change. Not anytime soon btw

13:06 llasram: (inc amalloy)

13:06 lazybot: ⇒ 97

13:06 martinklepsch: justin_smith, I think I've tried that before and then the parsing failed because xml/parse couldn't find the DTDs etc, maybe I need to try again ;)

13:06 technomancy: bbloom: I'm kinda biased against early exits because of FP, but this stuff is unapologetically imperative, so ...

13:06 I should probably get over that

13:06 bbloom: technomancy: yeah, you're writing the exact opposite of FP right now

13:06 justin_smith: martinklepsch: you may need to do more elaborate massaging before the arsing stage

13:06 bbloom: technomancy: which is a good thing in such a context

13:06 technomancy: bbloom: but ; as anything other than "definition over" seems to be specific to colorforth afaict?

13:06 bbloom: technomancy: turns out that a lot of the things you thought were no-nos from your C days turn out to be pretty damn reasonable in forth

13:06 ambrosebs: Bronsa: great

13:07 technomancy: bbloom: I didn't have C days

13:07 bbloom: technomancy: it's basically any "machine forth" which is just moore & friend's idea for a very simple minimal forth

13:07 martinklepsch: justin_smith, yeah, potentially prepending directory names before files and that type of stuff

13:07 justin_smith: martinklepsch: I just realized how inappropriate that sounded, no harrassment intended

13:07 amalloy: technomancy: apologetically imperative would be like..."look i'm really sorry, but i need you to increment the variable i. yes, i know you liked it as five, but we really need six right now, and you need to work with the team"

13:07 bbloom: technomancy: ok fine, your emacs lisp days

13:07 technomancy: well, more like my C days are happening now, solely in order to let me write forth

13:07 bbloom: amalloy: nice.

13:07 martinklepsch: justin_smith, all good

13:07 arrdem: (inc justin_smith)

13:07 lazybot: ⇒ 33

13:07 bbloom: technomancy: haha

13:08 technomancy: amalloy: hehe; totally

13:08 bbloom: technomancy: it's fun when you have such a small simple core. it's almost hard to resist tweaking it endlessly

13:08 ambrosebs: Bronsa: you should be able to edit your proposal

13:08 arrdem: technomancy: yeah... this penultimate yak shave of yours is seeming more and more like a decent into madnes.s..

13:08 bbloom: technomancy: like w/ eclj now, the semantics of clojure are expressed so sussinctly that i can clearly see every flaw b/c it's wherever an 'if occurs lol

13:08 technomancy: amalloy: "don't be all X is five, if five is what you mean. If five is on your mind then baby just come clean"

13:09 http://achewood.com/index.php?date=05052003

13:09 arrdem: I am not ruling it out

13:09 Bronsa: ambrosebs: oh, huh, didn't notice that. I guess I'll just copy paste the comment in a "Milestones" section of the proposal, for consistency, then

13:10 ambrosebs: Bronsa: Aaron unlocked it but forgot to tell you

13:10 arrdem: technomancy: it's ok tho, you can alway blame it on the atreus curse

13:10 technomancy: arrdem: hopefully this time no blood is spilled

13:11 arrdem: technomancy: lets hope so... I'd like to see you live to use that keyboard :P

13:12 Bronsa: ambrosebs: ah ok, done

13:12 ambrosebs: Bronsa: thanks

13:18 aciniglio: is there a way to memoize a multimethod?

13:18 amalloy: aciniglio: wrap it in a function?

13:18 arrdem: *memoized function

13:18 aciniglio: amalloy: just the defmethod? or the whole block?

13:19 amalloy: if you want to memoize every implementation, then create a function that calls the multimethod, and memoize that

13:19 arrdem: and be sure to recur through it.

13:19 amalloy: if you want to memoize just one implementation, then define its method to call a function, and memoize that function

13:19 arrdem: meh. you might or might not want to memoize recursive calls

13:20 aciniglio: yeah, that makes sense

13:20 thanks

13:20 justin_smith: arrdem: so you mean use explicit self calls instead of recur?

13:20 arrdem: justin_smith: use explicit calls to the memoizing wrapper rather than recur

13:20 halves your effective stack size tho :c

13:20 justin_smith: arrdem: cool, I can see how that would make sense for some reducing algorithms

13:21 technomancy: amalloy: can't you alter-var-root with a defmulti?

13:21 amalloy: uhhhh

13:21 i would be super-worried about doing that. maybe

13:21 justin_smith: arrdem: maybe memoizing some trampolined functions would be cleaner?

13:21 amalloy: probably not though, i would think

13:21 technomancy: I don't think you need an in-between function

13:22 justin_smith: technomancy: so you are saying you would replace the multi with its memoization with alter-var-root

13:23 Bronsa: I recently discovered that multimethods heavy code is a pain in the ass to profile

13:23 amalloy: technomancy: yeah, as i expected, you can alter-var-root it, but if you do you can't add new defmethods

13:23 Bronsa: It really doesn't help to know that you spend 88% on MultiFn.invoke

13:24 arrdem: ew...

13:24 amalloy: Bronsa: what profiler are you using? surely you can check self-time instead of total-time, or tell it to ignore time spent in MultiFn.invoke

13:24 technomancy: amalloy: true

13:24 tbaldridge: amalloy: yeah don't redef, instead define a multimethod called -foo and then name the memoized version foo. That way you can call the right one depending on what you want.

13:24 amalloy: tbaldridge: yes, that was my advice, though i didn't weigh in on naming

13:25 tbaldridge: amalloy: I don't think each method gets named sanely though either.

13:25 justin_smith: amalloy: but then the situation where you want to find out where your bottleneck is, and it may or may not be the multimethod

13:25 tbaldridge: The compiler doesn't emit (foo-bar...) when you (defmethod foo :bar)

13:26 amalloy: i'd call it foo and foom, because how often do you get to write source code as onomatopoeic explosions?

13:27 that's a good point, tbaldridge. i guess you'd have to do something pretty gross make the profiler aware of what methods are taking the time. like, have each just delegate to a function, or something. yuck

13:28 tbaldridge: yeah, but I sonder if cursive integrates enough with intelij that YourKit would give good insight into this.

13:28 *wonder

13:29 * tbaldridge puts that on a list of things to do

13:31 hiredman: amalloy: we have this thing in our code at work call the spock-tock-lock, and sometimes things block on the spock-tock-lock, it makes for greating standups

13:32 justin_smith: hah

13:32 rasmusto: hm, if I bind some stuff with :or, it doesn't get put into the :as binding thing?

13:33 amalloy: rasmusto: no. :as refers to exactly the incoming object

13:33 rasmusto: amalloy: okay, thanks.

13:34 justin_smith: ,((fn [{a :a :or {a 0} :as m}] [m a]) {})

13:34 clojurebot: [{} 0]

13:34 rasmusto: my code is getting a bit dangerous with these optional arguments + defaults :s

13:34 justin_smith: rasmusto: instead of :or you can do a merge on the input, and then destructure

13:35 (fn [m] (let [m (merge default m) {a :a} m] ...))

13:35 rasmusto: justin_smith: I like that approach, thanks again

13:35 justin_smith: np!

13:35 S3thc0n: I stumbled over Haskell and noticed it is 'missing' Lisp's macros. After some pondering I wonder: For which constructs are they actually >needed< (whose functionality is not already built into a hypothetical rather extensive language)? Most examples I have seen are pretty basic, and everything I tried to come up with ends being just a function. (Not that I doubt it, but I wish to know.)

13:36 amalloy: or provide a more spartan API, and make your clients pass the optional arguments anyway. if they don't, you can (throw (IllegalArgumentException. "This is SPARTA!"))

13:36 TEttinger: haskell calls its metaprogramming "templates" IIRC

13:36 technomancy: S3thc0n: using macros to delay evaluation isn't necessary in a lazy language

13:36 amalloy: TEttinger: like lispers, i think haskellers call their metaprogramming "programming"

13:36 rasmusto: amalloy: make them be explicit, I think I like that

13:36 TEttinger: heh fair enough

13:37 justin_smith: rasmusto: if nothing else, you can have a strict layer with no implicit arguments or coercions, then a separate coercing layer

13:37 if nothing else that makes understanding ones own code much simpler

13:38 amalloy: template haskell exists, but it's way more heavyweight than macros. and, as technomancy says, less necessary in a lazy language

13:38 rasmusto: all the pieces are coming together now :)

13:39 S3thc0n: That's my point: Would a lazy Lisp (just hypothetical) with the basic constructs (let, pattern matching etc) still need macros (except for when the designers abandon it and newly appeared basic features should be implemented)?

13:39 amalloy: the primary feature of macros is controlling the evaluation of arguments, by putting them in a different lexical/dynamic context, or by evaluating them multiple times or whatever

13:40 justin_smith: that makes me think of another possible framing "macros are for doctor who's business, if you don't need to deal with alternate flows of time, or universes where things are parsed differently, you may not need them"

13:40 amalloy: in a lazy language, a lot of that wouldn't be necessary, but it's still nice, both for bootstrapping the language from a small set of primitives, and for letting users customize things

13:41 technomancy: S3thc0n: oh I see; interesting. probably the main one would be evaluating things in a different lexical context, like how the for macro's :while or :let stuff works.

13:41 llasram: And for locally reducing boilerplate

13:41 bbloom: amalloy: evaluating multiple times is the one that gets forgotten by lazy advocates

13:41 technomancy: but that's not strictly necessary; it's just map sugar

13:42 llasram: I think my most frequent use of macros is when I'm defining <n> of the same thing in the same place, and create a private, local macro to capture the pattern

13:42 amalloy: bbloom: well, of course in a truly lazy side-effect-free language that doesn't matter anyway

13:43 technomancy: probably heavy code-walking things like core.async couldn't be done in userspace, but I'm not very familiar with that

13:43 and that's not the kind of macro mere mortals should be writing anyway, so not having that capability built-in to the language isn't a big deal IMO

13:43 amalloy: since evaluating an expression multiple times always produces the same result, and has no other effects

13:44 bbloom: amalloy: except that's not really true, hence Control.Monad.Loops

13:44 S3thc0n: technomancy: That is exactly what I was thinking of.

13:44 amalloy: to meaningfully evaluate something multiple times in a pure, lazy language, you need it to be a function, and pass it different args; this is roughly the same as evaluating multiple times in a modified lexical environment

13:45 bbloom: but those don't evalaute the same thing multiple times!

13:45 bbloom: amalloy: sure, they thread a state variable you can't get at through

13:45 amalloy: right. which means they don't need to be macros

13:46 bbloom: amalloy: right, but laziness is orthogonal to purity. it's just that laziness is practically impossible to reason about without purity

13:47 amalloy: and you can't implement loops with laziness alone, you also need a trampoline of sorts, which in the case of haskell is provided by the runtime for monads

13:47 technomancy: S3thc0n: I can't think of any cases of macros you'd write in application code anyway

13:47 amalloy: definitely. i guess i didn't say soon enough that i was talking about a pure language as well as a lazy one

13:48 bbloom: amalloy: our discussion was more for the sake of S3thc0n than either of us anyway :-P

13:48 justin_smith: in impure lazy lang would be kind of a fun INTERCAL style esolang actually

13:48 amalloy: bbloom: you sound so noble! you know we were just arguing because it's fun

13:48 bbloom: amalloy: sshhh

13:49 S3thc0n: bbloom: You may very well continue, I'm extracting knowledge through that. o.o

13:49 amalloy: bbloom: i don't understand what you mean by being unable to implement loops with just laziness

13:49 justin_smith: you could have like a "supervisor" construct, that forces the default lazy functions to grudgingly process some of their inputs at a semi-nondeterministic rate...

13:49 amalloy: obviously tail recursion is enough to implement loops, so you must mean something i don't understand

13:49 wink: hm, is there an easier way for foo-bar -> "Foo Bar" than this monstrosity? (let [p (string/split (:class c) #"-")] (apply str (map (fn [x] (str (string/upper-case (first x)) (apply str (rest x)) " " )) p)))

13:50 amalloy: wink: ##(doc clojure.string/join)

13:50 lazybot: ⇒ "([coll] [separator coll]); Returns a string of all elements in coll, as returned by (seq coll), separated by an optional separator."

13:50 justin_smith: wink: camel-snake-kebab may help you?

13:50 https://github.com/qerub/camel-snake-kebab

13:50 wink: thanks both, checkin

13:51 bbloom: amalloy: tail recursion isn't lazy

13:52 amalloy: well... i guess i can be

13:52 amalloy: monads certainly don't enter into it. you can write a lazy looping function without any monads

13:52 justin_smith: wink: oh, you would need to fork c-s-k and add a [capitolize capitolize " "] rule here for it to help you https://github.com/qerub/camel-snake-kebab/blob/stable/src/camel_snake_kebab.clj#L27

13:53 so probably never mind that - though c-s-k *should* provide that, as far as I am concerned

13:53 wink: hehe

13:53 amalloy: let f 0 = []; f x = x:(f (x - 1))

13:53 justin_smith: s/capitolize/capitalize/g

13:53 amalloy: it's the automatic thunking that makes lazily looping possible, not monads

13:55 bbloom: amalloy: i think you're making sense, but i'm not going to think about it too hard b/c my brain is still exhausted from yesterday

13:55 amalloy: goodness. what did i miss yesterday?

13:55 bbloom: amalloy: https://twitter.com/BrandonBloom/status/455452491304685568

13:56 justin_smith: you are in a twisty maze of stack-frames, all alike

13:56 bbloom: GO EAST

13:56 yedi_: does anyone have example ansible scripts for deploying clojure webapps

13:56 technomancy: oh man

13:56 justin_smith: your inspector has not been implemented yet, you are likely to be eaten by a Grue

13:56 technomancy: I started playing zork with my kids last week

13:57 enquora: anyone here using clara-rules?

13:57 technomancy: that damn maze is like ... an object lesson in life's unfairness

13:57 llasram: technomancy: The one you solve by leaving a trail of your most precious belongings?

13:58 technomancy: "I went east and then west and I should be back where I started but I'm not; what is the deal" / "listen buddy, what is this 'should'? the world doesn't owe you anything."

13:58 (not actually how I talk to my kids but you get the idea)

13:58 justin_smith: I once solved a non-euclidean self-modifying maze in a MUD by marking each room in a binary system devised of presence or absence of multiple easily found objects that could be left on the floor

13:58 amalloy: justin_smith: maybe it makes sense for c.j.io/reader to interpret a string as a url, for symmetry with c.j.io/writer, which clearly can't interpret a string as anything but a place to write to

13:58 technomancy: llasram: right; and then sometimes the thief steals your landmarks for kicks.

13:58 llasram: OH RIGHT

13:58 I forgot that part

13:59 justin_smith: {:mushroom 1 :magic-light 2 :dried-meat 4} and thus mark rooms...

13:59 llasram: Unless you kill him first? But maybe you can't do that until later

13:59 justin_smith: amalloy: I can see the logic, but not the usefullness

13:59 llasram: amalloy: Of course, io/copy with a source string copies the string content. Fun times

14:03 mikerod: so, are there no functions exposed in clojure.core that would allow me to test if a Symbol resolves to a class name or not?

14:03 without throwing an exception

14:04 S3thc0n: llasram: Good idea killing him, you can mark the floor with his blood and guts :3

14:04 mikerod: I think I see this idea @ Compiler$HostExpr#maybeClass() but it is a private method :)

14:04 llasram: mikerod: Why do you need this?

14:05 mikerod: llasram: DSL stuff

14:05 llasram: fairly long story

14:05 llasram: I want to fully-qualify symbols without compiling things.

14:06 justin_smith: ,(try (resolve 'java.io.Files) (catch ClassNotFoundException e false))

14:06 clojurebot: justin_smith: No entiendo

14:06 mikerod: llasram: dealing with the static member access via interop macros

14:06 (Instant/now)

14:06 ambrosebs: ,(resolve 'java.io.Files)

14:06 clojurebot: #<ClassNotFoundException java.lang.ClassNotFoundException: java.io.Files>

14:07 ambrosebs: ,(resolve 'java.io/Files)

14:07 clojurebot: nil

14:07 ambrosebs: of course.

14:07 justin_smith: ahh

14:08 ambrosebs: pretty sure this is abug

14:08 llasram: mikerod: I think you'll probably just want to Class/forName and catch the exception

14:08 justin_smith: ambrosebs: which behavior being a bug? the one where the class is not there?

14:08 ambrosebs: justin_smith: (resolve 'java.io.Typo) should return nil I think

14:08 resolve returns (U nil Var)

14:08 resolve returns (U nil Var Class)

14:08 llasram: mikerod: Although it honestly seems like a bad idea to do a different thing w/ a symbol based simply on whether or not a class named by it exists

14:09 justin_smith: llasram: yeah, good point/ Class/forName is more direct than turning the string into a symbol and resolving

14:09 tobani: , (resolve 'java.io/Typo)

14:09 clojurebot: nil

14:09 llasram: I think it's because the symbol has a namespace, and thus cannot be a class

14:09 justin_smith: tobani: but that is not a class, it is a function in a nonexistent ns

14:11 tobani: Yeah that was me thinking "is there a Files class in java8 or...."

14:11 justin_smith: I should have used a more obvious typo

14:12 Bronsa: ambrosebs: yeah it looks like a bug

14:13 ,(doc ns-resolve)

14:13 clojurebot: "([ns sym] [ns env sym]); Returns the var or Class to which a symbol will be resolved in the namespace (unless found in the environment), else nil. Note that if the symbol is fully qualified, the var/Class to which it resolves need not be present in the namespace."

14:13 Bronsa: should definitely return nil

14:14 bbloom: ,(def ^{:xx (prn 1)} f) ; whoa

14:14 clojurebot: 1\n1\n#'sandbox/f

14:14 bbloom: apparently def evals the metadata!?

14:14 Bronsa: bbloom: yeah, it's by design

14:15 bbloom: Bronsa: interesting. why?

14:15 Bronsa: bbloom: however it's a bug that it evals the metadata twice

14:15 bbloom: heh

14:15 Bronsa: there should already be a ticket in JIRA for that

14:15 * bbloom is fixing eclj b/c his :arglists were wrapped in (quote ...)

14:15 Bronsa: bbloom: don't talk to me about :arglists

14:16 bbloom: lol

14:16 tpope: oh bbloom 90% of the clojure.core's in fireplace are gone now

14:16 bbloom: tpope: that's both great news AND bad news b/c it means i need to port my changes :-)

14:16 S3thc0n: Wow - I just realized that with runtime macros, one could implement functions as a macro which replaces the variables in the function body's AST. And macros are special functions. Macroception?

14:16 tpope: using tricks like "eval in the user namespace"

14:17 bbloom: tpope: what's that mean exactly?

14:17 tpope: and tricks like "who the fuck would shadow macroexpand-1 I mean seriously"

14:17 bbloom: lol shit. b/c i might do that lol

14:17 hell, doesn't clojure.walk do that?

14:17 Bronsa: bbloom: I don't know *why* it's evalauted though, I just know that it's explicitely stated in http://clojure.org/special_forms#Special%20Forms--(def%20symbol%20init?) that it will be

14:17 tpope: jesus man you're the reason I got defensive about clojure.core in the first place

14:17 bbloom: S3thc0n: if you're interested in "runtime macros" i highly recommend checking out a language called "Kernel" & fexprs

14:18 Bronsa: weird. *shrug* ok

14:18 S3thc0n: bbloom: Thanks for the hint :)

14:18 I've never liked the differentation between runtime and compile time anyway :b

14:18 Bronsa: bbloom: I guess it's convenient for :inline/:inline-arities though

14:18 bbloom: Bronsa: i split def in to two primitive effects: :declare and :define

14:18 technomancy: compile time is just a subset of runtime

14:19 tpope: by "eval in the user namespace" I just mean I'm assuming that you'd have to be a pretty big asshole to shadow something in user

14:19 Bronsa: bbloom: huh? what are the benefits?

14:19 ambrosebs: tpope: if relevant: clojure.tools.analyzer/macroexpand-1, clojure.tools.analyzer.jvm/macroexpand-1

14:20 bbloom: tpope: so if i evaluate an individual form, you somehow evaluate that in user? what if i'm evaluating it in a ns that has extra stuff in scope?

14:20 Bronsa: https://github.com/brandonbloom/eclj/blob/master/src/eclj/env.clj#L64-L73

14:21 Bronsa: b/c i implement it in terms of intern and intern doesn't have a way to differentiate nil from unbound

14:21 Bronsa: lol I didn't even know intern took a val argument

14:22 bbloom: makes sense

14:22 tpope: bbloom: individual forms get evaled with no extra wrapping

14:22 bbloom: tpope: they get evaluated in the current namespace tho, right?

14:22 tpope: that (try (eval ...)) nonsense is long gone

14:22 yeah the current namespace

14:22 bbloom: tpope: ok, so what if the current namespace defines macroexpand-1 ?

14:22 tpope: then what the fuck is wrong with you

14:23 bbloom: tpope: Bronsa, ambrosebs, and i have all done that :-P

14:23 amalloy: ,(def macroexpand-1 (partial list 'macro!))

14:23 clojurebot: #<CompilerException java.lang.SecurityException: denied, compiling:(NO_SOURCE_PATH:0:0)>

14:24 amalloy: :(

14:24 bbloom: for eclj, i have to patch up eval, case, defprotocol, deftype, ns, and reify b/c all of those are basically compiler primitives in disguise

14:25 rasmusto: read edn from a resource (edn/read-string (slurp (resource filename))) ?

14:25 justin_smith: I love case for providing such a straightforward performant low level functionality, I hate it for making a special case exception for what (...) means

14:25 tpope: macroexpand-1 feels like a pretty frivolous extra to worry about anyways

14:26 gtrak: as far as I can tell, this discussion is about fireplace eval'ing stuff. Is it an option to implement this in an nrepl middleware? We shouldn't be writing new tooling code that gets eval'd except as a stopgap.

14:26 at least in theory

14:26 justin_smith: rasmusto: (edn/read (resource filename)) maybe?

14:26 rasmusto: justin_smith: edn/read wnats a pushback reader

14:26 tpope: lol don't talk to me about middleware mr. my middleware sends map data as lists because that makes the elisp easier

14:26 justin_smith: or do we need to turn resource into a reader first to make that work?

14:27 (-> filename resource reader edn/read) ?

14:27 Bronsa: justin_smith: reader doesn't return a PBR

14:27 justin_smith: never mind then :)

14:27 rasmusto: justin_smith: its a bufferedReader

14:28 justin_smith: there should totally be a clojure.java.io/hipster function that returns a PBR

14:28 tpope: seriously the fact there's generic ops like "info" that send data hand tailored for elisp makes the whole notion a bit of a joke

14:28 rasmusto: justin_smith: cloblue/ribbon

14:28 bbloom: tpope: here's my hacks btw: https://github.com/brandonbloom/vim-fireplace/compare/master...eclj

14:28 gtrak: tpope: I have a ticket out there to fix that :-), just backwards compatible for now b/c whatever..

14:28 I haven't heard any complaints.

14:29 don't point at me! tpope: https://github.com/clojure-emacs/cider-nrepl/issues/27

14:29 rasmusto: justin_smith: I'll use string-pushback-reader I guess

14:29 string-push-back-reader*

14:30 tpope: gtrak: whew at least we're on the same page there

14:30 justin_smith: rasmusto: what ns is that in?

14:30 gtrak: I had to debug the elisp bencode implementation to get this to work at all.

14:30 believe me, I have zero preference for elisp

14:30 rasmusto: justin_smith: clojure.tools.reader.reader-types

14:32 justin_smith: I might be on the wrong track here though, since slurp + memoize seemed to work OK

14:32 gtrak: tpope: if there's any other blockers for you, you should let me know.

14:32 kinda working in a vacuum here.

14:32 tpope: gtrak: my other piece of feedback is that you're sending absolute paths, whereas I already have classpath searching locally and would prefer to use that, because it will even work in cases like drawbridge on a remote server

14:33 gtrak: I get sending absolute, but could we also send classpath relative if available?

14:33 justin_smith: rasmusto: extra credit, have the internal function take two args, file path and timestamp, and top level function passes in the file you ask for, and its modification time

14:33 then memoize the internal, of course

14:33 gtrak: tpope: in that case I'd probably add an extra attribute to the response.

14:33 tpope: gtrak: yeah exactly

14:33 gtrak: I'll make an issue for it

14:34 rasmusto: justin_smith: hm, clojure.tools.reader.reader_types.PushbackReader isn't a java.io.PushbackReader I guess

14:34 justin_smith: ouch

14:34 tpope: gtrak: I already hooked up the stracktrace and complete ops

14:34 gtrak: tpope: I'll call it 'resource', I think.

14:35 file-classpath doesn't quite make sense

14:35 justin_smith: ,(java.io.PushbackReader. (io/reader (io/resource "project.clj")))

14:35 clojurebot: #<CompilerException java.lang.RuntimeException: No such namespace: io, compiling:(NO_SOURCE_PATH:0:0)>

14:35 tpope: yeah resource sounds much better than anything I can think of

14:35 TimMc: Is it some kind of sick joke that lein-voom is at 0.1.0-SNAPSHOT instead of a stable release?

14:35 llasram: nice

14:36 dbell: Anyone know what might cause a dirty take/put in core.async? #omproblems

14:36 mikerod: llasram: sorry, had a meeting...

14:36 justin_smith: (defn pbr [location] (java.io.PushbackReader. (io/reader (io/resource location))))

14:36 rasmusto: that function should make it easy?

14:37 llasram: mikerod: How dare you walk in the way of the channel dispensing sage advice?

14:37 mikerod: llasram: so I tried to catch up with what all was said. and the consensus is I have to try-catch a Class#forName ? booo

14:37 llasram: I know, I'm sorry :(

14:37 rasmusto: justin_smith: yep, shaves off about 1s from the slurp + read-string version

14:37 llasram: mikerod: haha. I don't know about consensus -- that's just my suggestion

14:37 justin_smith: rasmusto: oh, nice

14:37 mikerod: I was surprised that `resolve` throws exceptions on me for classes

14:38 gtrak: tpope: I think the map/list thing will be pretty easy. It's just at the top-level. I'll let you know when it's ready to go, I have to implement it in cider itself first.

14:38 justin_smith: mikerod: consensus is that is a bug that should be fixed I think

14:38 llasram: mikerod: What's so bad about catching exceptions?

14:38 gtrak: make it work both ways, then pull the rug out

14:38 tpope: gtrak: any concerns about making the op backwards incompatible?

14:38 mikerod: justin_smith: ah I see

14:38 tpope: ah ok

14:38 llasram: mikerod: If you're concerned about the class-load-initialize behavior, you can always use the form which inhibits initialization

14:38 tpope: yeah I'll just hold out for the map implementation I guess

14:39 gtrak: tpope: cider hasn't had a real release since I started on this, and the plugin remains at SNAPSHOT, too.

14:39 mikerod: llasram: no initialize concerns for me. try-catch control flow just always looks a bit shady to me.

14:39 llasram: mikerod: *shrug* When the Java standard library gives you exceptions, you make exception-ade

14:40 mikerod: llasram: haha, +1 putting it that way

14:40 bbloom: tpope: gtrak: sorry, i'm not really following this conversation right now, but i just want to add that sometimes nrepl returns errors that fireplace can't parse

14:40 mikerod: for putting*

14:40 bbloom: i'm not sure when that happens or why

14:40 tpope: it happens at .value[0] in the nrepl.vim code

14:40 basically, value isn't a vector sometimes... *shrug*

14:40 gtrak: bbloom: yea, I'd need more detail, like a printout of the nrepl response.

14:41 bbloom: gtrak: i can get that, 1 sec

14:42 gtrak: i get:

14:42 Exception not caught: nREPL: namespace not found

14:42 which is probably a mix of clojure & vim errors

14:42 also, i have a patched nrepl, so it could be me being an idiot somehow

14:43 gtrak: my patch is here: http://dev.clojure.org/jira/browse/NREPL-50?page=com.atlassian.streams.streams-jira-plugin:activity-stream-issue-tab

14:44 gtrak: ah, yea we don't do anything at all to handle top-level exceptions, emacs will just freeze when that's the case :-). Barring a general fix for that, if you have specific inputs that cause it, we can add a testcase and fix for the specific op.

14:44 bbloom: gtrak: seriously? sheesh.

14:45 tpope: there are definitely errors that fireplace can't handle either

14:45 gtrak: Once I understand the ramifications, I'll figure it out, but I'm still pretty new to nrepl and elisp :-)

14:45 tpope: in particular when nrepl craps out midway through serializing a response

14:45 gtrak: I just _really_ wanted the cljs thing to work.

14:45 tpope: bbloom: I don't have time to dig in now but feel free to make issues

14:46 gtrak: I'll add an issue for the general exception handling, I don't think there is one yet, but I've been aware of it.

14:46 bbloom: tpope: i only didn't file an issue b/c i don't have enough info to make a sensible bug report

14:46 gtrak: bbloom: should still get me the bad inputs, we should handle them if they make any sense.

14:47 or often, returning nil is fine.

14:47 better than an exception

14:47 bbloom: gtrak: i think it has to do w/ stack overflows in eval. basically if there is no stacktrace available, then tpope's code will do pst and gets no result to parse

14:47 gtrak: returning nil is NOT FINE. that's super confusing lol

14:48 gtrak: bbloom: depends :-). I think it's sensible if you're asking for a var that doesn't exist?

14:48 tpope: bbloom: skimming your changes, it's a mixture of happily moot and merge confict

14:48 gtrak: or we could just implement http ;-)

14:49 bbloom: tpope: which parts are which? / how can i help?

14:49 it's working good enough for me right now, so i probably won't bother attempting to reconcile your changes until after i get a little bit more stuff working in my own code

14:49 tpope: bbloom: the stacktrace stuff is hopefully moot. that's where I just evaled in the user ns

14:49 bbloom: one off runner definitely moot

14:50 bbloom: oh and for stacktrace you can just provide a stacktrace nrepl op

14:50 matching the cider nrepl one

14:51 bbloom: tpope: i can?

14:51 tpope: honestly, most of this stuff is only your problem b/c nrepl is not as general purpose as promised

14:51 tpope: well if you provide one fireplace will use it

14:52 can't really speak to your abilities

14:52 bbloom: i didn't write nrepl :-P

14:52 gtrak: tpope: bbloom: I've had similar problems recently with collisions between our own stacktrace stuff and the CLJS setup. still thinking about it.

14:52 like.. somehow the browser JS engine ends up evaling clojure pst code :-).

14:52 and totally screws up the repl.

14:53 bbloom: gtrak: yeah, clj + cljs + eclj = enough differences to design sensible enhancements

14:53 gtrak: I'm guessing that's because it's trying to eval it on the actual repl session instead of the tooling session to take advantage of dynamic vars *e.

14:53 the answer is, don't eval.

14:53 hence why I jumped into this :-)

14:53 bbloom: gtrak: for stack traces?

14:54 the whole damn point is that i wrote a fucking eval function! :-P

14:54 gtrak: ah, well, that might be interesting.

14:55 You're saying you want eclj eval with nrepl?

14:55 tpope: my use of eval is way down and once the info op is stable it'll basically just be frivolities

14:55 gtrak: maybe you should look at how piggieback implements it for cljs: https://github.com/cemerick/piggieback/blob/master/src/cemerick/piggieback.clj#L126

14:56 well, it's somewhere in there

14:56 bbloom: gtrak: i shouldn't need to write a plugin to swap out a single function. that's just silly

14:56 tpope: eval for macroexpansion seems pretty benign for example. it's basically just a shortcut to type out (macroexpand-1 ...) for you

14:56 we're not evaling to query, just helping the user to interactively eval

14:57 bbloom: tpope: i know that fireplace does macroexpand, but for some reason i never use it... probably should

14:57 tpope: I don't really use it either

14:57 bbloom: here i am, typing out macroexpand like a sucker

14:57 gtrak: bbloom: 'eval' is an op in nrepl, it's more complicated than that, but yea I guess you could use whatever to call a function.

14:57 the nrepl eval supports interruption and some other stuff

14:57 bbloom: gtrak: clojure.main/repl has an eval argument, so i supply it :-P

14:57 seems to work for me

14:59 gtrak: I'm not sure I understand the use-case, but that won't be first-class in nrepl terms.

15:00 i mean, you wouldn't want to replace clojure's eval for the whole process.

15:00 unless you do, but that sounds bad

15:01 bbloom: gtrak: i changed fireplace to look at the file extension. if it's clj, it does nothing different. if the ext is eclj, then it passes :eval 'eclj.core/eval

15:01 that's all

15:02 Bronsa: justin_smith: mikerod btw I opened a ticket for the ns-resolve bug

15:02 mikerod: Bronsa: awesome, I'll watch that one

15:03 sveri: hi, I am trying to parse some datomic data, especially the instant type, which comes as a standard date string. From the server I get some edn back, but when I try to display the date I see nothing, not even an error, however, it works with different attributes: this is the code: http://pastebin.com/VP1yQjRZ

15:04 gtrak: bbloom: ah, ok. weird :-). does fireplace use that for something?

15:04 bbloom: gtrak: no. i'm writing a clojure interpreter

15:04 gtrak: and i wanted it to work in vim

15:04 and now it does w/ my various patches/hacks

15:05 amalloy: sveri: i mean, you're trying to embed a time/date object into your dom. presumably you want to format it as a string of some kind

15:05 sveri: amalloy: are there helper functions in cljs available for this?

15:06 amalloy: also you seem to not be passing enough args to map? like, your paste is missing stuff. you have (apply dom/div nil (map #(...)))

15:07 sveri: amalloy: i left out the calls around that are not needed for the paste, however, calling a different keyword on the map it works as expected

15:08 gtrak: tpope: is the map thing only an issue in the response, or the request, too?

15:09 bbloom: Bronsa: ok eclj now evaluates var metadata... ONCE :-)

15:09 tpope: gtrak: I would much prefer to send a map for associative data, yes. I don't remember noticing any ops that forced me to send lists

15:10 gtrak: tpope: yea, I just haven't traced the request code yet, somehow it magically ends up as a map once it hits my middlewares :-).

15:10 but I'm not sure what it starts out as

15:11 tpope: so the top level structure seems to always be a map. I don't think any cider-nrepl ops take a nested structure?

15:11 gtrak: yea, I don't think there's a reason for it yet

15:12 but arglists at least is an example of some nested data

15:12 in the response

15:12 tpope: oh yeah that. I'm wondering if that might be better sent as a string?

15:13 I mean it depends what you want to use it for, but the only use case I have is display

15:13 gtrak: I'm back and forth on that. elisp ends up reading it, but it's a bit weird, since [] encodes as nil. I was thinking of adding an arglists-str attribute too.

15:13 tpope: yeah maybe both is the safe bet

15:13 whodidthis: any idea how to add index to maps in a vector like [{:t :a} {:t :c}] -> [{:t :a :index 0} {:t :c :index 1}]

15:14 amalloy: &(doc map-indexed)

15:14 lazybot: ⇒ "([f coll]); Returns a lazy sequence consisting of the result of applying f to 0 and the first item of coll, followed by applying f to 1 and the second item in coll, etc, until coll is exhausted. Thus function f should accept 2 arguments, index and item."

15:15 whodidthis: whoa, clojur has everything, thanks

15:16 tpope: gtrak: how are you formatting docs over in emacs? just stitching togethr the symbol, arglists, and doc string by hand?

15:16 with an arglists str that's pretty straightforward

15:17 btcNeverSleeps: when using clojure.test, is there an easy way to shortcut out of a deftest as soon as on test fails? e.g. I'd like (deftest test-ff (is false) (is false)) to report only one failure, not two.

15:17 s/as on/as one/

15:18 gtrak: tpope: it actually uses the data.

15:18 it used to 'read' the string.

15:18 but that's an elisp read on clojure data (eww..)

15:19 tpope: yeah sounds treacherous

15:20 gtrak: so, we got rid of the 'read' just a couple days ago, now I'm going to add the string representation back for you :-)

15:20 there's still some work to be done, the cljs arglists end up looking weird, I have to figure that out.

15:21 like '([113 117 111 116 101] [(coll k v) (coll k v & kvs)])'

15:21 for assoc

15:21 um.. come to think of it, pretty sure that first one is quote

15:22 (map int "quote")

15:22 ,(map int "quote")

15:22 clojurebot: (113 117 111 116 101)

15:22 gtrak: haha

15:22 tpope: brilliant

15:27 hyPiRion: gtrak: I know how you just knew by looking at the decimal representation

15:27 /s/know/love/

15:28 gtrak: hehe, tbh I'd seen it quoted before a couple months ago, just made the connection (five of them).

15:37 gfredericks: people who like non-namespaced maven artifacts: my build just broke and you're all individually responsible

15:38 llasram: gfredericks: I apologize for the mistakes of my past selves

15:39 gfredericks: (inc llasram)

15:39 lazybot: ⇒ 21

15:43 hyPiRion: gfredericks: like, unnamed packages?

15:43 gfredericks: hyPiRion: no like [foo "0.1.0"]

15:44 hyPiRion: gfredericks: oh, you're welcome then

15:57 xeqi: gfredericks: I'm interested to hear more

15:58 gfredericks: xeqi: somebody internally made a clojure library named [foo "0.1.1"] and put it on our internal maven repo

15:58 justin_smith: lol

15:58 gfredericks: 6 months later an OSS organization decides they like that name too

15:58 so they put [foo "0.1.1"] on clojars

15:59 xeqi: haha

15:59 justin_smith: I hope the package was actually called foo

15:59 like literally

15:59 technomancy: solution: never use libraries that aren't oss

16:00 bbloom: justin_smith: the new version of the package is foo.bar version 3.1.4

16:00 gfredericks: justin_smith: it wasn't

16:01 $latest foo

16:01 lazybot: No project by this name exists on clojars.

16:01 xeqi: gfredericks: becareful, the foo on clojars might of had secret compiled code that uploaded everything on your hardrive to some hackerz server

16:02 technomancy: seriously, with all the hassle around private repositories it's really a wonder that anyone bothers writing libs that aren't OSS in the first place

16:03 pjstadig: gfredericks: maybe you shouldn't have had an internal library named foo, and instead one called namespace/foo :-p

16:03 xeqi: not that namespacing the internal one prevents someone from using the same group/artifact combo in a public server

16:04 pjstadig: if namespace == [YOUR COMPANY'S DOMAIN NAME] probably not likely

16:04 gfredericks: pjstadig: yes I agree and that's how I fixed the issue

16:04 I didn't decide to name it that in the first place

16:04 pjstadig: but naming things in a global namespace is hard

16:07 justin_smith: (defproject `(symbol (str (java.util.UUID/randomUUID) / "project-name")) ...)

16:08 gfredericks: technomancy: I think we have some people that use the private repo for app deployment

16:08 pjstadig: YES!

16:08 turbofail: shouldn't that be a ~?

16:08 justin_smith: turbofail: yeah, also / should have been "/" or \/

16:09 technomancy: gfredericks: I've seen people do that but do not understand the motivation at all

16:09 I guess if you have regulatory concerns about S3 or something?

16:10 justin_smith: turbofail: also, the unquoting does not kick in until after the version number, it was a mock suggestion so whatevs

16:10 gfredericks: or availability? I dunno

16:10 technomancy: some companies might consider amazon to be a competitor :P

16:11 technomancy: it takes a lot of hubris to think you can do better than S3 though

16:11 justin_smith: because we need to keep all the client's private credentials in a clojure library as plaintext

16:11 turbofail: lol

16:11 justin_smith: and a private repo keeps that safe, right? /s

16:11 gtrak: technomancy: I don't think that's what he's saying..

16:11 arrdem: in registers, everything is plaintext

16:11 pjstadig: justin_smith: they use https, so by definition they are safe

16:11 gtrak: it doesn't take hubris to not give a competitor control over stuff you care about :-)

16:11 justin_smith: oh, yeah, I forgot

16:12 technomancy: gtrak: meant re: availability specifically

16:12 justin_smith: carry on then

16:12 arrdem: pjstadig: low blow

16:13 gfredericks: technomancy: the more datacenters it takes to deploy your app...

16:13 technomancy: gfredericks: still though, why not just scp or something?

16:14 all the repository-specific logic isn't being used for single uberjars

16:14 gfredericks: no idea

16:14 setting up a private repo is still good for redundancy though

16:14 technomancy: sure, as a cache

16:14 gfredericks: right

16:15 technomancy: I guess if you already have it up as a cache, it's not much additional extra complexity

16:15 but it's complecting caching and publishing zomg

16:15 justin_smith: that's been traditional for analog publishing

16:15 technomancy: (protip: easy way to convince clojure users something is a bad idea: accuse it of complecting)

16:16 justin_smith: technomancy: that's complecting good programming advice with social engineering advice

16:16 technomancy: oh noes

16:16 TEttinger: technomancy: I've linked people to the keyboard pants concept after they said they'd paid $200 for a keyboard

16:17 technomancy: TEttinger: hehe; nice

16:17 FWIW I haven't been doing that recently, but maybe there is more research to explore in that field

16:18 TEttinger: I wonder if you could use similar technology to those laser keyboards and track finger movement directly

16:18 keygloves

16:19 technomancy: nah, typing without tactile feedback is a nightmare

16:19 TEttinger: who said no tactile feedback?

16:19 you could have a pad at the fingertip

16:19 justin_smith: technomancy: easily fixed the way cellphones do it: install a vibrator in the pants

16:19 rasmusto: I want haptic gloves

16:19 justin_smith: technomancy: bonus, secondary market :)

16:20 technomancy: TEttinger: maybe if you cloud vary the strength of the feedback based on hew far from the center of the "key" you struck

16:21 * rasmusto wants http://www.cyberglovesystems.com/products/haptic-workstation/photos-video

16:21 amalloy: i wonder what cyborglovesystems.com would be like

16:22 justin_smith: depends where you break the words

16:22 cyborg love systems

16:22 rasmusto: haha

16:23 amalloy: that's really the only sensible place to break the words, which is why i thought it was funny

16:23 rasmusto: (inc amalloy)

16:23 lazybot: ⇒ 98

16:38 TimMc: hagelborglovesystems

16:39 rasmusto: ha! gel borglo vesys tems

16:40 Bronsa: lol

17:02 blake__: Is there a preferred way to indicate a function parameter when the function has a specific, known task (as opposed to being highly abstract). Like, if I need a function that foos bars, should I code the formal parameter as "bar-fooer-fn" or "bar-the-foo" or...is there a "best practice" here?

17:03 justin_smith: blake__: I typically just call it f

17:03 and make sure my comment and code are clear as air

17:03 blake__: 'k.

17:04 justin_smith: actually - maybe "half the time" - if there is an extremely straightforward name, I just go for that

17:04 like if it describes something that stores data, I call it "save"

17:04 I like to name it the verb, and not "doer of the verb"

17:05 blake__: but also not "verb-the-noun"...

17:05 justin_smith: no

17:05 but that is style of course, I am sure there are many good ways to do it

17:06 bbloom: blah-fn is common when you want to differentiate from blah the macro

17:06 blake__: Sure. I'm not gonna marry it, I just don't want to bring over some other language-style, like nounReceiveVerbWhenDesired.

17:07 devth: twi

17:07 blake__: bbloom: Good tip, thx.

17:07 devth: mt

17:07 TimMc: devth: Are you a cat?

17:07 mdrogalis: Hahah.

17:07 That took me a sec. :P

17:08 amalloy: one example of a bad way would be to name it after the type signature it would have in haskell. (defn frobnicate [data lparen_a->b->a_rparen->a->lsquare_a_rsquare->a] ...)

17:08 devth: TimMc: nope, alfred user trying to switch to twitter window :)

17:09 blake__: amalloy: I can't even.

17:09 amalloy: hey, where does the "mt" acronym for like "oops, wrong channel/window/person" come from?

17:09 devth: mistell

17:09 TimMc: huh

17:09 amalloy: okay. that's what i guessed, because i'd only seen it in games before. but then you brought it here

17:09 rasmusto: wtb a better irc client, pst

17:10 devth: i figured it was appropriate in irc

17:10 technomancy: http://nedroid.com/2012/07/b-r-webcoms/

17:10 TimMc: I wonder if I could set up irssi to require me to type /say in front of messages.

17:10 justin_smith: (inc rasmusto)

17:10 lazybot: ⇒ 7

17:10 Bronsa: TimMc: that would be horrible to use.

17:11 justin_smith: cast fireball TimMc

17:11 :( didn't work

17:12 amalloy: Bronsa: he would add a keyboard macro to automatically prefix with /say

17:12 TimMc: prolly

17:13 blake__: Ultimately, probably ending up defeating the purpose...

17:13 oskarth: What's a good example of simple error handling in a Clojure library interacting with an API? Looking for good patterns I should adopt

17:14 gtrak: simple: happy-paths-only programming :-)

17:14 llambda: are there any best practices around testing om apps? (even cljs in general, for that matter)

17:15 justin_smith: oskarth: this may seem like a non-sequitor, but always name anonymous functions

17:15 (fn name-you-see-in-the-stacktrace [& args] ...)

17:15 oskarth: gtrak: definitely

17:15 justin_smith: makes figuring out what you broke so much easier....

17:16 oskarth: For example if I call a GET I might get three types of errors. The request might be malformed, I might lack access, the resource might not exist etc. How to uniformly report and propogate this in a sane manner?

17:16 true, good one

17:16 justin_smith: if only I could "name" comp - how hard would it be to make comp produce an anon fn with a name derived from the names of its args? is that totally absurd?

17:16 gtrak: oskarth: in our compojure api, I just slingshot throw an exception with the status code as part of the map, can pattern match on that if I feel like it.

17:17 oskarth: Right now I'm doing a cond for the different "levels" of error and returning a heterogenous map with an error key with optional details

17:17 justin_smith: slingshot rich exceptions are pretty cool, yeah

17:17 oskarth: what does slingshot throw an exception mean?

17:17 gtrak: I've got a middleware to catch and modify them, too

17:18 oskarth: well, actually you can use ex-info instead of slingshot for the throw side.

17:18 justin_smith: oskarth: slingshot lets you attach arbitrary clojure data to exceptions, that the one catching it can use

17:18 oskarth: oh, it's a library?

17:18 justin_smith: yeah

17:18 gtrak: slingshot can pattern-match the data on catch, yea.

17:18 ex-info's built into clojure

17:18 ,(ex-info {:a :b})

17:18 clojurebot: #<ArityException clojure.lang.ArityException: Wrong number of args (1) passed to: core/ex-info>

17:19 gtrak: see? it exists ;-p

17:19 devn: whoa. i hadn't seen the "Promote" button on clojars.

17:19 justin_smith: it's not a great way to do general purpose programming since exceptions are expensive and in the jvm truly are designed only for exceptional conditions, but it definitely beats switching on the type of the exception or something

17:19 gtrak: ,(ex-info "Message" {:a :b})

17:19 clojurebot: #<ExceptionInfo clojure.lang.ExceptionInfo: Message {:a :b}>

17:19 oskarth: what about "sane" errors, ie external ones? sometimes they are in a json body, and sometimes they are just in a "not authorized" response, any getting around cond-handling that?

17:20 justin_smith: oskarth: design the api to always return a map including error code and optional message, with a convenience function for the common "barf on it if it is weird" option

17:20 oskarth: slingshot looks interesting though

17:21 justin_smith: it's not necessarily my API ;) but yeah, something like that is what I'm doing right now

17:21 but manually constructing the map when it doesn't exist

17:22 gtrak: if you're just throwing stuff, I don't think slingshot actually helps you

17:22 oskarth: it seems like a lot of special case analysis though, with all the cond, and then higher up dealing with it in different ways

17:22 not sure what the shape of something better would look like

17:22 gtrak: in the impl of the lib, you don't need it, might be convenient for clients to use it

17:23 oskarth: some kind of rules system?

17:24 gtrak: as a lib user, in practice, I don't handle every error case, just the ones I'm interested in.

17:24 justin_smith: oskarth: maybe a multimethod or protocol for the returned data, and the client defines the implementation that is called in each error state?

17:24 oskarth: thats true

17:24 justin_smith: do you have any examples of code using such a pattern?

17:24 justin_smith: with sane defaults provided of course

17:24 hmm...

17:25 gtrak: justin_smith: how is that better than just wrapping the call? a little more obvious, imo.

17:25 justin_smith: I don't know that I've seen it, it was just an idea of how it could be done?

17:25 oskarth: seems reasonably, if I want to get a user and the thing I get back does not satisfy being a user, it might satisfy being a malformed request or something, and then it can be dealt with on a differnet level

17:25 justin_smith: gtrak: in a try block you mean?

17:25 gtrak: yea

17:26 or just funnel stuff into a common function

17:26 not necessarily a try-catch every time you use it

17:27 I guess, why worry about being clever here? I don't get it. if the data's available in a convenient way, that's enough.

17:27 oskarth: right now I have a handle-error function which creates a map for various cases

17:28 justin_smith: gtrak: I guess my motivation with the multimethod / protocol defining was that this way the client does not have to worry about the control flow (which is a common source of bugs, and could easily be defined once by the lib), and instead just implement each of the known possible cases

17:28 which could be a win for clarity overal

17:28 oskarth: having a protocol for the returned data is something I'll look into

17:29 gtrak: but that's global.. I'd probably just do a default impl that throws an exception :-)

17:29 justin_smith: oskarth: I didn't mean a protocol for the returned data, but a protocol defining the handlers that would be used on that data

17:29 gtrak: then you've got the issue of defining what exactly the protocol handles and doesn't handle. I'd want to see everything I could.

17:29 justin_smith: ahh

17:29 oskarth: hm

17:30 gtrak: ie, don't define spurious abstraction boundaries.

17:30 oskarth: I think a code example of something which has nice error handling/flow would be most useful at this point, if anyone knows of any

17:30 yeah I see that point

17:33 gtrak: nice is when I can easily see everything I want to see, clj-http is pretty good at that. https://github.com/dakrone/clj-http/blob/master/src/clj_http/client.clj#L143

17:33 dakrone: \o/

17:33 justin_smith: gtrak: I think you are right, I was trying to overengineer it

17:34 gtrak: dakrone: but I wonder if slingshot is necessary anymore :-)

17:34 justin_smith: also agreed, once i figured out how it worked, clj-http was nice

17:34 dakrone: gtrak: hmm.. when was ex-info added again?

17:34 gtrak: 1.4 I think?

17:35 ya

17:35 dakrone: hmm... wonder if it's time to drop 1.3 support

17:36 gtrak: i guess it's not hurting anything

17:37 technomancy: it'd be cool to see "how long did you take to upgrade" numbers for various clojure versions in the State of Clojure survey

17:37 I suspect 1.3 would score pretty low

17:37 gtrak: justin_smith: I guess my biggest criticism of multi-method/prot is simply action-at-a-distance

17:38 you end up splaying the dependency across your codebase, without the normal benefits of those things (extending existing/closed types)

17:49 blake__: How does one rename a lein project? Do I just manually go through and change all the directory and filenames?

17:50 hiredman: blake__: depends what you mean by rename

17:50 blake__: if you just want to change the artifact name in maven, just make the change to project.clj

17:50 if you want to keep the artifact name but change the namespace names, move the files and change the ns forms

17:50 and of course you can have various mixes of the two

17:50 blake__: I did a "lein new aproject" when I should've done "lein new bproject".

17:52 hiredman: if it is a brand new project you may as well just delete the typo and lein new again with the corrected version

17:52 devth: blake__: i like ack -l 'pattern' | xargs perl -pi -E 's/pattern/replacement/g'

17:52 blake__: So I have to go into project.clj, change "def project aproject" to "def project bproject" and ":main aproject.core" with ":main bproject.core".

17:52 hiredman: Yeah, not new.

17:52 (I've done that a lot =P)

17:52 hiredman: blake__: it realyl depends

17:53 blake__: devth: Thanks, I'll try.

17:53 hiredman: what are you trying to achieve

17:53 there are lots of orthogonal names that lein new generates

17:53 blake__: hiredman: Well, exactly the same thing I would've gotten had I done it right. I think it's just the project.clj and the core.clj?

17:53 hiredman: But I take your point; probably why there isn't a "lein rename".

17:54 justin_smith: in emacs you can do M-x rgrep to get hyperlinks to every usage of a regex within some directory subtree

17:54 hiredman: blake__: so you want to change the artifact id and all the namespaces

17:54 justin_smith: (then follow and edit, followed by renaming applicable files)

17:55 blake__: hiredman: yeah, I think so. I'm not sure what an "artifact" is.

17:55 hiredman: you might try using https://github.com/clojure/tools.namespace/blob/master/src/main/clojure/clojure/tools/namespace/move.clj to automate renaming namespaces

17:55 blake__: the artifact id is the name of the artifact in a maven repo

17:55 blake__: justin_smith: Fie upon your emacs!!! (I'm getting there. Slowly. Right now I'm doing a combination of "edln" and smoke signals.)

17:56 amalloy: i just found https://github.com/dakrone/cheshire/blob/master/src/cheshire/generate.clj#L67-L69 - can anyone think of a reason it might have been done this way, before i send a pull request to use (name k#)?

17:56 justin_smith: blake__: I am pretty sure sublimetext has a similar feature, vim may also

17:56 blake__: justin_smith: "edln" does not. =P

17:57 hiredman: amalloy: it may be for backwards compat

17:57 justin_smith: amalloy: also wanting the namespace part?

17:57 hiredman: amalloy: name used to throw on strings

17:57 justin_smith: ,(name :foo/bar)

17:57 clojurebot: "bar"

17:57 amalloy: hiredman: wow, really? that must have been before 1.2, which is when i showed up

17:57 rasmusto: ,(str :foo/bar)

17:57 clojurebot: ":foo/bar"

17:57 justin_smith: ,(.substring (string :foo/bar) 1)

17:57 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: string in this context, compiling:(NO_SOURCE_PATH:0:0)>

17:57 amalloy: i'm pretty sure cheshire isn't that old anyway

17:57 hiredman: amalloy: I could be mistaken

17:57 justin_smith: ,(.substring (str :foo/bar) 1)

17:57 clojurebot: "foo/bar"

17:58 justin_smith: I don't know if the different behavior with namespaced keywords is intented, but that would definitely change

17:59 amalloy: yeah, the a/b stuff looks like the only difference, and probably an important one

18:11 hm, i'm having trouble following the locals-clearing here. it seems like https://www.refheap.com/347dfa4f9706149b049631c34 should be able to run in constant memory, but if i actually run it that's not what happens. i think this is because when it seqs over my map, each k/v entry holds a reference to the whole map

18:11 is there a clever way i can use cheshire to do something like this, or do i have to do it by hand, like manually write "{x: 100, xs: " and then ask cheshire to write the object, and then write "}"?

18:13 dnolen_: amalloy: I don't see how that could work, there's no local to clear since the root of sequence is in the map and the map needs to be written.

18:13 dakrone: amalloy: see my experiments with doing that for a string field here: https://github.com/dakrone/cheshire/blob/master/src/cheshire/experimental.clj

18:14 amalloy: dnolen_: if the large object (here, xs) were the very last thing in the map, you could un-reference the map before you start writing xs

18:14 or even, perhaps, dissoc :xs from the map before you start writing it? that seems like it should work even ignoring field ordering

18:15 dnolen_: amalloy: yeah dissoc'ing would work, wasn't clear you could do this in your case.

18:16 amalloy: dnolen_: well, i mean cheshire could do that. in order to write m, first dissoc x, then write the value of x; then dissoc xs and write the value of xs; then discover that the remaining map is empty

18:16 that is, instead of seqing over the map, you recurse on it until it's empty

18:17 justin_smith: maybe a reduce?

18:17 no, never mind

18:19 dnolen_: amalloy: hmm, yeah seems like that would work? though honestly I'm surprised it doesn't just work if they seq the map first

18:20 amalloy: dnolen_: if you seq the map first, every entry in the map has a reference back to the root, right? and even if your "large" field is last, there's a thunk after it, which discovers that the map is actually nil so there's no work left to do

18:20 i'll put together a prototype and see if it improves behavior for my test case

18:21 justin_smith: what about (map vec {...}) ?

18:21 amalloy: dakrone: still holds onto it all, in the seq produced by map

18:21 because the first thing map does is seq it

18:23 justin_smith: ,(into [] {:a 0 :b 1})

18:23 clojurebot: [[:b 1] [:a 0]]

18:23 justin_smith: maybe not

18:25 dnolen_: amalloy: ok yeah I don't dissoc'ing is enough, you have to know that the original map is going to get collected.

18:25 amalloy: dnolen_: sure, whoever's above you has to not be holding onto the map as well

18:26 dnolen_: yeah

18:26 seems brittle

18:26 amalloy: dissoc is necessary but not sufficient

18:27 brittle seems a bit strong. cheshire should hold onto the object as weakly as it can (which should be enough to permit streaming output, i think); then it's your fault if you hold on too tightly as a user of cheshire, and you can fix it

18:27 dnolen_: amalloy: interesting, you could avoid this by cloning the value before printing it

18:27 amalloy: cloning, huh? how does that help?

18:28 oh, in the user/client code

18:28 maybe. i don't think it's actually necessary, but i'll finish my little proof of concept and see

18:28 dnolen_: amalloy: when you encounter a value if it's a lazy sequence / range you copy all the fields into a new thing first

18:28 dakrone: amalloy: interested in the results, lemme know how it goes

18:29 dnolen_: amalloy: you don't have clone in CLJ, but with-meta nil serves the same purpose

19:45 rhg135: hello everyone, is it just me or is the :nodejs target broken? keeps on saying cljs.nodejs being provided twice, i've tried 0.0-2202 and 0.0-2197 thanks

19:46 dnolen_: rhg135: gist of your project.clj

19:46 rhg135: k

19:48 dnolen_, https://gist.github.com/rhg/10690590

19:49 dnolen_: rhg135: that doesn't include any :build settings

19:49 rhg135: i'm building at the repl, dnolen_

19:50 dnolen_: rhg135: you still need to supply build settings

19:50 rhg135: (cljs.closure/build "server.cljs" {:optimizations :simple :target :nodejs :output-to "server.js"})

19:51 dnolen_: rhg135: in server.js do you see the nodejs ns provided twice?

19:53 rhg135: it won't output anything but the shebang with :target

19:55 dnolen_: rhg135: k, I can't look into this at the moment, I suggest bringing it up on the ClojureScript ML asking if someone else has encountered this with exact steps to repro.

19:56 rhg135: ok, dnolen_ wasnt sure if it was just me

19:58 dnolen_: rhg135: you might want to try :optimizations :whitespace to check if the offending namespace is actually provided twice

19:59 amalloy: so dakrone, i wrote https://github.com/amalloy/cheshire/commit/ee81c68986a55c06a43753e423c42596fe0b66d4, which has a few issues. (1) it doesn't work for java.util.HashMap, since it uses dissoc. you'd need a special case there. (2) i can't actually tell if it worked. in all my trials i don't see objects being held onto by cheshire, but they're still being held onto by swank somehow(???)

20:03 dnolen_: rhg135: fwiw can't repro w/ cljsbuild, helpful if you create a minimal repo with the problem that I can look at, thanks.

20:05 rhg135: hmm interesting ok

20:10 amalloy: dakrone: i see that you have some stuff in cheshire.generate that takes a JsonGenerator, which i imagined that i could use: create a generator, write some stuff to it, then write some more - so that i can try managing the gc reachability of my own objects

20:10 but you don't expose a way to actually get a jsongenerator

20:11 hiredman: amalloy: I wonder if it would be behave differently if it was a hash-map instead of an array map?

20:12 amalloy: hiredman: probably not. i think seqing over either of those maintains a pointer to the top-level map

20:12 but my patch makes it not keep a handle on the seq anyway, so it shouldn't really matter

20:15 seangrove: bbloom: Was it you talking about a debugger visualizing events traveling up the component tree?

20:15 Some time ago

20:16 perses: if i have empty graph G, and i want to do this, and want to add 1, 2, 3 one by one to g, my technique is: add-nodes (add-nodes (add-nodes G 1) 2) 3, add-nodes G node will return a new graph with nodes, how can i implement this?

20:18 arrdem: ,(doc alter)

20:18 clojurebot: "([ref fun & args]); Must be called in a transaction. Sets the in-transaction-value of ref to: (apply fun in-transaction-value-of-ref args) and returns the in-transaction-value of ref."

20:19 arrdem: ,(doc dosync)

20:19 clojurebot: "([& exprs]); Runs the exprs (in an implicit do) in a transaction that encompasses exprs and any nested calls. Starts a transaction if none is already running on this thread. Any uncaught exception will abort the transaction and flow out of dosync. The exprs may be run more than once, but any effects on Refs will be atomic."

20:20 arrdem: smelly code smells

20:22 rhg135: dnolen_, this is WEIRD, https://github.com/rhg/htmlscript actuall compiles now

20:25 perses: can anybody help?

20:26 crocket: Can clojure be used as a systems programming language yet?

20:26 cespare: If I find myself using update-in with a length-1 vector is there some other function I should be using instead?

20:27 gfredericks: cespare: not in clojure.core; various util libraries define update

20:27 I use prismatic/plumbing

20:27 cespare: gfredericks: ok thanks

20:29 bob2: crocket, no

20:29 arrdem: crocket: define "

20:29 systems"...

20:30 crocket: A language in which to write linux utilities and OSes.

20:30 rhg135: no

20:30 arrdem: and it may never be...

20:30 rhg135: the jvm isnt even a dep

20:30 dbasch: I have a rest API built using compojure. What’s the easiest/standard way to type-check the parameters on the server and create standard error messages (e.g “parameter X must be [type])?

20:31 technomancy: crocket: you'd be better off with racket or ocaml

20:31 crocket: racket?

20:31 arrdem: $google racketlang

20:31 lazybot: [The Racket Language] http://racket-lang.org/

20:31 technomancy: assuming your goal is "FP systems"

20:31 rhg135: or c

20:31 technomancy: ...

20:31 arrdem: rhg135: please... no...

20:31 rhg135: assuming you like pain

20:31 crocket: It seems rust will replace C if it is lucky.

20:31 arrdem: rhg135: we point people at Rust. Not at C. C needs to die.

20:32 gfredericks: ~C |needs| to die

20:32 clojurebot: c'est bon!

20:32 rhg135: agreed, but c will always be great self-harm

20:32 technomancy: C is perfectly cromulent...

20:32 for people writing code that needs to run on microcontrollers

20:32 ...assuming those people are allergic to forth

20:32 arrdem: rhg135: I mean if you want a sufficiently large shotgun with which to remove that pesky leg of yours...

20:33 or landmine...

20:33 rhg135: exactly arrdem !

20:33 arrdem: or artilery piece..

20:33 crocket: No

20:33 We need artificial general intelligence that writes programs instead of languages.

20:33 arrdem: crocket: but you could remove it so elegantly with a 155mm shell...

20:33 areyoufuckingkiddingme.jpg

20:33 crocket: Why do we toil on writing programs ourselves?

20:34 arrdem: because for four generations of researchers we haven't built an AGI

20:34 so this I say to you

20:34 crocket: http://arrdem.com/i/shoo.gif

20:34 crocket: arrdem, Fortunately, this time around, hardwares are about to emulate human brain.

20:34 Moore's law caught up with us.

20:34 arrdem: crocket: you believe that, if it gives you comfort.

20:35 rhg135: arrdem, i worked on https://bitbucket.org/rhg135/nice for a friend once, i havent recovered

20:35 arrdem: ^ Mr. Bennit, Pride and Predudice, Jane Austin.

20:35 crocket: arrdem, Humans will probably emulate human brains around 2030.

20:35 With super computers.

20:36 arrdem: crocket: great. call me in 14 years when you still can't build a sufficiently high resolution scanner to fulfull Ray's grand vision.

20:36 s/14/16/g

20:36 * arrdem mutters darkly about the rapture of the nerds and stumps off

20:36 crocket: arrdem, destructive brain scanning might be there around that time.

20:36 It means slicing a dead brain into sheets and scanning it.

20:37 arrdem: crocket: thank you, I'm sure everyone else in this channel has read The Singularity Is Near as well.

20:37 crocket: arrdem, Just a probable timeline.

20:37 might happen or might not.

20:38 timsg: anyone know offhand where the logic for clojure’s basic repl lives?

20:38 arrdem: unfortunately, this means that we have another 16 years of using handtools as master craftsmen before we can build an "A"GI to do the job better.

20:38 timsg: clojure.repl?

20:38 crocket: arrdem, yes at least 16 years.

20:38 long enough for my career.

20:38 hiredman: clojure.main and clojure.repl

20:39 arrdem: crocket: did you have a question or are you just being offtopic.

20:39 crocket: arrdem, I was just off topic.

20:40 arrdem, I just want to be lazy.

20:42 dbasch: To rephrase my question: I have a json api, so I get my parameters from the json-params map, and they are typed. I’d like to have a wrapper that type-checks them according to the spec for each call, and returns a 400 error if the types are not right. Does such a thing exist, or do I need to build it?

20:42 seangrove: dbasch: Check out prismatic's stuff. I don't know how it works with the compojure routing system though.

20:43 dbasch: seangrove: you mean fnhouse?

20:43 seangrove: Yeah, that and Schema

20:44 bob2: you could use it with liberator

20:44 if you have the patience

20:46 dbasch: seangrove: this guy is doing it with schema https://github.com/metosin/compojure-api/

20:46 there should be one preferred way to do these things though

20:47 crocket: arrdem, How good is clojure compared to other general purpose languages?

20:47 seangrove: crocket: ~7ish

20:47 crocket: 7ish?

20:47 seangrove: crocket: Often times blue though

20:47 timsg: arrdem, hiredman: thanks

20:47 dbasch: bob2: liberator seems like overkill for this

20:48 crocket: My company is a java/javascript shop, which is depressing.

20:49 seangrove, Your analogies don't really sink in my mind.

20:49 * seangrove mutters something about "Ask a nonsensical question..."

20:50 crocket: So how good is clojure?

20:50 arrdem: well, fellow lurkers, it seems that we warranted an upgrade! someone saw fit to send us a technically competent troll rather than a help vampire!

20:52 nightfly: crocket: Give it a try

20:52 Made a judgement about it on your own

20:52 If you've never worked with a lisp before it will probably be a very interesting experience for you

20:57 gtuckerkellogg: clojure+emacs+cider is awesome, but I could really use an Explain It Like I’m Six explanation of integrating clojurescript

20:58 or is it Explain it Like I'm Five? Anyway, the point stands

21:00 `szx: gtuckerkellogg: how about one of these? https://github.com/magomimmo/modern-cljs https://github.com/swannodette/lt-cljs-tutorial http://swannodette.github.io/2013/11/07/clojurescript-101/

21:03 gtuckerkellogg: ooh, i hadn't seen the port of the lighttable tutorial

21:03 bob2: arrdem, clojure is moving up in the world!

21:03 gtuckerkellogg: @thanks `szx

21:03 `szx: np

21:06 technomancy: gtuckerkellogg: I wrote the original code behind cider and I'm still confused by all the stuff that comes up when people try to debug their cljs repls

21:07 gtuckerkellogg: that's reassuring :)

21:25 arrdem: bob2: :D

21:33 Rosnec: I just had a pretty cool idea for a function, which may or may not exist already

21:34 it would be a modified ->, where along the way you can somehow prefix with a keyword

21:34 and it returns a mapping of all of those keywords, to the evaluated form that comes after it

21:35 so something like this...

21:36 (->' x f :first g :second h) => {:first (g (f x)), :second (h (g (f x)))}

21:36 it would let you use threading, but store intermediate values along the way

21:36 the only problem I see would be the fact that keywords are functions

21:37 so that would conflict with how threading works

21:37 but perhaps there's some way to get around that

21:37 arrdem: Rosnec: I think that zipmap and juxt are right up your alley...

21:37 Rosnec: I've actually never really looked too much into those two, so I don't really know how they work

21:38 I should probably learn, though

21:39 arrdem: ,(doc fnmap

21:39 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

21:39 arrdem: ,(doc fnmap)

21:39 clojurebot: No entiendo

21:39 arrdem: ,(doc fmap)

21:39 clojurebot: No entiendo

21:40 arrdem: ,(defn -:> [v & pairs] (let [pairs (partition 2 pairs) keys (map first pairs) fns (map second pairs)] (zipmap ((apply juxt fns) v) keys)))

21:40 clojurebot: #'sandbox/-:>

21:40 arrdem: ,(-:> 3 :+ inc :- dec)

21:40 clojurebot: {2 :-, 4 :+}

21:41 arrdem: I got it backwards but that's the idea :P

21:41 ,(defn -:> [v & pairs] (let [pairs (partition 2 pairs) keys (map first pairs) fns (map second pairs)] (zipmap keys ((apply juxt fns) v))))

21:41 clojurebot: #'sandbox/-:>

21:41 arrdem: ,(-:> 3 :+ inc :- dec)

21:41 clojurebot: {:- 2, :+ 4}

21:41 arrdem: HAH

21:41 aaaand that's my first use of juxt in anger :D

21:42 Rosnec: awesome, arrdem

21:43 what happens if I do this:

21:43 ,(-:> 3 inc :+ inc :- dec)

21:43 clojurebot: {#<core$inc clojure.core$inc@1a955d8> nil}

21:43 arrdem: it breaks just like you'd expect...

21:43 Rosnec: yeah

21:44 you could always do what you do in lets anyway

21:44 ,(-:> 3 :_ inc :_ inc :+ inc :- dec)

21:44 clojurebot: {:- 2, :+ 4, :_ 4}

21:44 Rosnec: treat _ as trash

21:44 I thought this might be useful in lets anyway

21:45 you could thread through a bunch of functions, and destructure it in the let binding

21:45 or I guess any binding

21:46 well, I'm saving that function

21:46 I might as well use it in the piece of code that made me think of that

21:48 arrdem: hum... got a better name for it than -:>

21:49 juxt->

21:51 Rosnec: well thank you for that, arrdem

21:51 and actually, now I'm thinking I shouldn't use it in that snippet of code

21:51 but I'll definitely save it for later

21:51 arrdem: T_T

21:51 :P

21:52 Rosnec: I would basically need it to be able to fork into multiple ->'s

21:52 because I need to call two different functions on the first form

21:53 so it'd actually be simpler to just write them out one-by-one

21:53 at least in this case

21:56 if there isn't, there should really be a way to destructure & [key val]*

21:56 which would basically use partition 2 in that case on the & pairs

21:56 or to put that better

21:57 instead of doing (fn [& pairs] (partition 2 pairs))

21:57 you could do (fn [& [key val]*] ... crap what would you even refer to it by?

21:58 maybe this won't work

21:58 I just think it would make the documentation more readable

21:59 although I guess you could just modify the arg list it shows in the doc

22:24 TravisD: Or you could, like, pass in a map

22:26 Heh, unnecessary and delayed sarcasm is the greatest

22:31 cbp: I have a bunch of .class files in a jar how do I go about putting them on clojars?

22:33 * seangrove preps his for his impersonation of dnolen_ ...

22:33 seangrove: "Right?"

22:35 technomancy: cbp: you can scp a jar up

22:35 actually wait no

22:35 you can use `lein deploy` on any random old jar

22:35 jar+pom that is

22:38 cbp: Ok well I'm not entirely sure how to make a pom for a bunch of protobuffers but ill try

22:38 thanks :-P

22:46 java.lang.NullPointerException

22:46 for a second I thought it would be easy

23:12 I'm getting an error when I scp to clojars https://www.refheap.com/76236

23:13 My pom is this https://www.refheap.com/76233

23:13 Any pointers?

23:16 beamso: is there an issue in that the artifact id has no capital letters but the .jar does?

23:17 cbp: If I remove the capital letter from the .jar it then complains that it expected a jar with a capital letter

23:17 beamso: ouch

23:23 dbasch: cbp: I used a pom based on this and it worked https://github.com/ato/clojars-web/wiki/POM

23:33 cbp: ....

23:35 I've been modifying a copy of the pom which im not actually using in the scp and wondering why my changes do nothing haha

23:35 dbasch: thanks

23:35 It worked finally

23:36 dbasch: haha

23:37 derek_c: newbie question: I'm trying to write a macro that takes an arbitrary number of expressions, and then just put those expressions in a list and return the list

23:37 so something like: (mymacro 1 2 3) => [:some_other_stuff 1 2 3]

23:37 how do I do that?

23:37 cddr: why must it be a macro?

23:38 derek_c: cddr: it doesn't have to

23:39 cddr: In that case, I think you just need a variadic fn. For example (fn [& args] (concat [:some-other-stuff] args))

23:42 If you get to choose datomic for persistence, and clojurescript for the client, would you just propagate the datomic info model all the way down to the app?

23:43 derek_c: cddr: thanks

23:44 cddr: Or is there still benefits to be had in building a conventional "REST" API

23:44 derek_c: when a macro and a function do the exact some thing, does it make sense to choose the macro because it saves you a function call?

23:45 beamso: cddr: i'd still build the REST API.

23:45 derek_c: it is seen as better form to only use macros when necessary

23:45 cddr: derek_c: I'd always prefer a function because they are more composable

23:46 derek_c: beamso: I see, thanks

23:46 cddr: why?

23:50 bbloom: seangrove: still there?

23:50 cddr: derek_c: Paul Graham has a chapter on it in "On Lisp": http://dunsmor.com/lisp/onlisp/onlisp_12.html

23:51 seangrove: bbloom: Yeah, finishing up some stuff, but a bit burnt out. Might have some visual stuff you might enjoy soon though from some ideas that I've been able to pull off

23:52 bbloom: seangrove: heh ok awesome, well let me know tomorrow or something

23:52 seangrove: i'm beat now

23:52 derek_c: is there a function that can sort of take things out of a list? I mean, instead of doing (concat [1 2 3] [4 5 6]), I want to do [1 2 3 (something [4 5 6])]. is that possible?

23:54 cddr: What is "something" a function that you indent to pass [4 5 6] to?

23:55 seangrove: bbloom: Sounds good, will do

23:55 bbloom: As a hint, it's another "oh, he's crazy, that'd take a ton of work" => "oh, that's possible, and kind of handy"

23:55 derek_c: cddr: yeah

23:55 so [1 2 3 (something [4 5 6])] would return [1 2 3 4 5 6]

23:56 bbloom: seangrove: yeah that's not a hint

23:56 Jaood: ,(into [1 2 3] [4 5 6])

23:56 clojurebot: [1 2 3 4 5 ...]

Logging service provided by n01se.net