#clojure log - Nov 08 2012

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

2:42 seannetbook: ibdknox: replied to your email... still having problems on win8 x64

2:42 ibdknox: ugh

2:43 seannetbook: anything unique about your setup?

2:44 seannetbook: hardly... it's vanilla win8 release preview on a parallels VM

2:44 i know next to nothing about windows so i haven't customized it :)

2:44 ibdknox: ironically me neither ;)

2:44 I'm on a fresh install of win8 on parallels x64

2:44 seannetbook: is there any debug flag i can set or logs or something?

2:45 ibdknox: Not that I can find, it seems to be deep down in node territory

2:45 I have a couple other guesses on what might be wrong

2:45 and how I can fix it

2:46 I'll give them a shot and ping you when I have something worth trying

2:46 thanks a ton for helping out with this btw

2:46 seannetbook: 'k... anything i can do to help, just let me know

2:46 i'm probably buying a win8 convertible tablet as my main travel device so i'll need light table to work on that :)

2:48 i have lein, clojure, java, emacs, nrepl all working on win8 on the vm so light table is the last piece of the puzzle!

2:52 ibdknox: seannetbook: you mean a surface?

2:53 seannetbook: not sure yet - MS haven't confirmed specs or pricing on the Pro

2:53 ibdknox: I think the surface doesn't *actually* run most apps

2:53 seannetbook: right now i'm leaning toward the Dell XPS 12 Ultrabook Convertible

2:53 ibdknox: it's an arm device

2:54 seannetbook: the Surface RT doesn't, but the Pro is a full Intel/Win8 Pro machine

2:54 Urthwhyte: I've got an RT if you have questions

2:54 seannetbook: my spec is an i7, 8GB RAM, 256GB SSD

2:55 dell, sony, toshiba all have convertibles with that spec for $1,500

2:55 ibdknox: nice

2:55 seannetbook: the asus taichi is a possibility too but more expensive

2:56 (and i'm a lifelong apple guy)

2:56 Urthwhyte: I'm still waiting for better Linux support of retina displays :/

2:57 Won an rMBP at a hackathon and had to give up Linux

2:57 Losing xmonad has been quite the chore

2:58 seannetbook: my alternative is a MacBook Air 11 fully loaded but i would prefer a tablet hybrid

2:59 Urthwhyte: My concern with going to W8 is losing the shell

3:00 Cygwin doesn't really cut it

3:00 seannetbook: use emacs and eshell :)

3:01 Urthwhyte: vim guy at heart, nty

3:05 ibdknox: seannetbook: just to make sure, can you try deleting .lighttable and running it?

3:06 seannetbook: just a sec i'll go try that

3:07 Urthwhyte: Oh, is that the Lt author?

3:08 ibdknox: it is :)

3:08 Urthwhyte: Always surprises me how populous this channel is

3:09 seannetbook: ok, deleted .lighttable and ran the new download again - same error

3:09 ibdknox: k, just wanted to be certain

3:09 thanks

3:10 seannetbook: anything else tonight or can i go to bed? :)

3:12 Urthwhyte: Now I'm tempted to retry some 4clj problems with LT v. vimclojure and see which goes faster hah

3:12 brainproxy: &(let [lazy-seq* #'clojure.core/lazy-seq] (lazy-seq* [1 2 3]))

3:12 lazybot: clojure.lang.ArityException: Wrong number of args (1) passed to: core$lazy-seq

3:12 ibdknox: seannetbook: head out, I'm not far behind

3:12 brainproxy: ^ what's the correct way to "alias" a macro in another namespace?

3:13 seannetbook: 'k man.. are you gonna be at rich's talk tomorrow in town?

3:13 amalloy: usually the answer is to not define aliases for things that already exist

3:13 for sure you can do it, but...

3:13 brainproxy: amalloy: sure, well let's just assume I have a really good reason to do it

3:16 tomoj: (:require [clojure.core :as core]) ?

3:16 (core/lazy-seq [1 2 3])

3:19 brainproxy: tomoj, thanks, but not quite what I was after

3:19 amalloy: this works `(def #^{:macro true} lazy-seq* #'clojure.core/lazy-seq)`

3:19 tomoj: why do that?

3:20 brainproxy: tomoj: just learning some things...

3:42 jyu: hi, are there any awesome bdd style test framework

4:41 pingtimeout: Hello world !

4:41 _ulises|away: pingtimeout: pong

4:42 * pingtimeout like

4:42 ejackson: sssh.... its meditation hour in #clojure

4:43 pingtimeout: Hmm ok

4:43 I'll be quiet

4:43 ejackson: just kidding, its usually quiet in here until the American wander in with their spurs and big hats :P

4:44 pingtimeout: :)

4:44 Ok so lets go

4:44 I'm wondering : is it possible to start a clojure nREPL and connect to it using telnet ?

4:46 The point is : I have a webapp where you can send code to a node.js server

4:46 (Only for training purpose)

4:46 So currently it supports only javascript code, and I would like to add clojure support

4:47 And here I am, trying to figure out how nREPL works

4:48 Do you have any advice or pointers about how I could achieve that ?

4:48 ejackson: you connect to an nrepl directly

4:48 over so long as you can see the port

4:48 I have a couple of machines with an embedded nrepl server, forward the port over ssh, and then connect directly

4:49 couldn't be easier

4:49 pingtimeout: Yeah but, what do you use to connect to the nREPL ?

4:50 ejackson: aaah, I see, I'm doing it from emacs

4:50 using nrepl.el

4:50 if you dig into that I'm sure you'd find your answers

4:51 pingtimeout: Ok thanks :)

4:52 For instance, I connected a telnet to the nrepl server and typed "(println :foo)" but it did nothing

4:52 ejackson: yeah, I imagine there may be more to it than that :)

4:53 pingtimeout: Yeah obviously, but that would be my goal : have a server that evaluates clojure expressions and return the result over HTTP or something like that

4:54 ejackson: pingtimeout: there are a couple of existing projects that do it in embedded clojurescript: session being the most interesting

4:54 so cljs sends clj to server, its eval'd, and the result sent back to cljs in the browser

4:57 pingtimeout: Ok thx, I'm going to dig that :)

4:57 clgv: pingtimeout: there is a HTTP transport for nrepl

4:58 ejackson: aaah, and there's the answer :)

4:59 clgv: pingtimeout: and telnet should work to. but "(println :foo)" is a command you want to execute but the server expects message of his nrepl-protocol. hence you have to wrap the clojure command in the appropriate nrepl message

5:00 pingtimeout: clgv So to summarize : I could either use clojurescript in my node.js server to connect to the repl, or try to write a http client using the http nrepl protocol

5:01 ejackson: the first doesn't require the the repl - you can just send use an http server yourself

5:01 clgv: pingtimeout: I dont know much about that first option but you can certainly use the second and talk to the nrepl server via the nrepl protocol

5:02 pingtimeout: Yeah http would be easier I think

5:02 Do you know where i can find the documentation of the nrepl http protocol ?

5:03 I found this but not sure it is relevant : https://bitbucket.org/kotarak/nrepl

5:05 clgv: pingtimeout: maybe a bit outdated since nrepl made a jump to 0.2.0 which might have broken apis

5:06 pingtimeout: https://github.com/cemerick/drawbridge

5:07 pingtimeout: if you are stuck try to ping cemerick this afternoon

5:09 pingtimeout: Ok

5:09 Many thanks !

5:34 luxbock: why does ((fn [a b] [a b]) 1 2) give me [1 2] but (#([%1 %2]) 1 2) throws an exception?

5:36 scottj: luxbock: because #(a) is the equivalent of (fn [] (a)) not (fn [] a)

5:39 luxbock: hmm I see

5:47 alexnixon: luxbock: I disagree with scottj, rather it's because the #() form tries to evaluate the stuff within

5:52 luxbock: in this case it's trying to evaluate a vector

5:54 luxbock: alright

5:54 rcg-work: huh

5:54 err

5:58 alexnixon: ,(#(vector %1 %2) 1 2)

5:58 clojurebot: [1 2]

7:14 clgv: luxbock: just for the record, scottj had the right explanation

7:16 alexnixon: clgv: he did - I misunderstood

7:17 luxbock: next question: how do I exit an infinite loop in Emacs, using nREPL? is there a way beyond killing the buffer and the process with it?

7:18 antares_: luxbock: unlikely

7:23 clgv: luxbock: nREPL supports that but the question is if nREPL.el has support for that already

7:23 in CCW there is a button to kill the current execution in the REPLView

7:24 luxbock: what's CCW?

7:24 clgv: Counterclockwise a plugin for Clojure development in eclipse

7:25 luxbock: ah

7:25 clgv: so you have to check nrepl.el documentation or source to find out whether there is a keybinding for that

7:31 luxbock: C-c C-b seems to work

7:37 zakwilson: Lighttable actually runs for me now. Yay. Instarepl doesn't seem to like it when I call in-ns though.

7:59 frawr: hi, looking for some help with enfocus.

8:27 solussd: Anyone else here use noir-cljs for clojurescript? When I deploy to heroku everything is AOT compiled, but the clojurescript compiler blows up at runtime if I AOT. Any else experience this?

8:41 magius_pendragon: hey everyone ; I'm having some trouble with genclass. It's throwing a class not found exception on the class I'm trying to subclass... it's fully qualified (I think? I don't know java very well) and the containing jar is in my projects.clj file as a dependency.

8:42 _ulises: magius_pendragon: can you paste the code somewhere?

8:42 magius_pendragon: _ulises: yeah, is there any preference on where?

8:42 I vaguely remember a clojure pastebin last time I hopped in here, but don't have the address on hand

8:43 _ulises: magius_pendragon: refheap, friendpaste, they're all fine

8:43 magius_pendragon: https://www.refheap.com/paste/6483

8:44 I'm aware that this example in particular could use proxy instead, but it was simpler than the one that I'm working on that I think does (needs to access a protected field of a superclass, where the superclass doesn't provide a getter)

8:45 _ulises: magius_pendragon: I don't have much experience with gen-class et al, but I've generally seen it used inside the (ns ...) form

8:46 magius_pendragon: docs say it can be outside. It's throwing the error on the name of the superclass, rather than the name of the generated class as well

8:47 _ulises: magius_pendragon: have you tried the import in a repl?

8:48 magius_pendragon: _ulises: the import was working when I used proxy instead

8:48 _ulises: magius_pendragon: interesting

8:48 magius_pendragon: can't get it in a repl right now cuz the code won't compile, and linking all of the libraries to a fresh repl would be a headache

8:48 _ulises: oh

8:49 cmdrdats: hey guys, i have a vector of maps, like [{:age 31} {:age 20}] - what's the idiomatic way to run a function against all the :age values and 'update' the value - resulting in [{:age 32} {:age 21}], if i run it using inc?

8:50 madsy: cmdrdats: map should work fine

8:50 cmdrdats: (map #(inc (:age %)) items) ?

8:51 was hoping for something like (update-walk [:age] inc items)

8:53 magius_pendragon: _ulises: any other ideas ?

8:53 joegallo: ,(map (update-in % [:age] inc)) [{:age 1} {:age 2} {:age 3}])

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

8:53 joegallo: ,(map #(update-in % [:age] inc)) [{:age 1} {:age 2} {:age 3}])

8:53 clojurebot: #<ArityException clojure.lang.ArityException: Wrong number of args (1) passed to: core$map>

8:53 joegallo: ,(map #(update-in % [:age] inc) [{:age 1} {:age 2} {:age 3}])

8:53 clojurebot: ({:age 2} {:age 3} {:age 4})

8:54 _ulises: magius_pendragon: not from the top of my head unfortunately

8:54 joegallo: which is basically (map #(update-in instead of the idate of update-walk. you only lose a few characters, it's not so bad.

8:54 s/idate/idea/

8:54 cmdrdats: i was hoping to drop the anonymous function :/

8:55 but oh well, no biggie

8:55 i'll just roll my own, just wanted to check that I'm not missing some super obvious function that already does it

9:06 magius_pendragon: _ulises: figured it out. Apparently removing the []'s around the superclass was needed.

9:07 _ulises: but thanks for your help :)

9:11 luxbock: is there a way to auto-load certain libraries with REPL? more specifically I'd like to be able to do it in Emacs with nrepl

9:19 AWizzArd: luxbock: What you mean by „auto-load”?

9:20 luxbock: so that I can use the library straight away, without having to import it

9:23 clgv: luxbock: you could put a require or use in project.clj as :injections "(require '[my.lib :as lib])"

9:23 args no. :injections [(require '[my.lib :as lib])]

9:28 luxbock: ah, hadn't seen that option before

9:28 while googling it I found this:

9:28 http://stackoverflow.com/questions/12329713/how-to-load-ns-by-default-when-starting-repl

9:29 seems like I can also use :repl-options

9:31 clgv: oh right :init^^

10:04 Anderkent: Anyone familar with sqlkorma? Is it alive?

10:04 clgv: Anderkent: well, chris granger is busy with light table ;)

10:07 pandeiro: can you program clojurescript with lighttable, anyone know?

10:10 i would see for myself but i get an error about libudev.so missing :(

10:19 jsabeaudry: Short way of doing (into {} (map #(vec [% (foo %)]) #{:a :b :c})) ?

10:19 Or more idiomatic

10:22 ejackson: jsabeaudry: maybe you like (into {} (map (juxt identity f) #{:a :b :c})

10:23 Anderkent: (zipmap my_vector (map foo my_vector)) maybe?

10:24 jsabeaudry: ejackson, Anderkent, thanks, I think I'll go with the zipmap

10:24 ejackson: yeah, its nicer :)

10:26 apwalk: or the venerable: (reduce #(assoc % %2 (f %2)) {} #{:a :b :c})

10:29 alexnixon: does this function look 'generally useful'? I've needed it a few times myself, just wondering if anyone else has too: https://www.refheap.com/paste/6484

10:31 the context is when using the threading macro to store the results of sequential computations in a 'state' map: (->> state (assoc-if some-opt :foo (compute-foo)) (assoc-if other-opt :bar (compute-bar)))

10:37 Anderkent: shouldn't it be a macro in case compute-foo has side effects?

10:43 alexnixon: Anderkent: that's a good point - and also for efficiency

10:47 TimMc: alexnixon: I believe test-> or whatever it is called would help with that.

10:49 alexnixon: TimMc: I haven't come across that before - can you point to the source?

10:49 TimMc: https://gist.github.com/3885504

10:49 It's not in any released code yet, I think.

10:51 alexnixon: yes that would help. Is that slated for 1.5?

10:51 TimMc: (test-> state some-opt (assoc :foo (compute-foo)) other-opt (assoc :bar (compute-bar)))

10:52 Let me check the chatlog.

10:53 hyPiRion: groan.. Now I remember why I went from Common Lisp to Clojure.

10:54 TimMc: https://github.com/clojure/clojure/commit/026691e2f6cc8d1bab4feb7e577530a9f06fd85e

10:56 TimMc: oh, sweet

10:56 alexnixon: cool so that's in the 1.5 beta

10:57 gtrak: when-> is like -?> and let-> is like -<> ?

10:58 S11001001: is let-> anaphoric, gtrak?

10:59 gtrak: what's anaphoric?

10:59 hyPiRion: ~anaphoric

10:59 clojurebot: Titim gan éirí ort.

10:59 S11001001: gtrak: that is, it would have to do proper form replacement, not just bind a let with a variable

10:59 gtrak: introduces a binding implicitly

10:59 gtrak: it looks like it replaces it in top-level forms, but also binds it

10:59 S11001001: gtrak: well that's nasty

11:00 gtrak: S11001001: wait, I think I'm reading it wrong, it doesn't place it in the form, but it does bind it

11:01 S11001001: gtrak: that's the opposite of -<>

11:01 Mr_Bond: I need to get a clojure book, all these operators are like greek to me

11:01 :)

11:01 S11001001: Mr_Bond: you won't find these in any book

11:01 Mr_Bond: and they're just names; it's no harder to find out what -<> does than what "reductions" does (notwithstanding google being crap, but grep is always better for that anyway)

11:02 gtrak: Mr_Bond: blow your mind: https://github.com/rplevy/swiss-arrows

11:02 Mr_Bond: yeah, that's true

11:02 gtrak: -<><:p

11:02 Mr_Bond: thanks, nice overview. I'm not a big fan of such it's like $_, $-, $!, $<, etc in perl and ruby

11:02 hyPiRion: heh

11:03 It's moving into APL-land.

11:03 S11001001: Mr_Bond: anaphora have problems, but they're typically much safer than the globals perl offers

11:04 Mr_Bond: Ah, I ment more in terms of readability

11:04 S11001001: Mr_Bond: I can say entirely empirically that -<> is highly intuitive to readers

11:04 Mr_Bond: hehe :)

11:05 gtrak: let-> seems like a good alternative

11:05 Mr_Bond: yeah

11:05 S11001001: gtrak: when it works.

11:05 Mr_Bond: you don't get the benefit of people using it in a sentence here; we're just talking about it abstractly

11:05 gtrak: is it broken in some way?

11:06 S11001001: gtrak: making a let binding is fundamentally different from form replacement

11:06 TimMc: Looks fine to me.

11:06 DaReaper5: Basic clojure question: What is the best way to pass json to java in a method's parameters?

11:06 S11001001: for example, if <<- did binding instead of form replacement, you couldn't use it as a replacement for let-else

11:07 TimMc: DaReaper5: That doesn't sound very basic.

11:07 S11001001: (<<- (let [x 42]) (when (= x 42)) (if (on?) "on") x)

11:07 TimMc: What do you mean by "json"?

11:07 DaReaper5: haha thought it was

11:07 S11001001: instant depth reduction

11:07 DaReaper5: TimMc json is javascript object notation

11:07 gtrak: S11001001: I'm not sure I'm deep enough into this to undertand why that matters. I always thought of form-replacement as a nice hack, but I prefer to think in values and bindings anyway.

11:07 TimMc: DaReaper5: Not what I meant.

11:07 S11001001: gtrak: see above for usage; it's not at all just a hack

11:08 DaReaper5: i want to pass a json object to a java method

11:08 TimMc: S11001001: And then you have a kind of non-locality of control flow that smells really bad.

11:08 DaReaper5: should i do the conversion on the clojure end or java end

11:08 S11001001: TimMc: it's no worse than let-else

11:08 DaReaper5: can cheshire do this?

11:08 S11001001: TimMc: if you're desperate to reduce expression depth it's the shortest path

11:09 dakrone: DaReaper5: it's not quite clear what you're asking about

11:10 gtrak: S11001001: it's totally not clear to me what that's doing, so there's that

11:10 S11001001: gtrak: copy and paste it and put newlines in between the args

11:10 DaReaper5: On the clojure side i have a json object. I want to pass this in a java method's parameter.

11:11 Java does not recognize json so i have to convert

11:11 TimMc: DaReaper5: Are you having trouble with Java interop syntax?

11:11 gtrak: S11001001: so it's threading them from the bottom up?

11:11 S11001001: gtrak: you've got it

11:11 gtrak: not sure what the benefit is though

11:11 DaReaper5: Does the java interop have a way of converting json?

11:11 ohpauleez: DaReaper5: You mean you have a JSON string? Or you've parsed the JSON into a Clojure map?

11:12 S11001001: gtrak: do the expansion, and imagine it's longer

11:12 DaReaper5: ohpauleez i can have either on the clojure side

11:12 i already have a way of converting json to and from a string

11:13 ohpauleez: DaReaper5: Ok, well if the Java method expects a JSON string, just pass it in. If it expects a map-like thing, just pass in the hashmap

11:13 DaReaper5: i can pass a string but... can i pass a clojure map to a java method

11:13 gtrak: so it's good if you're nesting a lot of forms with no branching in the tree

11:13 DaReaper5: ok

11:13 Anderkent: you can pass a clojure map to a java method that wants a map

11:13 DaReaper5: so it just behaves like a hashmap

11:13 gtrak: I think I rarely do that

11:13 DaReaper5: no conversion necessary

11:13 ohpauleez: correct

11:13 gtrak: I'll just make functions usually

11:13 TimMc: DaReaper5: Everything you're asking about depends on what the Java method expects, which you haven't xplained at all.

11:14 DaReaper5: so the answer to my question is: The best way to pass json to a java method is to pass the json object as a clojure map which will be the equivilant of a hashmap

11:14 ohpauleez: TimMc: I think it expects a map-like

11:14 DaReaper5: TimMC i can have the java method retrieve anything

11:14 ohpauleez: DaReaper5: Don't use "json" like that

11:14 DaReaper5: but a string would be impractical because a conversion would still have to be done

11:14 ophauleez, sorry like what?

11:15 Anderkent: you need to do the json string -> hash map conversion somewhere anyway

11:15 gtrak: S11001001: seems like it's equivalent to not indenting properly :-).

11:15 Anderkent: whether you do it in java or in clojure does not really change much

11:15 DaReaper5: anderkent i have cheshire for that i believe

11:15 S11001001: gtrak: you'll note there's a branch in my example

11:15 ohpauleez: JSON is a string format. A data exchange. You want to say: "If my Java method expects a map, I need to parse the JSON string into a Clojure map before passing it on to Java"

11:15 gtrak: is it more readable? https://gist.github.com/d7b45e347df19d9e808f

11:16 ohpauleez: "If the Java method expects a JSON string, I should pass the string directly in"

11:16 DaReaper5: ohpauleex yes you are right but i was unaware of the possiblity of using a clojure map in the context

11:16 S11001001: gtrak: and it autoindents correctly

11:17 gtrak: right, I just think I'd prefer the auto-indented version of the second thing I wrote.

11:17 S11001001: gtrak: sure; <<- is for longer series

11:17 DaReaper5: anderkent it does matter because if i can use a bult in converter on the clojure side it would be easier :)

11:18 S11001001: or if you want to use ->> but backwards

11:18 because that's all it is

11:18 DaReaper5: but i believe i know what to do now so thanks!

11:18 gtrak: yes. I could see it being useful for deep nesting.

11:18 TimMc: S11001001: That "if" is hella confusing.

11:19 gtrak: but the benefit of ->> and -> for me is the value-flow, and it's slightly nicer than lots of let's. I don't have to reason about stack-frames.

11:19 TimMc: Especially because "<<-" looks like it puts things at the beginning of the form, not the end.

11:19 ohpauleez: DaReaper5: totally welcome

11:19 gtrak: I see it as macroized comp

11:19 S11001001: TimMc: what else would you call backwards ->>?

11:19 TimMc: >>-, duh :-P

11:20 djcoin: gtrak: oh, awesome, your logo from keen commander, I love this game :)

11:20 gtrak: it's classic!

11:20 keen commander? is that a foreign language version? :-)

11:21 ohpauleez: haha

11:21 djcoin: gtrak: don't know, what is your version ? maybe I don't recall it exactly :)

11:21 gtrak: Commander Keen

11:22 ohpauleez: I don't think I ever realized that was a Carmack and Romero game

11:22 gtrak: we were talking about threading and ordering after all

11:22 djcoin: Well Commander Keen then must be the exact name

11:22 pandeiro: in JoC, there's a brief part on PersistentQueue that says "repeatedly check a work queue to see if there’s an item of work to be popped off, or if

11:22 you want to use a queue to send a task to another thread, you do not want the

11:22 PersistentQueue discussed in this section.

11:23 -- my question: if that's what i want, what *should* i use?

11:23 gtrak: (-> Keen Commander)

11:23 pandeiro: probably an agent

11:23 ohpauleez: pandeiro: and a priority queue

11:24 pandeiro: ohpauleez: that is a java class?

11:24 ohpauleez: or an atom with with a watcher

11:26 pandeiro: http://clojure.github.com/clojure-contrib/branch-master/priority-map-api.html

11:26 Dig around to see where this went to, and use watchers

11:26 gtrak: commander keen was the birth of smooth side-scrolling on pc, like mario 2.

11:28 pandeiro: ohpauleez: gracias

11:34 ohpauleez: pandeiro: Certainly! happy to help

11:36 ejackson: gtrak: hard to believe that after Keen they then did Doom !

11:36 djcoin: :)

11:37 gtrak: ejackson: wolfenstein

11:37 ejackson: yeeeeeeees

11:37 still, from collecting pizza to topping nazis....

11:40 gtrak: keen 4-6 was pretty great, too

11:41 djcoin: I mostly played to keen4 as a kid, love the universe

11:44 ejackson: the book "Masters of Doom", about the iD mob, is a great read

12:04 deg: Is there any codewalker that I can use, e.g. to find the body in a defn form? (That is, something smart enough to peel away the arglist, metadata map, doc string, etc., and leave me with just the body forms?. (I know that I can copy the source code of defn itself, but I'm looking for a more elegant solution).

12:05 gtrak: deg: if it's on functions you write yourself, you can create a macro to attach it as metadata

12:06 deg: gtrak: Not sure what you meant, especially the "it" at the end.

12:07 gtrak: make your own defn that does what you wan

12:07 t

12:07 deg: I see. Nope. I need to walk existing code, separating the function body from everything else.

12:07 gtrak: ah

12:07 that sounds harder :-)

12:07 deg: It's not rocket science, but does involve a bunch of detailed rules...

12:08 gtrak: you might want to look at the clojurescript analyzer, or consider hacking the clojure compiler?

12:09 deg: I've looked at the definition of defn. I could copy that code but it is, for obvious reasons, written using very blunt instruments, since it comes into play before most of the Clojure runtime is loaded.

12:09 gtrak: hack your own dist of clojure/core.clj might be easier, too

12:10 deg: I've not played with clojurescript at all. Do you happen to know where can I find the clojurescript analyzer source?

12:11 gtrak: not off-hand

12:11 there are some projects that use it though

12:11 https://github.com/jonase/kibit

12:11 deg: k, I'll poke around. Might be higher-level than the def'n of defn

12:12 andrewmcveigh: Isn't it here https://github.com/clojure/clojurescript/blob/master/src/clj/cljs/analyzer.clj ?

12:13 deg: thanks. I'll take a look at it. Off for a bit now while I put on my reading cap.

12:13 ohpauleez: deg: Kibit and Ambrose's analyzer should get you there

12:14 https://github.com/jonase/eastwood, https://github.com/jonase/kibit, https://github.com/frenchy64/analyze

12:14 deg: ^

12:14 eastwood is an example on how to use analyze

12:14 but if you can match the forms, you can use kibit (see how cljx uses kibit)

12:16 deg: Thanks!

12:16 ohpauleez: np

12:19 antoineB: hello, for doing (map and [true true false]) i need to do (map #(and %1 %2) [true true false]), is there another way?

12:20 raek: antoineB: you don't want to do 'and' element wise, so 'map' is the wrong higher order function to use here

12:20 ohpauleez: antoineB: so you want to and the pairs? or and the whole thing?

12:21 ,(apply and [true true false])

12:21 clojurebot: #<CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/and, compiling:(NO_SOURCE_PATH:0)>

12:21 raek: antoineB: your pattern seems to be 'reduce': (reduce and [true true false])

12:21 ohpauleez: yes

12:22 joegallo: ,(every? identity [true true true])

12:22 clojurebot: true

12:22 joegallo: ,(every? identity [true true false])

12:22 clojurebot: false

12:22 raek: ('reduce' is what 'and' uses internally when given many arguments)

12:22 antoineB: and the whole thing

12:22 ohpauleez: yeah, i'd use identity

12:23 antoineB: raek: you are right i mistype, i want to use reduce

12:23 joegallo: every? has the benefit of returning false early even if you have very long seq of trues but a false at the beginning

12:23 raek: hrm, sorry. 'and' is not a function, so you can pass it to apply or reduce directly

12:23 joegallo: not sure if that's a concern for you

12:23 raek: ,(reduce #(and %1 %2) [true true false])

12:23 clojurebot: false

12:24 raek: ,(macroexpand '(reduce #(and %1 %2) [true true false]))

12:24 clojurebot: (reduce (fn* [p1__135# p2__136#] (and p1__135# p2__136#)) [true true false])

12:24 ohpauleez: expand more

12:25 raek: ,(macroexpand '#(and %1 %2) [true true false])

12:25 clojurebot: #<ArityException clojure.lang.ArityException: Wrong number of args (2) passed to: core$macroexpand>

12:25 raek: ,(macroexpand '#(and %1 %2))

12:25 clojurebot: (fn* [p1__191# p2__192#] (and p1__191# p2__192#))

12:25 raek: ,(macroexpand '(and %1 %2))

12:25 clojurebot: (let* [and__2241__auto__ %1] (if and__2241__auto__ (clojure.core/and %2) and__2241__auto__))

12:25 ohpauleez: ,(macroexpand-1 '(reduce #(and %1 %2) [true true false]))

12:25 clojurebot: (reduce (fn* [p1__245# p2__246#] (and p1__245# p2__246#)) [true true false])

12:25 ohpauleez: ahh that's what I was looking for, thank you

12:26 But yes, antoineB I'd use every? and identity

12:26 raek: anyway! you can't apply and, because it's a macro (and that would be like trying to apply 'if')

12:26 antoineB: every? is fine

12:28 that seems bizar to see and implemented by an if

12:28 logical, but bizar

12:34 gtrak: antoineB: of course it's logical!

12:35 it's also not bizarre. and/or are short-circuiting in all languages I know of.

12:35 the only way to short-circuit is with control-flow/branches/if

12:36 TimMc: and lambda-wrapping

12:36 gtrak: lambda-wrapping?

12:36 antoineB: bizar in sense of in other language it seen an operator implemented in the compiler not in the language

12:36 TimMc: but that requires "if" at some level for selection

12:36 gtrak: jump-tables are branches

12:37 TimMc: (if-fn true #(println "true") #(println "false"))

12:37 (def if-fn [test then else] (if test (then) (else)))

12:37 gtrak: turtles

12:38 TimMc: (def if-fn [test then else] (if-fn test #(then) #(else))) :-P

12:38 gtrak: haha

12:39 goto/branch/jump are fundamental

12:39 I was thinking maybe lambda calculus has something to say about this, though?

12:41 anyway it's a very useful construct on a von-neumann architecture

12:42 ForSpareParts: Have you guys ever seen an exception like this? "java.lang.ClassCastException: Cannot cast java.lang.Float to [F"

12:42 TimMc: Sure. [F is a float array.

12:43 25 cents on varargs.

12:43 ForSpareParts: TimMc, Thanks. I had no clue, and Google for [F is a non-starter.

12:43 gtrak: symbolhound?

12:43 ciphergoth: I can do (vec "foo") to turn a string into a vector of characters - what's the neatest way to go the other way? (clojure.string/join "" [\a \b])?

12:44 TimMc: gtrak: Doesn't help here.

12:44 gtrak: yea... was just about to say, that's unfortunate

12:44 TimMc: ciphergoth: apply str

12:44 ciphergoth: ForSpareParts: FWIW that's a Java thing, not a Clojure thing

12:44 TimMc: ciphergoth: Not exactly, it's a JVM thing.

12:44 ciphergoth: TimMc: indeed

12:45 will have to get more used to making that distinction now I'm learning Clojure...

12:46 TimMc: And things in java.lang... are kind of both Java and JVM at the same time.

12:46 ForSpareParts: TimMc, So, this is a varargs issue, I believe. But how do I deal with that? I mean, AFAIK I'm passing in the types I want for the specific method overload I'm looking for.

12:47 TimMc: ~varargs

12:47 clojurebot: I don't understand.

12:47 maleghast: Evenin' All

12:47 * maleghast tips hat to the room

12:48 maleghast: otfrom: You about, old bean?

12:48 otfrom: (Don't worry not about to tap you up for extended support requests)

12:48 otfrom: maleghast: after a fashion

12:49 pfft... so many better on this channel to get support from

12:49 maleghast: otfrom: OK, good - just wanted to ask you a question - will send prig message...

12:49 TimMc: clojurebot: varargs is a fiction of the Java compiler -- from Clojure, you'll need to pass in an array of the appropriate type. See into-array and float-array, etc.

12:49 clojurebot: c'est bon!

12:50 gtrak: fiction! lies!

12:50 TimMc: ForSpareParts: ^

12:51 ForSpareParts: TimMc, scratch that, I was wrong. This isn't a varargs method -- I should've googled that term first. My bad.

12:51 gtrak: java is just an obfuscation over the C stdlib! burn them!

12:51 TimMc: Dammit, I lost 25 cents.

12:51 What's the exchange rate with lazybot karma?

12:52 ciphergoth: OK style question: I have a list of things which are ether like [:a this that] or [:l this] or such like. Should they be vectors? Or something else, like tuples?

12:52 gtrak: hiccup is just like that

12:52 (html [:div#foo.bar.baz "bang"])

12:53 what's a tuple?

12:54 maleghast: gtrak: http://en.wikipedia.org/wiki/Tuple

12:54 ciphergoth: what I'm looking for is the best way do to something like algebraic data types

12:54 TimMc: ciphergoth: I guess it depends on how you're going to use them.

12:54 ciphergoth: TimMc: clojure.core.match and dispatch on what sort I'm looking at

12:54 gtrak: records?

12:54 clojurebot: Records are (and, long ago, structs were) "advanced features", which can cause significant pain if you don't get all the subtleties. If you're using them to create "classes" because classes are awesome, then you are probably better off just using plain old hashmaps, possibly with a :type key if you want to be clear about what type they are.

12:55 AWizzArd: Ceshire users: (json/decode "{\"keyword_example\":1}" true) ==> {:keyword_example 1} is already supported. But can the following be done easier, without specifying this explicit FN? (json/decode "{\"keyword_example\":1}" #(keyword (.replaceAll ^String % "_" "-"))) ==> {:keyword-example 1}

12:59 pandeiro: is there an obvious way to create a 'singleton function', ie i have a fn used as a watch but i only want it to be called if it is not already 'running' from a previous invocation

12:59 gtrak: pandeiro: set a flag somewhere, like an atom

12:59 dakrone: pandeiro: defonce

13:00 SegFaultAX: dakrone: What?

13:00 pandeiro: gtrak: ok, thought of that, so the fn 'closes the door behind it' when it finishes

13:00 scriptor: not sure if defonce would be useful here

13:00 pandeiro: dakrone: didn't get how that would work

13:00 SegFaultAX: It's not even related to the question.

13:01 dakrone: SegFaultAX: pandeiro: hah, sorry, I misunderstood the question

13:01 pandeiro: dakrone: np

13:01 gtrak: pandeiro: yes.

13:01 joegallo: do you want other callers to block until the first call exits?

13:01 or just pass through with no effect?

13:01 pandeiro: joegallo: right, i don't even want it to get called

13:02 i thought the atom solution was 'dirty' but i will go with it

13:02 SegFaultAX: pandeiro: For the record, this doesn't sound like a good idea.

13:02 pandeiro: it's literally my first time trying to implement a queue of sorts, no idea what i am doing really

13:02 SegFaultAX: i appreciate that :)

13:02 gtrak: pandeiro: if you want to make it cleaner, perhaps wrap the check/update in a lock

13:02 joegallo: if you want the calls to queue up, maybe you should be sending to an agent?

13:03 gtrak: serialize access to the atom, in other words

13:03 pandeiro: gtrak: right, not sure how though

13:03 joegallo: also very unfamiliar with using agents

13:04 gtrak: there's a convenient 'locking' utility, can lock on the atom or the var or whatever

13:04 I've only used it once really... for serializing calls to a println

13:05 pandeiro: basically i have a singlular 'connection' and i want to take requests to use it but process them serially, while also 'sleeping' and automatically 'waking up' when there are requests to be processed

13:05 gtrak: pandeiro: that sounds like a perfect use-case for an agent

13:05 pandeiro: gtrak: i have been thinking that and reading about agents for the last few days and it just doesn't click in my head

13:06 i would send the request to the agent?

13:06 SegFaultAX: pandeiro: Sounds like you're implementing a blocking queue.

13:06 gtrak: an agent is a queue with a threadpool

13:06 non-blocking though

13:06 pandeiro: SegFaultAX: i think i am, basically

13:06 joegallo: you really should probably look into agents more, just a suggestion

13:06 seems like most of us think that, which you should probably take as a sign ;)

13:07 gtrak: pandeiro: if you want to block on the agent, you can use await or promise/deliver

13:07 promise/deliver are implemented with CountdownLatch

13:07 TimMc: Agents are supposed to be value-oriented, and receive fns to operate on them.

13:08 Maybe you want a queue + a while loop.

13:08 pandeiro: TimMc: that is what i was implementing just now

13:08 ForSpareParts: TimMc, I found my problem, by the way. I was being an idiot and giving the wrong arguments.

13:08 gtrak: TimMc: in my case the 'value' is the job store itself. If I want to wait on an intermediate value, I can do that in the function I send to the agent.

13:08 * ForSpareParts headdesk

13:08 pandeiro: (while (peek (deref persistent-queue-atom)) (do-stuff ...))

13:08 AWizzArd: So, 8 minutes after his question pandeiro got 29 different strategies. I guess this means that there is no obvious way to create a „singleton function” (-:

13:09 gtrak: I think it's analagous to datomic's single writer strategy, the value of the agent being the DB

13:09 pandeiro: AWizzArd: yes i can tag this question as answered :)

13:09 TimMc: What we need is a singleton strategy for creating singleton functions.

13:09 SegFaultAX: TimMc: :)

13:10 pandeiro: TimMc: the limitation i have with a queue + while loop is the 'sleep' and 'wake up' part

13:10 hence the original question

13:10 i could create a watch

13:10 gtrak: sleep and wake up bits are taken care of in the agent

13:10 TimMc: pandeiro: LinkedBlockingQueue

13:11 raek: pandeiro: you could do (def running (atom false)) (defn try-to-acquire [a] (compare-and-set! a false true)) (defn singleton-fn [f] (fn [& args] (when (try-to-acquire running) (try (apply f args) (finally (reset! running false))))))

13:12 pandeiro: raek: that looks like a much more elegant way to do it dirty than i could've come up with

13:12 SegFaultAX: raek: Or you could use a monitor and locking, which is basically what you just tried to re-invent. :)

13:12 TimMc: pandeiro: Will it run forever?

13:12 raek: well, my version simply returns nil if the atom was "occupied"

13:12 pandeiro: TimMc: yes

13:12 raek: no blocking

13:13 SegFaultAX: raek: But he wants the calling thread to sleep (enqueue in the monitor) if it can't acquire the condition variable.

13:13 raek: ah, a lock then

13:14 SegFaultAX: I think. Actually he hasn't really described what he wants clearly other than using a meaningless term "singleton function"

13:14 raek: (or monitor)

13:14 TimMc: Oh, the caller needs to block?

13:14 pandeiro: singleton fn was specific to the implementation of using while and a persistent queue

13:14 the queue would be an atom with a watcher

13:14 SegFaultAX: pandeiro: That term isn't really a thing in this context.

13:14 gtrak: (let [p (promise)] (send my-agent (fn [val] (deliver p something) val) @p)

13:14 SegFaultAX: pandeiro: You just want a synchronized function.

13:15 TimMc: For some reason I imagined that this was async.

13:16 jsabeaudry: What do you use to do SVG in a noir context? Is analemma the recommended tool?

13:18 andrewmcveigh: jsabeaudry: I found using hiccup to generate the xml easier tbh.

13:19 raek: (defonce running (atom false)) (defonce running-monitor (Object.)) (defn singleton-fn [f] (locking running-monitor (while (compare-and-set! runngin false true) (.wait running-monitor))) (try (apply f args) (locking running-monitor (.notify running-monitor))))

13:20 sorry (defn singleton-fn [f] ... (try (apply f args) (finally (locking running-monitor (.notify running-monitor) (reset! running false)))))

13:21 pandeiro: gtrak: i pasted that (let...) in my REPL and locked myself out :)

13:21 gtrak: haha

13:22 you can deref with a time-limit by the way

13:22 pandeiro: i really wish there were some concurrency materials for beginners dealing with real world scenarios

13:22 gtrak: I've used it to great effect in testing

13:23 raek: pandeiro: Java Concurrency in Practice is a really good book in the subject

13:24 pandeiro: raek: i've seen it mentioned, i will try to hunt it down

13:24 gtrak: CTMCP covers the async stuff pretty well

13:24 pandeiro: coming from JS my experience is all single threaded or async

13:24 i really don't see how to apply things like agents, promises, even futures

13:24 gtrak: http://www.amazon.com/Concepts-Techniques-Models-Computer-Programming/dp/0262220695

13:25 JCIP was more gotchas building-blocks, CTMCP is cohesive mental-model stuff

13:25 raek: pandeiro: fyi, agents, promises and futures are not the basic building blocks. they are what Clojure add on top of the regular JVM features

13:26 it's good to know something about what's in java.util.concurrent

13:26 pandeiro: raek: i see the roads all leading there, yeah

13:27 hiredman: b

13:28 raek: it feels nice that most stuff that Java Concurrency in Practice warns about can't happen in Clojure (it's a good guide to the j.u.c classes (even from a Clojure perspective) though)

13:29 hrm. (defonce running (Object.)) (defn singleton-fn [f] (fn [& args] (locking running (apply f args))))

13:30 this, as well as the previous version, deadlocks on recursion though

13:30 gtrak: reentrantreadwritelock?

13:30 or just RenetrantLock I guess

13:31 Reentrant*

13:32 if I remember correctly, JCIP says all the locks are built from http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/AbstractQueuedSynchronizer.html

13:33 yea, in ReentrantLock there's a subclass: abstract static class Sync extends AbstractQueuedSynchronizer

13:35 CountdownLatch, Semaphore, and Futures as well

13:42 daniel__: I have a file src/backend/communication.clj and also a directory src/backend/communication

13:42 is that going to cause problems?

13:42 on requires/use

13:43 pandeiro: daniel__: no

13:43 raek: daniel__: no.

13:43 daniel__: ah wait, think i found my problem

13:43 i move a file into communication but didnt change the ns

13:43 my cpu is at 130%

13:45 for some reason my repl wont launch, keeps timing out

13:45 lein repl that is

13:46 pandeiro: so i just need to read 811 pages and i will be able to implement this basic queue

13:51 daniel__: any ideas why lein is consuming all my cpu?

13:51 gtrak: pandeiro: I think it's good to bring a certain fear to concurrency discussions.

13:53 pandeiro: gtrak: i have been avoiding it, really

13:54 but my current task involves interacting with a webapp in a headless browser using htmlunit, and the Rhino engine takes 15 seconds just to load it, on my machine

13:54 so either i learn to keep it loaded and queue my interactions with it, or i die of boredom

13:58 gtrak: why queue? why not synchronous?

13:58 with callbacks and things

13:59 pandeiro: gtrak: hmm

13:59 gtrak: I see async and queues as a tearing apart of call stacks, a reifying of the ordering

13:59 into a data structure

14:00 pandeiro: gtrak: not sure i see how else to do it

14:00 gtrak: not sure I get the details of it, then

14:00 pandeiro: server starts, instantiates connection, listens for requests and processes them with the single connection

14:01 the server could get two requests at the same time

14:01 gtrak: ah, it's in a different process?

14:01 pandeiro: no, it's in the same process now

14:02 i guess it makes sense to just set it up as an atom or something

14:02 is 'locking' to be used with atoms?

14:03 gtrak: so, here's what I do with agents, it might be relevant. The value of the agent is an object of some sort that represents a job store. I've created a protocol and extended it to a couple of custom types. I have functions that modify the job store, and I also have functions that perform side effects. The role of the agent in the side-effect case is only to guarantee ordering.

14:04 so, to enqueue, I just send it a function. If I want some result, I deliver on promises within that function.

14:04 If I want to read from the job store directly, I just use the value of the agent.

14:05 pandeiro: i follow everything but the delivering and promise part

14:05 the point of that is that it executes on another thread? or that it delays execution until necessary?

14:05 gtrak: yes, web requests come in and enqueue actions, which happen on the agent's thread pool.

14:06 I don't want to block the web request unless I care about the result.

14:06 promises are objects that you pass along. If you try to deref them, it will block your thread until another (only 1) delivers a value to them, then it returns the value.

14:07 in CTMCP, they are described as dataflow variables along with futures

14:07 they represent a value to be determined later

14:08 so, when you hung your REPL, it was because you blocked the thread.

14:08 In testing, everything I use has timeouts.

14:08 agents also have the benefit of centralized error-handling.

14:08 So, I've created a function that checks for errors during a test run, then rethrows the exception if any.

14:09 pandeiro: k this is starting to make sense

14:10 gtrak: futures decouple value from execution. Promises reify that into an object you can pass around.

14:10 or rather, they decouple execution from the evaluation

14:10 I think you can still pass around futures.

14:11 pandeiro: and there is no analog for 'deliver' with futures?

14:11 gtrak: but futures care about how they're executed, promises are just placeholders.

14:11 nope

14:11 futures manage their own threads, with java Futures you can pass an executor I think.

14:12 with promises, you can use the agent's queue or whatever you want.

14:12 pandeiro: great, ok. thanks for the hand-holding :)

14:12 gtrak: a 'deliver' for futures is the return value of the thread-stack :-)

14:13 promises decouple that

14:13 pandeiro: the abstractions make sense to me now

14:14 gtrak: i will probably share some code here tomorrow if you're around, see what monstrosity i come up with ;)

14:28 gtrak: pandeiro: sure, this stuff is still fun for me :-)

14:31 I just find the reification of a thread stack as data to be helpful in understanding async. We do the same with lazy-seqs.

14:31 an iteration is then a sequence of values.

14:32 a tail-recursion is an iteration, etc..

14:33 data-dependency is expressed as return values, when decoupled, when the thread stack is split apart, it must be made explicit.

14:42 jamii: Does anyone know how to turn off the math symbols in emacs-live (lambda for fn etc)

14:46 TimMc: gtrak: Man, I bet you love continuations.

14:47 gtrak: I haven't done much with them yet, but in theory, yes :-)

14:51 TimMc: stacks are poor man's gotos

14:51 TimMc: haha

14:56 mudge: how do I add a checkout dependancy to my project.clj file?

14:57 TimMc: mudge: You do it like a normal dependency as far as project.clj is concerned.

14:57 then you add the symlink in ./checkouts/

14:57 mudge: TimMc: the symlink goes to the root of the project I am depending on correct?

14:58 TimMc: in my project.clj file I have the project listed in dependancies like this: [im-client "0.1.0-SNAPSHOT"] does it have any group id? or just artifact that is the project name?

15:01 gfredericks: what's the latest clojure version?

15:02 TimMc: mudge: I think the ID group defaults to the artifact ID.

15:03 mudge: Right, you'd have a symlink like ~/repos/foo/checkouts/bar -> ~/repos/bar/

15:04 * gfredericks assumes clojure-1.5-beta1

15:04 mudge: TimMc: thanks. So I created a checkouts directory and put in a symlink to the root of the project I depend on and put the dependancy in my project.clj file. However when I run lein compile, it says that the artifact is not found in maven or clojars

15:05 TimMc: gfredericks: 1.4.0, I believe.

15:05 mudge: not found in maven or clojars repositorys.

15:06 TimMc: gfredericks: http://search.maven.org/#search|gav|1|g%3A%22org.clojure%22%20AND%20a%3A%22clojure%22

15:06 raek: mudge: the dependency needs to exist first. one quick solution is to run 'lein install' in the dependency project

15:06 gfredericks: TimMc sonatype has 1.5.0-beta1

15:07 TimMc: gfredericks: Sure, but that's not a release.

15:07 gfredericks: why is lein run -m foo.bar/baz not working for me? it says class not found

15:07 I thought you could call a specific var with lein run

15:07 hiredman: gfredericks: have you tried loading foo.bar in a repl?

15:07 TimMc: I remember someone having trouble with that feature.

15:07 gfredericks: nope :)

15:08 * gfredericks lein repls

15:08 hiredman: I guess it will throw an error

15:08 * Sgeo has a better thought for how to get an &env into runtime

15:08 mudge: raek: do you mean that the dependacy needs to be in the local repository?

15:08 gfredericks: indeed it does

15:08 hiredman: of course not the class not found error, but some other error that lein is swallowing

15:08 Sgeo: Using a global atom containing a map.

15:08 gfredericks: hiredman: thanks!

15:09 Sgeo: Wait, that idea does not work as intended.

15:09 And I _just_ realized it now

15:09 mudge: when I make a checked out dependancy, does the dependancy have to be in the local maven repository?

15:09 raek: mudge: it needs to be in some repository

15:09 mudge: raek: i see, I didn't know that

15:09 frawr: Hi, I'm trying the enfocus exawple, but they don't seew to work, the interposed alerts do though. what might be some common pitfalls?

15:10 mudge: raek: I have two projects and one project depends on the other. So should I put the project that is depended on into the local repository?

15:10 TimMc: raek: I didn't know that either. :-/

15:10 raek: mudge: yes

15:10 mudge: or start with one project and split them later

15:10 mudge: I thought the point of checked out dependacies was so that you didn't have to continually update your repository when you are working on two projects at the same time

15:11 raek: yes. you only need to install it locally once

15:11 mudge: raek: but what happens if I make changes to the dependancy project, don't I then have to update the repository?

15:12 raek: I think checkouts is more useful for testing bugfixes in dependencies than for hacking on an unreleased project and an unrelease library at the same time

15:12 mudge: no

15:13 mudge: lein will use any dependency information from the version in the repo, but the source code can be updated

15:13 mudge: raek: Okay, I think I understand then. So I put the dependacy in the project.clj, but lein doesn't look there for that project, it looks at the project via the symlink in checkouts directory

15:14 raek: does that sound right?

15:14 raek: well, it does look for the version it finds in the project.clj

15:15 if I recall correctly it just puts the src/ of the checkout dependency first in the classpath (which overrides the repo version)

15:15 well, this would be clear from the output from 'lein classpath'

15:15 mudge: raek: thanks

15:17 I'm confused by another thing. I know want to put my project into the local repository and so I looked at the command lein install. The documentation says that lein install puts your project into the local repository, but when I ran it, it just wrote a pom file and jar to the target directory of the project

15:17 Isn't lein install supposed to put your project into the local repository?

15:17 raek: mudge: it isn't in your ~/.m2/ directory?

15:18 mudge: raek: I checked, and it is in my local repository --- lein install just didn't tell me that it put it there. sorry, it works

15:20 TimMc: I don't think there's any good reason that lein needs a jar somewhere for the dependency -- it's just a quirk of the system.

15:21 raek: yeah

15:22 TimMc: Maybe someone can make a patch to plumb checkout deps info through the deps downloading code.

15:28 mudge: I am still getting a classNotFoundException with my checkout dependancy, I checked the classpath and the class is in the path

15:29 raek: mudge: what is the name of the namespace and how do you require it?

15:31 mudge: raek: this is the namespace: com.perfectabstractions.im-client.components.ImComponent

15:31 TimMc: That hy[hen looks like trouble.

15:31 raek: are you generating classes or is that last segment a namespace?

15:32 mudge: raek: I import it in :import like this: (com.perfectabstractions.im-client.components ImComponent)

15:32 (ns (import: (com.perfectabstractions.im-client.components ImComponent)))

15:32 (ns mynamespace (import: (com.perfectabstractions.im-client.components ImComponent)))

15:32 raek: it should be ":import"

15:32 mudge: raek: yes, sorry, it is :import

15:33 raek: and the directory should be called im_client if the namespace segment is called im-client

15:33 mudge: raek: right, it is im_client

15:33 raek: mudge: are you using gen-class?

15:33 mudge: raek: yes I am

15:33 raek: i'll put the code in a gist

15:34 raek: then I think you need to compile that namespace first (I'm not very sure about the details since I haven't used gen-class much)

15:34 mudge: raek: https://gist.github.com/4041394

15:35 raek: yes, that namespace has been compiled

15:35 raek: hrm. maybe this is one of these cases when you need to use an underscore in Clojure

15:35 mudge: raek: well I'll try it

15:35 raek: since you're using Java interop to access the generated class

15:36 (:import (com.perfectabstractions.im_client.components ImComponent))

15:36 mudge: raek: oh my gosh, yes that is it

15:36 raek: this works: (:import (com.perfectabstractions.im_client.components ImComponent)

15:36 with the underscore like you said

15:37 raek: ok, great!

15:37 mudge: yea!

15:37 thanks very much for your help

15:37 raek: np. :)

15:37 moogatronic: Emacs/nrepl question: Is there a way to re-start a jacked-in nrepl session? In the past, with swank, reissuing clojure-jack-in would kill and restart. I've tried killing the nrepl buffers, but I can never seem to re-establish a working repl.

15:39 technomancy: moogatronic: killing *nrepl-server* and re-running M-x nrepl-jack-in works for me

15:40 moogatronic: When i do that, and try to re-compile a class, I get "Namespace not found"

15:41 it seems to start the repl just fine however.

15:41 brainproxy: when spec'ing metadata map for (def ...) is there any difference in using #^{...} vs ^{}

15:42 moogatronic: weird. I just switched to repl, and issued (in-ns 'the-namespace), switched back to the buffer, and C-c C-k and it worked.

15:42 raek: brainproxy: ^{} is the pre-Clojure 1.2 syntax

15:43 sorry, there reverse!

15:43 brainproxy: okay

15:43 raek: man.

15:43 ^{} is what you use these days

15:43 brainproxy: cool... both seem to work w/ clojure 1.4

15:52 piranha: I have strange situation: some code works in REPL when I execute it, but when I do same in tests, it does not work

15:53 and I really can't understand what's going on there... any clues? maybe some insights? I'll post some example soon

15:54 ah

15:54 I'm sorry

15:54 for + repl are doing strange things sometimes

15:54 moogatronic: Example code?

15:54 raek: for returns values as a lazy seq. the for body is not evaluated until needed.

15:54 piranha: yes

15:54 raek: use 'doseq' if you're after the side-effects

15:54 amalloy: don't use for to do side effects

15:55 piranha: and in repl it's evaluated because I see return value :)

15:55 raek: exactly. :)

15:55 piranha: yes, I know, I just need to get used to that :)

15:55 it's already second time for a week when it brings me almost to panic :))

16:02 TimMc: I wonder if there's a kibit rule for hyphens in :import package names.

16:07 daniel__: can't i include a namespace (use 'backend.communication.zmq) which has a defrecord and then reference that defrecord in the repl?

16:08 user=> (extends? CommunicationProtocol ZeroMQ) 9 (close [context] nil)) │CompilerException java.lang.RuntimeException: Unable to resolve symbol: ZeroM

16:11 TimMc: daniel__: I think you need to also import the class the defrecord created.

16:11 This was certainly true in 1.2.

16:12 daniel__: thanks, works :D

16:13 uvtc: I was just looking at the docs for `letfn`, and it appears to be a shortcut for using `let` with func names and `(fn ...)`. But looking at `(source letfn)`, the impl uses `letfn*`. But I can't find the docs for `letfn*` in the repl nor at <http://clojure.github.com/clojure/&gt;.

16:14 And the repl tells me there *is* no `letfn*`: unable to resolve symbol.

16:14 Is there a `letfn*`, or am I not understanding the macro in the source for `letfn`?

16:14 raek: uvtc: 'letfn*' is a special form. it is implemented in the compiler.

16:15 TimMc: &#'clojure.core/letfn*

16:15 lazybot: java.lang.RuntimeException: Unable to resolve var: clojure.core/letfn* in this context

16:15 raek: so there is not letfn* var

16:15 TimMc: Oh, OK.

16:15 raek: (like there is no 'if' var)

16:15 TimMc: I guess letfn has to have compiler support.

16:16 uvtc: Oh. Hm. Ok. Thanks, raek. I suppose then that I'll have to look in the source for the docs on `letfn*`.

16:17 raek: I suspect 'letfn*' relates to 'letfn' as 'fn*' relates to 'fn'

16:17 pjstadig: i believe its because the fns are all aware of each other

16:17 like you can reference one of the later fns in an earlier fn

16:18 uvtc: Oh, ok. Thank you. :)

16:18 daniel__: user=> (def foo (ZeroMQ. "test" "test")) │#'user/foo

16:19 so i instantiated my defrecord, how do i call methods on it?

16:19 raek: daniel__: you use the protocol functions (which you require/use like ordinary functions)

16:19 daniel__: raek, where do i require/use them from

16:20 pjstadig: in the ns form where you want to use them

16:20 daniel__: i want to use them in the repl for now

16:21 raek: then you use the 'require' or 'use' functions

16:21 daniel__: i have foo which is an instantiated protocol: user=> (def foo (ZeroMQ. "test" "test")) │#'user/foo

16:21 raek: (and quote the argument)

16:21 daniel__: in what ns does the protocol live?

16:21 daniel__: the defprotocol lives in backend.communication and the defrecord lives in backend.communication.zmq

16:22 pjstadig: (use '[backend.communication :only [THE-FUNCTION]])

16:22 (THE-FUNCTION foo)

16:22 raek: then you need to do something like (require '[backend.communication :as comm] 'backend.communication.zmq) (import 'backend.communication.zmq.ZeroMQ)

16:23 (comm/protocol-method foo arg1 arg2)

16:23 daniel__: i see, so the protocol is the function and i pass it the implementation

16:24 (protocol-method implementation ... )

16:24 raek: precisely

16:29 jweiss: what's the shortest path to making all print-method output readable by the reader? overriding print-method or using the extensible reader? i'm not too concerned about exactly how things are read in, just as long as it reads something

16:31 daniel__: user=> (require '[backend.communication :as comm] 'backend.communication.zmq)

16:31 user=> (import 'backend.communication.zmq.ZeroMQ)

16:31 user=> (comm/receive (ZeroMQ. "test" "test") "test")

16:31 CompilerException java.lang.IllegalArgumentException: No single method: receive of interface: backend.communication.CommunicationProtocol found for functisrc/backend/communication/zmq.clj on: receive of protocol: CommunicationProtocol, compiling:(NO_SOURCE_PATH:1)

16:32 hiredman: daniel__: pastebin

16:32 daniel__: should just return "test"

16:32 http://pastebin.com/USQfhKGC

16:34 raek: daniel__: and the ZeroMQ type/record implements the protocol?

16:35 daniel__: yeah

16:35 wait, ill paste both bits of code

16:36 https://gist.github.com/4041813

16:36 im just testing receive at the moment, it should just return it's argument

16:37 raek: hrm, I can't see anything odd

16:37 wait

16:38 daniel__: in the protocol (and the implementation) the function takes one arg, but you give it two

16:38 you need to include the "this" argument in the protocol

16:38 daniel__: but the defrecord takes two arguments

16:38 raek: oh wait, you did that

16:38 daniel__: receive takes 1

16:38 raek: daniel__: send indeed takes two args, but receive takes 1

16:39 and you pass reveive 2

16:39 *receive

16:39 the instance and the string "test"

16:39 try (comm/receive (ZeroMQ. "test" "test"))

16:39 it should return the ZeroMQ instace

16:40 daniel__: this gives me #backend.communication.zmq.ZeroMQ{:context "test", :package "test"}

16:40 what do i do with that?

16:40 raek: daniel__: but that's what you wrote in (defrecord ZeroMQ ... (receive [context] context) ...)

16:41 the receive method, when invoked on a context, returns the context

16:41 daniel__: ok, thats not what i intended

16:41 i intended that it would just return "test" since this is what i passed in as context

16:42 i think i fundamentally mistunderstand something

16:42 raek: oh, I see

16:42 daniel__: you have too "context" variables in your code

16:42 one is the record field

16:42 the other is the first argument to the methdo

16:42 daniel__: yeah, it gets passed through as the argument?

16:42 i thought the methods would wrap their context in a closure

16:43 raek: yeah, the first argument is the "this" object

16:44 daniel__: let's rename the "receive" argument: (defrecord ZeroMQ [context package] (receive [context2] context2) ...)

16:44 does it make sense now?

16:44 daniel__: the first argument to defrecord is this?

16:44 not really

16:44 :(

16:45 whatever i pass through to defrecord should be used in each of the methods

16:45 raek: if you have (defprotocol FooProto (foo-method [a b c]))

16:45 daniel__: i intended for these contexts to be the same

16:45 raek: and (defrecord BarRec [x y] FooProto (foo-method [a b c] ...))

16:46 when you call (def bar (BarRec. 1 2)) (foo-method bar 3 4)

16:46 daniel__: bar is passed to foo-method as a

16:46 i get it

16:46 raek: then you have x=1, y=2, a=<BarRec object with x=1, y=2>, b=3, and c=4

16:47 since you have access to the fields of the record implicitly, it's common to structure the code like this: (defrecord ZeroMQ [context package] ... (receive [_] context) ...)

16:48 daniel__: ok, let me give this a try

16:48 thanks

16:49 raek: the field "context" and the first argument to the protocol functions can never be the same

16:49 I mean, one is a part of the other

16:50 it would be like having a vector [a b] and call it a

16:53 daniel__: yaaay, got it working

16:55 so in the defprotocol, the first argument i give the methods needs to be 'this'

16:55 so instead of (receive [context] it should be (receive [this context] ?

16:56 in the defrecord it seems to work with one argument, as long as ignore it (receive [_] context)

16:56 romanandreg: hey do you know if the semantics of subvecs in cljs are different from the ones of clojure on purpose?

16:56 dnolen_: romanandreg: what's the issue?

16:57 tomoj: anyone seen an ":protocol/unsupported Unsupported protocol :ddb" error from datomic?

16:57 romanandreg: dnolen_: in cljs `(subvec [1 2 3 4] 0 30)` => [1 2 3 4 nil nil nil …]

16:57 dnolen_: in clojure… IndexOutOfBound exception

16:58 daniel__: its a bit like explicit self in python methods

17:00 i dont quite see why having this is ever useful?

17:00 having 'this'

17:00 (defprotocol Proto (meth [this arg1 arg2]))

17:00 when am i going to want to have this inside the method?

17:01 how is that useful?

17:01 dnolen_: romanandreg: no explicit reason that I'm aware. patch welcome of course.

17:02 romanandreg: dnolen_: I'm wondering if doing the check would incur in performance issues

17:03 dnolen_: romanandreg: not sure how since vectors keep track of their count.

17:03 romanandreg: very likely an oversight - that's all.

17:03 tomoj: daniel__: suppose for example that you extend a protocol to String. how could the protocol function impl do anything useful without access to the String itself?

17:04 romanandreg: dnolen_: awesome… yes, we'll try to have one ready soonish, one of our test broke (port from clojure to clojurescript) because of this fact (yay testing!)

17:05 dnolen_: romanandreg: seems likes a simple patch too - subvec just doesn't check bounds at the moment.

17:07 amalloy: aw man. i wrote subvec

17:07 daniel__: ok tomoj, are there any examples of protocols extending strings?

17:07 i think a real world example or two might help me get my head around it

17:11 tomoj: well, there are plenty of other cases where you want this

17:11 here's one example from core.cljs https://www.refheap.com/paste/037765df5f84e7ae012b27e8e

17:11 you need this to be able to tell whether it's equal to other for IEquiv

17:13 daniel__: thanks tomoj, bookmarked

17:13 gunna call it a night

17:14 tomoj: `mvn install` in datomic-pro seems to not work

17:14 but `mvn install:install-file -Dfile=...jar -DpomFile=pom.xml` does

17:15 I guess that is not surprising

17:45 pendlepants: can someone tell me what the idiomatic way would be to share a db instance across a clojure app?

17:46 so if I'm using something like korma where am I putting my defdb and entities definitions, and am I just using require to share those throughout the app?

17:49 ivan: I would pass the db around into everything, regardless of what other people's macros are encouraging

17:55 bosie: i just switched to vimclojure (in vim, ofc). is there a way to go to the fucntion definition somehow?

17:56 ToBeReplaced: pendlepants: i was bothered by that too... you can avoid it by not defdb and instead passing around your connections to your entities

17:56 pendlepants: for me, i ended up scrapping it and using java.jdbc and c3p0 directly

17:56 * nDuff also ended up scrapping korma

17:57 ToBeReplaced: way to parse the cookies out of a ring-response? i'm assuming there's something in clj-http but i can't seem to find it

17:58 pendlepants: thanks, ivan/ToBeReplaced. I'll try it out w/o korma.

17:58 ToBeReplaced: for when response is ... :headers {"Set-Cookie" ("ring-session=yaddayadda")}

17:58 ivan: my korma is patched to take a pool created by bonecp

17:59 haven't used it much other than to confirm it works

18:00 ibdknox: fwiw, I've been looking for someone who has a vested interest in SQL to take Korma over

18:00 I simply don't have time for it, especially given that I don't see in any SQL work in my future anytime soon

18:01 ToBeReplaced: yeah; it seems like a high-maintenance project

18:01 ibdknox: not overly

18:01 There's not really *that* much that needs to happen to appease just about everyone

18:02 wingy: is there a way to stop jetty server programmatically?

18:02 tomoj: ToBeReplaced: clj-http.cookies/wrap-cookies ?

18:02 wingy: is start it using (run-jetty #'handler {:port port :join? false})

18:03 tomoj: wingy: call .stop on the return value of that, iirc

18:03 wingy: ok

18:03 tomoj: if you lost the return value, I think you have to kill the jvm :(

18:03 ToBeReplaced: wingy: def it before you start it, then .stop your-symbol

18:04 wingy: tomoj ToBeReplaced: so it returns a java object?

18:04 i think i should use an atom here

18:04 ToBeReplaced: wingy: yes

18:08 tomoj: yes that's it, if you also use wrap-lower-case-headers, thanks

18:12 wingy: does this look ok: (swap! server #(run-jetty #'handler {:port port :join? false}))

18:12 im starting the server and updates the atom in the same time

18:14 bbloom: wingy: you can use reset! if you don't need the prior value of server

18:14 ,(let [a (atom 1)] (reset! a 2) a)

18:14 clojurebot: #<Atom@542c47d7: 2>

18:15 wingy: yeah it worked thx

18:16 gtrak: wingy, teh problem with the first is the atom's value is getting passed in as an arg, though you haven't used it anywhere. It won't work.

18:16 wingy: yepp i noticed

18:21 what is weird is that i get "No matching field found: stop for class clojure.lang.Atom" when i try to stop the jetty server with (.stop server)

18:21 gtrak: deref

18:22 wingy: i updated the atom using (reset! server #(run-jetty #'handler {:port port :join? false}))

18:22 ah

18:22 egghead: does anyone use paredit with slime/nrepl? how can I make a newline without it submitting :(

18:22 technomancy: egghead: C-o should work

18:23 TimMc: Does C-q help?

18:23 wait, nvm

18:23 wingy: gtrak: you mean (.stop @server)

18:23 egghead: ah thanks guys

18:23 gtrak: yes

18:23 the atom evals to itself, vars eval to what they point to

18:24 egghead: i'm a paredit noob, I only use it for killing expressions and balancing parens

18:24 gtrak: symbols rather

18:24 symbols eval to var lookups

18:24 wingy: I get No matching field found: stop for class clojure.lang.PersistentArrayMap

18:24 gtrak: wingy: perhaps run-jetty returns a map

18:24 wingy: (def server (atom {}))

18:25 amalloy: egghead: C-j

18:25 gtrak: hmm? did your reset never happen then?

18:25 wingy: my reset did happen

18:26 here is my code: https://www.refheap.com/paste/6494

18:29 a better one: https://www.refheap.com/paste/6495

18:31 ToBeReplaced: do you know why i can't call .stop on the returned server?

18:34 ToBeReplaced: you didn't reset the server in your refheap

18:34 you used a multimethod, and followed the second path

18:34 oh config somewhere nvm

18:41 wingy: issue resolved yet? why the reader macro in the reset! ?

18:41 wingy: ToBeReplaced: what reader macro?

18:41 i can't get stop working yet

18:45 ToBeReplaced: wingy: take the # off of (reset! server #(yadda))

18:45 wingy: ToBeReplaced: but that creates an anonymous fn

18:45 hm

18:46 ToBeReplaced: i don't know if you can set an atom to an anonymous function, but either way, it's not what you're trying to do

18:49 bosie: how do you guys debug clojure, preferably with vim?

18:50 wingy: ToBeReplaced: wohoo worked

18:54 Somelauw: bosie: I use tslime + tmux

18:55 mattmoss: &(let [x (atom nil)] (reset! x #(+ 3 4)) x)

18:55 lazybot: ⇒ #<Atom@5d3011: #<sandbox7657$eval476836$fn__476837 sandbox7657$eval476836$fn__476837@aa003d>>

18:55 mattmoss: &(let [x (atom nil)] (reset! x #(+ 3 4)) @x)

18:55 lazybot: ⇒ #<sandbox7657$eval476858$fn__476859 sandbox7657$eval476858$fn__476859@a56d69>

18:55 Somelauw: and I actually think it is elegant that way, but emacs people tell me it is not a real repl

18:56 mattmoss: You can put a fn in an atom w/ reset!, but it doesn't eval the func.

18:56 &(let [x (atom nil)] (reset! x #(+ 3 4)) (@x))

18:56 lazybot: ⇒ 7

18:57 mattmoss: However...

18:58 &(let [x (atom nil)] (swap! x (fn [_] (+ 3 4))) @x)

18:58 lazybot: ⇒ 7

20:04 bbloom: dnolen: ping

20:13 holo: hi!

20:14 egghead: hi holo

20:17 holo: what is the name of that app hosted on heroku accounting the number of clojure library instances for each library being used at the moment?

20:18 brehaut: http://www.clojuresphere.com ← holo

20:19 holo: ha yes! that's it.. thanks brehaut

20:19 tomoj: grr https://www.refheap.com/paste/6fcd5e37b489c0e08f9a20ec7

20:20 oh, that was fixed 2 months ago

20:23 holo: hey! i'm going to be the first one using metis..

20:24 tomoj: coincidence? "inspired by Active Record Validations"

20:29 holo: >.>

21:19 tomoj: dakrone: thanks!

21:19 dakrone: tomoj: no problem! (for what?)

21:19 tomoj: the cheshire fix

21:20 dakrone: tomoj: :) thanks for finding it, silly mistake on my part

21:57 bbloom: if i never see an enum again, it will be too soon

21:57 #{:mmmm :set :of :keywords}

21:57 nightfly_: yes, keywords for the win

21:58 bbloom: blows my mind when i see java files that have a big enum up top, then repeat every key to add it so some map for dynamic dispatch, then have a setter and getter for every key, then have another map for converting them to strings

21:59 it's crazy how much work you need to do to get something half as useful as print and read

21:59 and assoc :-)

22:00 Sgeo: bbloom, what about Haskell data types with several constructors which each take 0 arguments?

22:00 bbloom: I don't know enough Haskell to comment, but I do remember thinking "instance Show" wtf?

22:00 * nightfly_ wonders how that would even work

22:01 shachaf: instance Show?

22:01 bbloom: shachaf: show is sorta like print

22:02 shachaf: bbloom: Yes, I know.

22:02 Sgeo: bbloom, you can tell Haskell to try to automatically make an instance of Show

22:02 shachaf: What's the context?

22:02 bbloom: Sgeo: like i said, i don't know much haskell

22:02 i just know i <3 keywords :-)

22:14 ChongLi: the crazier thing is Haskell's Read

22:16 read :: Read a => String -> a

22:16 shachaf: What's crazy about Read?

22:16 ChongLi: that it's polymorphic on a value rather than an argument

22:17 shachaf: Oh, well, sure.

22:17 ChongLi: a lot of languages can't do that

22:17 shachaf: You can take a simpler example: class Bounded a where minBound, maxBound :: a

22:17 minBound :: Int = -9223372036854775808, etc.

22:17 ChongLi: yeah that's pretty weird too

22:19 I wish there were some way to do that in Clojure

22:19 would make monads easier

22:20 shachaf: It's a bit tricky with dynamic types. :-)

22:20 ChongLi: yeah it's one of those tradeoffs

22:20 like the tradeoff between currying and arity overloading

22:21 shachaf: Speaking of crazy things in Haskell, there's Text.Printf.

22:22 ChongLi: yeah, a crazy hack

22:22 haha

22:22 brehaut: also HLists

22:23 shachaf: Pft, HList is too easy with modern GHC extensions.

22:24 data HList :: [*] -> * where { Nill :: HList '[]; Cons :: t -> HList ts -> HList (t ': ts) }

22:24 s/ll/l/

22:24 Cons True (Cons 'a' (Cons "hi" Nil)) :: HList '[Bool, Char, String]

22:25 ChongLi: hmm that's weird

22:26 brehaut: kids these days with their modern extensions.

22:27 ChongLi: the type system has gotten pretty crazy with them

22:27 shachaf: Way too crazy.

22:27 I like my type system simple, like Agda's.

22:27 brehaut: O_o

22:33 bbloom: I'm not sure that dynamic is what makes return type polymorphism hard, i think it's laziness

22:33 lisps choose configurable laziness: functions vs macros

22:33 where as haskell chooses always lazy, but you can't get the ast

22:33 brehaut: bbloom: qi weakens your argument

22:33 shachaf: I don't think you mean the same thing by "laziness" that Haskell people do...

22:34 ChongLi: how do you know which function to dispatch to if you don't know the type?

22:34 bbloom: sorry, brb

22:35 brehaut: ChongLi: how do protocols work?

22:35 ChongLi: they dispatch on the type of an argument

22:35 brehaut: right, so a dynamic typed language can do that just fine; it just has to do it at runtime

22:35 ChongLi: but with return type polymorphism you don't know the type

22:35 shachaf: Yes, but that's not what we're talking about here.

22:35 maxBound :: Word8 -- 255

22:36 maxBound :: Word16 -- 65535

22:36 That thing isn't a function at all. It's just a value.

22:36 ChongLi: yeah

22:36 it's set at compile time when the type is inferred

22:36 shachaf: ChongLi: Or at runtime.

22:36 brehaut: every method in the jvm has a return type; yes, those functions have no arguments but it doesnt mean the information is not available

22:36 shachaf: Sometimes you can't figure it out at compiletime.

22:37 ChongLi: if it can't be determined at compile time, doesn't haskell give an ambiguous type error?

22:38 shachaf: Not necessarily. The constraints will just be propagated.

22:38 ChongLi: ambiguous type variable

22:38 right

22:38 but if it never converges to a type somewhere down the line, it is ambiguous

22:39 shachaf: Sure, but you can compile a function that uses a Bounded on its own.

22:40 And in practice in the compiled code minBound might turn into a function instead of a constant. But that doesn't really matter.

22:40 ChongLi: sure, but the result will still be based on whatever types are inferred

22:40 at compile time

22:40 shachaf: Right, eventually.

22:40 ChongLi: all of the type information is gone at runtime (unless you're doing stuff with Data.Typeable)

22:41 shachaf: Sure.

22:41 ChongLi: I like to think of it as the type system just setting up all the plumbing

22:41 shachaf: But a polymorphic-over-Bounded function might get an extra argument with a Bounded dictionary.

22:41 ChongLi: yeah

22:42 shachaf: But that's just compilation details. :-)

22:42 ChongLi: I saw one article a guy wrote that talks about how to get rid of type classes in your code

22:42 by passing dictionaries explicitly

22:43 shachaf: Sometimes that's a much nicer approach.

22:43 ChongLi: it's pretty weird

22:43 it's basically just desugaring

22:43 shachaf: Are you thinking of http://lukepalmer.wordpress.com/2010/01/24/haskell-antipattern-existential-typeclass/ ?

22:44 I think he makes a good argument.

22:44 As far as existential types + type classes are concerned, it's often simpler not to use either.

22:44 ChongLi: I haven't read this one, but I think the one I read reached the same conclusion

22:44 shachaf: Well, the one I linked to argues for a specific use case.

22:45 Just an extension of the idea that [exists a. Show a *> a] ~ [String]. :-)

22:46 * shachaf likes the thing where converting existentials to universals is more or less just uncurrying.

22:46 Sgeo: This conversation is now over my head.

22:47 shachaf: Then raise your head!

22:47 I have the feeling all I ever end up doing in this channel is talking about Haskell.

22:47 ChongLi: the example he gives is pretty silly

22:48 it's rube-goldberg with types

22:48 shachaf: Which example?

22:48 That's an actual library.

22:48 ChongLi: the first code snippet

22:48 oh I'm not saying it isn't a valid example

22:48 just that people who write that stuff are being silly

22:48 shachaf: Well, yes.

22:48 That's his point. :-)

22:48 Sometimes classes aren't the right solution.

22:49 ChongLi: it's akin to people who, upon learning clojure, make tons of records

22:49 instead of just using maps and vectors

22:49 shachaf: "Advanced type system features have their place, but plain old functions go a long, long way. Functions are the masters of reuse: when you use an advanced feature, you need a yet more advanced feature to abstract over it (think: classes < existential types < universally quantified constraints < unknown). But all you need to abstract over a function is another function."

22:49 Sure.

22:51 ChongLi: I'm trying to characterize the mindset that goes into these sorts of antipatterns

22:52 some kind of desire to be idiomatic?

22:53 it's the idea that if something's exists you have to use it

22:53 shachaf: I think the Haskell thing just comes from the idea that type classes are the natural/only way to abstract over different things that have similar behaviors.

22:54 ChongLi: hmm, maybe

22:55 you know what bothers me?

22:55 the word "variable" and how it's misused so much

22:55 in clojure's documentation, it says that a lot of things are "not variables"

22:56 such as let-bound names

22:56 shachaf: It's misused constantly.

22:56 ChongLi: whereas in haskell they're called variables, using the mathematical definition of the term

22:56 shachaf: I don't really care what words you use for something as long as you define them clearly and use them consistently.

22:57 ChongLi: it can be confusing for beginners though

22:57 shachaf: Most things are. :-)

22:58 ChongLi: I've actually discussed this a lot with my friend

22:58 we argue over the philosophy of language

22:58 shachaf: I like the way Haskell takes almost every name from OO -- class, instance, method, etc. -- and uses it to refer to a completely different concept.

22:58 ChongLi: he calls me a Wittgensteinian

22:58 well, Haskell has a right to

22:58 it's old enough

22:58 shachaf: It is?

22:59 1989 isn't that old.

22:59 brehaut: its not like OO took those terms from a vacuum

22:59 ChongLi: it's old enough that such terms weren't nearly as widely used as they are today

22:59 shachaf: Hmm, I didn't think so. But I wouldn't really know, not having been around at the time. :-)

23:00 ChongLi: same goes for vi and emacs

23:00 people complain about their "non-standard" key bindings

23:00 shachaf: Uh oh. No editor wars in here.

23:01 bbloom: speaking of types....

23:01 technomancy: the standard WIMP definitions of "window" and "frame" really don't make any sense

23:02 ChongLi: nah I'm not a na editor wars type

23:02 bbloom: i've got the closure script backend completely reworked to emit a javascript AST instead of printing strings!

23:02 ChongLi: I use both editors

23:02 bbloom: just need to figure out the closure compiler type system, so that i stop getting horrible failures in advanced compilation mode :-)

23:02 ChongLi: they're both infinitely superior to mouse-based notepad clones :)

23:02 bbloom: https://github.com/brandonbloom/clojurescript/blob/js-ast/src/clj/cljs/compiler.clj

23:03 lots more work to do cleaning it up & also want to write up some design notes

23:03 ChongLi: javascript makes my blood boil

23:04 ugh I don't want to think about it

23:04 bbloom: as expected, it's much slower, but i think i'll also get the expected speed improvement if i skip the to-string step

23:04 jonasen: bbloom: cool!

23:05 ChongLi: great work though

23:05 clojurescript is really cool

23:05 bbloom: yeah, this is more or less a direct port of the string emitting version

23:05 now that it's "pure" there are lots of opportunities for cleanup and simplification

23:05 jonasen: bbloom: what are the advantages over emitting strings

23:06 bbloom: is the ast standardized?

23:06 bbloom: jonasen: i should be able to wire it up to automatically generate source maps ;-)

23:06 ChongLi: manipulating strings is always bad :)

23:06 bbloom: jonasen: the AST is rhino's

23:06 it seems relatively stable

23:06 shachaf: What about stringing manipulations?

23:06 ChongLi: it's why we love lisp languages

23:06 bbloom: i gotta run, but i'll provide more details as this evolves :-)

23:06 ChongLi: ok, so it's not always bad

23:06 Drakeson: Question about Clojure java-interop syntax: Would the alternative syntax (foo-object .method param1 param2) have worked instead of (.method foo-object param1 param2)? The first form could have provided a way to get "method completion" which the current syntax doesn't.

23:06 bbloom: probably on the mailing list

23:06 cya

23:07 ChongLi: but it's much easier to manipulate data structures like ASTs than strings

23:15 unnali: Drakeson: it wouldn't really be very Lispy (where the function is always first)

23:15 tomoj: I get method completion anyway, sorta

23:16 I think with swank, you can complete to any methods on any classes that are imported

23:16 unnali: (-> foo-object (...)) gets you half-way there ;)

23:17 brehaut: rearranging the method / object order wouldnt really help either; theres infrequently enough static type information to restricted it just to one class or interface

23:18 unnali: indeed!

23:19 ChongLi: yeah I'm not sure what is gained by such rearranging

23:19 help with auto-completion?

23:19 that's all I can really think of

23:19 type in an object and auto-complete on its methods

23:20 but that's a very different style of programming

23:20 that's "thinking in nouns" rather than verbs

23:20 brehaut: except that its not going to help with autocompletion

23:20 ChongLi: why not?

23:21 brehaut: because to restrict autocompletion to a particular class or interface requires knowing what that class or interface is, and much clojure code doesnt have that information statically available

23:21 ChongLi: oh I wasn't referring to clojure specifically

23:22 but to "traditional" OO languages like java

23:22 brehaut: the other thing is that parametric polymorphism makes it less useful

23:22 ChongLi: yeah

23:23 to really learn to be a functional prgrammer (when coming from a traditional OO background) requires a change in mindset

23:23 from nouns to verbs

23:24 I think that sort of conflict is evident in the people that desire such a change

23:24 conflict is too strong a word

23:25 Drakeson: brehaut: I *slightly* disagree: If you place have type hints, you might be able to single out the type of an object. If you don't, you might at least be able narrow it down to multiple possible types, and offer all their methods.

23:26 brehaut: well yeah, obviously if you typehint, but…

23:26 Drakeson: and about it being not lispy, methods are not exactly functions, they are very stubborn about what you pass onto them ...

23:27 ChongLi: Drakeson: the point is that lisp considers the car (or first element) of a list to be a function

23:28 if you make some special case where the second element is now a method and the first is just a value

23:28 how do you implement that? it seems really messy

23:28 brehaut: well, clojure does use the . special form to indicate that it is a OO interop with .whatever desugaring to it anyway

23:28 but yes

23:29 Drakeson: IMHO both `java-obj java-method ...' and `java-method java-obj ...' are messy and non-lispy.

23:29 ChongLi: so you'd still have to have the . special form occupy that position

23:29 brehaut: well you do anyway

23:29 it would just be the second and third arguments that switch position

23:30 ChongLi: Drakeson was talking about doing (my-object .mymethod)

23:30 brehaut: i realise that

23:30 but that could be (. my-object mymethod)

23:30 Drakeson: well, you could also do it as (java-obj. :java-method ...), and find something else for `new'.

23:30 ChongLi: oh, yeah

23:31 well you could write a new macro to flip the arguments if you wanted

23:31 brehaut: trivially

23:32 ChongLi: I don't see the advantage though

23:32 Drakeson: ChongLi: a new macro is moot. A reader macro would have been useful though, which I understand why it is not allowed.

23:32 twobitsprite: why does it bother me that docstrings come between the function name and the argument list? I mean, I get it, variable arity, but... it bothers me for some reason

23:32 ChongLi: the auto-completion type issue still remains

23:33 brehaut: twobitsprite: they dont have to

23:33 ChongLi: I like that clojure's reader doesn't have a huge amount of special syntax

23:33 twobitsprite: brehaut: no? I can put them after the args list?

23:33 brehaut: ,(fn [a b] "docstring" (+ a b))

23:33 clojurebot: #<sandbox$eval27$fn__28 sandbox$eval27$fn__28@77409080>

23:33 Drakeson: As I said, you might be able to narrow down possible types of the object and offer a union of all the types' methods.

23:34 twobitsprite: ooohh :)

23:34 brehaut: but its kinda weird these days to do so

23:35 twobitsprite: maybe it'll be one of those things that I'll do at first, run in to problems with, and it'll click why it's done the other way, and eventually I won't be able to stand docstrings after the args list... but for now, it just feels more natural :)

23:35 ChongLi: also I think it could get confusing

23:35 twobitsprite: so, what about:

23:35 Drakeson: ChongLi: I am arguing that that wouldn't need more special syntax.

23:36 It would merely rearrange the meaning of a couple special forms.

23:36 twobitsprite: ,(fn ([a b] "docstring1" (+ a b)) ([c d e] "docstring2" (- c d e)))

23:36 clojurebot: #<sandbox$eval55$fn__56 sandbox$eval55$fn__56@61254e91>

23:37 ChongLi: Drakeson: could you give me an example?

23:37 TimMc: twobitsprite, brehaut: I'm pretty sure that's a no-op.

23:37 Drakeson: of what?

23:37 ChongLi: of your proposed syntax

23:38 TimMc: twobitsprite: Try (defn foo [bar] "docs go here?" bar) in your REPL, followed by (doc foo).

23:38 The string is taken to be the first expression in the fn body.

23:39 twobitsprite: I just tried that, for some reasoning I'm get cannot resolve symbol: doc

23:39 TimMc: Try (use 'clojure.repl)

23:40 twobitsprite: yeah, you're right

23:40 just says nil

23:40 Drakeson: Well, one of these: 1. (obj. :method ...), 2. (obj :method ...). (2 requires implementing on infering callables on all java objects, considerably more than a syntax change)

23:41 twobitsprite: ohh well... guess I'll have to get used to reading the args list after the docstring...

23:41 ChongLi: yeah I don't like 2

23:41 TimMc: twobitsprite: I came to appreciate it.

23:42 docs before impl

23:42 Drakeson: ChongLi: why? (really looking for reasons, not to troll or anything)

23:42 TimMc: Well, no. Intent before specifics.

23:42 sjl: anyone know why (= #{-1 "-1" :-1} #{-1 "-1" :-1}) would return true in the REPL, but false when it's run as part of a test case?

23:42 ChongLi: because of how lisp treats the first element of a list

23:43 this would dramatically complicate that, making code a lot less readable

23:43 twobitsprite: TimMc: I can see that... but I just like to have the args count and names to have some context before reading the docs... often just the args list is enough to convey the gist

23:44 TimMc: sjl: Works for me in lein test.

23:44 twobitsprite: anyways, in an unrelated note... is there any way to get lein to use the nailgun server? possibly to speed it up a bit? It's unbearably slow :(

23:45 Drakeson: ChongLi: How about really making all java objects be callable with first arg the name of the method/`message'? (thinking about the lisp side for now, ignore how to do so).

23:45 tomoj: twobitsprite: well, when you do (doc foo), you get the name, args, then docs, at least

23:46 twobitsprite: tomoj: but that almost makes it worse... now it's just inconsistent...

23:46 ChongLi: Drakeson: in lisp you don't call objects

23:46 you call functions (and special forms)

23:46 twobitsprite: it's just a minor nit pick... but it's just kind of bothersome :-\

23:46 ChongLi: putting an object (a noun) at the front of a list just makes it really confusing and arbitrary

23:47 sjl: TimMc: okay now it's returning false at the repl

23:47 argggh

23:47 tomoj: (defn foo [] "doc")

23:47 TimMc: sjl: At the REPL, try *clojure-version*

23:47 tomoj: is that an empty function with a docstring, or a function that returns "doc" with no docstring?

23:47 sjl: TimMc: http://i.imgur.com/dd1bM.png

23:48 twobitsprite: tomoj: I'm not saying it *should* be that way.. I'm just lamenting that the current way seems awkward

23:48 xeqi: ChongLi: do you disapprove of ##({:a 1} :a) ?

23:48 lazybot: ⇒ 1

23:48 ChongLi: xeqi: no, because {:a 1} is a function

23:49 mathematically, a map is just a synonym for a function

23:49 TimMc: sjl: Ah, so it's the output of a fn. Try (map class (c/to-keys "-1")). I think you'll be surprised.

23:50 sjl: TimMc: Oh cool, one is an Integer and one is a Long

23:50 "Simple"

23:50 TimMc: In 1.4, that shouldn't matter...

23:50 sjl: and people wonder why I say you need to know Java to write Clojure...

23:50 tomoj: &[*clojure-version* (= (Long. "1") (Integer. "1"))]

23:50 lazybot: ⇒ [{:major 1, :minor 4, :incremental 0, :qualifier nil} true]

23:51 TimMc: &(= #{(Integer. -1) "-1" :-1} #{(Long. -1) "-1" :-1})

23:51 lazybot: ⇒ false

23:51 TimMc: Oho, so it is!

23:51 tomoj: hah

23:51 sjl: lol

23:51 TimMc: I had figured that one was a Symbol, since that would print the same way.

23:51 Is this a regression?

23:52 tomoj: appears still broken in 1.5.0-alpha4

23:52 sjl: &[(= (Integer. "1") (Long. "1")) (= #{(Integer. "1") (Long. "1")})]

23:52 lazybot: java.lang.IllegalArgumentException: Duplicate key: 1

23:52 sjl: &[(= (Integer. "1") (Long. "1")) (= #{(Integer. "1")} #{(Long. "1")})]

23:52 lazybot: ⇒ [true true]

23:52 sjl: wait what

23:53 TimMc: &(= {(Integer. -1) :val} {(Long. -1) :val})

23:53 lazybot: ⇒ true

23:53 Drakeson: ChongLi: I am suggesting that you can consider java objects as functions that have a first parameter that specify what to do. Not very much so with simple objects for which clojure functions work far better. I would consider a BufferedOutputStream something that should occupy the first place in the form as there are few clojure functions that make sanse to call on it.

23:53 ChongLi: I wouldn't mind the syntax if it was something like this

23:53 ((object :method) ...)

23:53 tomoj: whoa, bizarre

23:54 jkkramer: it's java's fault

23:54 &[(.hashCode (Integer. "-1")) (.hashCode (Long. "-1"))]

23:54 lazybot: ⇒ [-1 0]

23:54 TimMc: loljure

23:54 ChongLi: it'd be like object was just a map

23:54 sjl: oh man

23:54 twobitsprite: ChongLi: a "method dispatch" map?

23:54 sjl: it's only negative numbers

23:54 ChongLi: yeah

23:55 sjl: dram.test.context> (= #{(Integer. -1)} #{(Long. -1)})

23:55 er

23:55 &(= #{(Integer. -1)} #{(Long. -1)})

23:55 lazybot: ⇒ false

23:55 sjl: &(= #{(Integer. 1)} #{(Long. 1)})

23:55 lazybot: ⇒ true

23:55 sjl: dammit clojure

23:55 TimMc: jkkramer: Right, but I thought 1.3 or 1.4 fixed this.

23:55 jkkramer: there was a debate about whether/how to handle this

23:55 twobitsprite: ChongLi: are you familiar with dylan? they had an interesting method dispatch system, might be good to look at for something similar in clojure

23:55 ChongLi: I've heard of dylan, not familiar with it though

23:56 you could probably write a macro that'd turn java objects into method dispatch maps

23:56 I still wouldn't use it though :)

23:56 I'm pretty happy with the way things are, just trying to help Drakeson

23:57 Drakeson: ChongLi: Yeah, a dispatch map also makes.

23:58 twobitsprite: well... it's similar to the idea of abstractions... except dylan uses typed dispatch... but just like with maps, the type of the map being "called" would determine how the "argument" is dispatched

23:58 ChongLi: it'd be a companion to import-static

23:58 tomoj: https://groups.google.com/d/msg/clojure/7-hARL5c1lI/6Na-3J8fdFgJ one post about long/integer hashcode

23:58 twobitsprite: so, thinking of objects as maps of their methods seems fairly natural actually

23:59 tomoj: I guess the 'fix' was ##(class 1) ?

23:59 lazybot: ⇒ java.lang.Long

23:59 twobitsprite: ##(class -1)

23:59 lazybot: ⇒ java.lang.Long

Logging service provided by n01se.net