#clojure log - Jul 01 2010

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

0:00 qbg: Telling the compiler that time2 is a macro and that this is the function to call to get its expansion

0:00 itistoday: when it's compiled, what does it look like before it's called?

0:00 qbg: Here, the function executes (time `(dotimes [_# ~times] ~expr))

0:01 Say for instance the compiler is compiling (dotimes [n 10] (println n))

0:01 The compiler sees that dotimes is a macro and replaces this form with:

0:01 ,(macroexpand '(dotimes [n 10] (println n)))

0:02 clojurebot: (let* [n__3820__auto__ (clojure.core/int 10)] (clojure.core/loop [n (clojure.core/int 0)] (clojure.core/when (clojure.core/< n n__3820__auto__) (println n) (recur (clojure.core/unchecked-inc n)))))

0:02 qbg: And then proceeds to compile that form

0:02 itistoday: wait, but that's different, that doesn't have the backtick

0:02 KirinDave: Backtick is just a fancy tick.

0:03 qbg: What the macro's function returns is what macroexpand returns

0:03 KirinDave: Quasi-quote allows for symbols to have lexical annotations for additional processing.

0:03 But in the end it all is a quote.

0:05 qbg: (Actually it is what macroexpand-1 returns; macroexpand just expands that more)

0:06 hiredman: KirinDave: it's called syntax-quote in #clojure

0:06 itistoday: ok, but my original question hasn't been answered i don't think, or at least i don't understand: what happens when i define that macro I gave? what's time2?

0:06 before it's called with anything

0:06 qbg: In the case of (time2 (println "Hello") 10), the macro returns (for instance) (clojure.core/dotimes [___109__auto__ 10] (println "Hello"))

0:06 itistoday: macroexpand isn't being called at that point

0:06 hiredman: itistoday: do you understand how macros work?

0:07 itistoday: hiredman: no, that's what i'm trying to understand

0:07 hiredman: itistoday: if you don't, the follow up is, do you understanding what quoting is?

0:07 itistoday: hiredman: yes

0:07 qbg: The macro is only expanded when it is used

0:07 hiredman: so if the second macro was not a macro, but a function, what would it return?

0:09 itistoday: hiredman: ok, if i use the version where the syntax-quote is on the outside of time, it returns: (clojure.core/time (clojure.core/dotimes [___201__auto__ 100] 2))

0:10 and if i do the version where it's on the outside of dotimes it calls (time __) and returns (clojure.core/dotimes [___195__auto__ 100] 2)

0:10 so i'm guessing it calls: (time '(clojure.core/dotimes [___195__auto__ 100] 2))

0:10 hiredman: what calls that?

0:10 right

0:11 itistoday: ok, so a macro is: (time (eval (clojure.core/dotimes [___195__auto__ 100] 2))) ?

0:11 hiredman: no

0:11 itistoday: err: (time (eval '(clojure.core/dotimes [___195__auto__ 100] 2))) ?

0:11 hiredman: so the compile sees a list (OP A1 A1)

0:12 if OP is a macro, it looks up the macro (which is really just a function) and passes the unevaluated arguments to the macro's function

0:12 and replaces the list (OP A1 A2) with the result and continues compiling

0:13 itistoday: so it's like an eval...? but it's more efficient?

0:13 hiredman: no

0:14 it's like a compiler "plugin"

0:14 qbg: You are essentially extending the compiler

0:14 hiredman: eval still runs at runtime

0:15 qbg: Macros are source-to-source transformation

0:15 hiredman: if the compile runs (OP A1 A2) and the result is (OP2 A3) the compiler examines that

0:15 itistoday: alright... so that brings me back to: (defn time2 [expr times] (time `(dotimes [_# ~times] ~expr)))

0:15 hiredman: if OP2 is a macro then OP2's function is valled with A3

0:15 itistoday: it's assume dotimes is a function and not a macro

0:15 *let's

0:15 hiredman: no

0:16 itistoday: err... rather: (defmacro time2 [expr times] (time `(dotimes [_# ~times] ~expr)))

0:16 hiredman: no

0:16 itistoday: and assume dotimes is a function

0:16 hiredman: no

0:16 itistoday: stop saying no

0:16 :-p

0:16 what's wrong with that? you haven't heard my question

0:17 that's perfectly legitimate code, i'm trying to understand what happens when time2 is called if it's defined like that

0:18 qbg: Say the compiler is compiling (time2 2 5) in this case.

0:19 It then calls the macro function that defmacro defined for you

0:19 Lets simplify things and say it is essentially (fn [expr times] (time `(dotimes [_# ~times] ~expr)))

0:20 It then calls that fn with 2 and 5 (both unevaluated, but that doesn't make a difference here)

0:20 itistoday: k

0:20 qbg: The function runs, and the execution of the body of time is timed

0:20 And the return value of the body is returned from the function

0:21 In this case, (clojure.core/dotimes [___109__auto__ 5] 2)

0:22 itistoday: but i just called it and it returned nil

0:22 when i used macroexpand-1 on it, then it returned that

0:22 qbg: Now the compiler replaces (time2 2 5) with that, and continues by compiling that

0:23 Correct, because when you run (time2 2 5), it gets macroexpanded, and that returned code is then run

0:23 Another way to think about it:

0:23 Suppose eval didn't know about macros

0:24 But you wanted macros, so you wrote a function macroexpand-all that would perform the above transformation

0:25 So if it saw (time2 2 5) nested in its argument, it replaces it with (clojure.core/dotimes ...)

0:25 Now, we can define a macroexpanding eval as (defn my-eval [form] (eval (macroexpand-all form)))

0:26 So when you run (time2 2 5) in the repl, it is essentially running (my-eval '(time2 2 5))

0:27 Which is essentially (eval '(clojure.core/dotimes ...))

0:27 Or nil, because that is what dotimes returns

0:27 Now the macro is incorrect because time executes before the code is actually evaluated!

0:28 itistoday: oh that's another problem i had, i thought dotimes returned the last thing inside the body

0:28 qbg: Are you starting to understand?

0:29 itistoday: qbg: i'm going to re-read your statements with my understanding of dotimes return val, one sec

0:30 qbg: (Above time runs before you get to (eval '(clojure.core/dotimes ...)))

0:31 dnolen: itistoday: dotimes is all about side effects, it always returns nil.

0:31 ,mexpand-all

0:31 clojurebot: java.lang.Exception: Unable to resolve symbol: mexpand-all in this context

0:31 dnolen: darn

0:32 ,clojure.contrib.macro-utils.mexpand-all

0:32 clojurebot: java.lang.ClassNotFoundException: clojure.contrib.macro-utils.mexpand-all

0:32 itistoday: part of the problem in understanding this for me is getting out the idea that this is happening at runtime, which is hard because it *is* happening at runtime in the repl

0:33 qbg: You are invoking the compiler at runtime

0:34 itistoday: doesn't eval evoke the compiler?

0:34 so in the repl this is essentially the same as eval?

0:34 qbg: Yes

0:34 itistoday: *invoke

0:34 qbg: The 'e' in repl stands for eval...

0:34 itistoday: hehehe

0:35 qbg: You could call it the rmepl, (m = macroexpand), but that isn't as sexy.

0:35 dnolen: ,(macroexpand-1 '(dotimes [_ 10] 1))

0:35 clojurebot: (clojure.core/let [n__3820__auto__ (clojure.core/int 10)] (clojure.core/loop [_ (clojure.core/int 0)] (clojure.core/when (clojure.core/< _ n__3820__auto__) 1 (recur (clojure.core/unchecked-inc _)))))

0:37 dnolen: one of the major features preventing me from leaving Emacs is the ability to macroexpand anything underneath the cursor

0:38 itistoday: is calling (time2 2 10) in this case the same as calling (time nil)?

0:39 qbg: No

0:39 itistoday: ok good

0:39 so, here's my understanding so far, let me know where i'm wrong:

0:39 in the repl, I call: (time2 2 10)

0:41 a new function is created: (defn time2-autogen [] (time (dotime [__auto 10] 2))

0:41 by the compiler

0:41 qbg: No

0:41 itistoday: ok, so what is created by the compiler?

0:41 qbg: When time2 is defined, the extra function is created

0:42 itistoday: alright, let me try that:

0:44 i enter this in repl: (defmacro time2 [expr times] (time `(dotimes [_# ~times] ~expr))) -- that creates a new function: (defn time2 [expr times] (time (dotimes [__auto (eval times)] (eval expr))) ?

0:44 no, that doesn't seem right

0:44 qbg: No

0:45 dnolen: itistoday: a macro is just a regular function that is used to take unevaluated code and transform it into something else.

0:45 qbg: It creates (defn time2-autogen [expr times] (time `(dotimes [_# ~times] ~expr))

0:45 dnolen: isittoday: http://gist.github.com/459585

0:45 qbg: )

0:46 tomoj: what's this autogen stuff?

0:46 itistoday: dnolen: thanks, but that's not the macro

0:46 qbg: (It actually isn't named that)

0:46 itistoday: dnolen: the syntax quote is on the outside of dotimes, not time

0:47 dnolen: itistoday: but it's incorrect if it's not outside of time

0:47 qbg: (Just simplifying it a bit for explanation)

0:47 dnolen: That is the point

0:49 itistoday: qbg: ok, how about this: time2-autogen is a "placeholder", that's expanded as the compiler encounters calls to time2?

0:49 qbg: time2-autogen is called when the compiler encounters a call to time2

0:52 itistoday: qbg: http://paste.pocoo.org/show/232109/

0:52 qbg: No

0:52 arrummzen: In Clojure: Is there an easy way to pass functions from worker threads to a main thread for execution (like passing Runnables to the Swing Event Queue to be executed in regular Java).

0:53 itistoday: qbg: well what then??

0:53 qbg: When the compiler sees, (time2 2 10), the compiler calls (time2 '2 '10)

0:53 Right at that time. Not at run time.

0:53 (time2-autogen '2 '10) that is

0:54 time2-autogen runs like any other function

0:54 time does its thing and prints "Elapsed time: x msecs"

0:55 dnolen: itistoday: http://gist.github.com/459585

0:55 updated my gist showing both version of the macro

0:55 notice that lot of code does not get generated in the second version.

0:55 qbg: time2-autogen then returns (clojure.core/dotimes ...)

0:56 scottj: arrummzen: you could probably call whatever method you do in java and pass a function since they implement Runnable

0:56 dnolen: anyways guessing or trying to intuit what is going on is much harder than just seeing what code gets generated.

0:56 qbg: The compiler then works on that instead of (time2 2 10)

0:56 itistoday: qbg: time measured the time of what then?

0:57 qbg: The execution of `(dotimes [_# ~times] ~expr)

0:57 itistoday: dnolen: thanks, looking it over

0:57 qbg: Which is very fast

0:57 itistoday: qbg: what does that sentence mean? "The execution of `(dotimes [_# ~times] ~expr)"

0:57 how does that execute?

0:58 is it the creation of a list? is it macroexpansion? what is it?

0:58 qbg: `(dotimes ...) executes and returns (clojure.core/dotimes ...)

0:58 itistoday: so it measures the time it takes macroexpand to run?

0:58 qbg: It creates the list, fully qualifies the symbols, etc.

0:59 But it does not execute the resulting the list

1:00 itistoday: qbg: ?

1:00 arrummzen: I think a blocking queue is the standard way to do it in Java (producer makes runnables for consumer to execute)... I'm just learning clojure and was wondering if there was a more standard "clojure" way of doing it (Clojure seems to have a lot of interesting clojure specific methods for dealing with concurrency) .

1:00 qbg: Lets do (defn make-code [expr times] `(dotimes [_# ~times] ~expr)))

1:01 What is happening then is that time2-autogen is basically executing (time (make-code expr times))

1:01 So it just timing how long it takes (make-code ...) to execute

1:01 itistoday: qbg: "so it measures the time it takes macroexpand to run?"

1:02 qbg: Close

1:02 itistoday: what's the difference?

1:03 qbg: Macroexpand here isn't really doing anything other than executing `(dotimes ...)

1:03 itistoday: but that's what you said!

1:03 said by qbg: "The execution of `(dotimes [_# ~times] ~expr)"

1:04 qbg: But time isn't timing how long macroexpansion actually takes

1:04 itistoday: argh...

1:05 qbg: If the macro's body was (let [foo (really-long-computation)] (time `(dotimes ...)))

1:05 Then macroexpansion would take much longer than what time would report

1:05 As time is only timing `(dotimes ...)

1:06 And not how long it takes time2-autogen to run

1:07 This is really fine nitpicking though...

1:07 dnolen: itistoday: qbg explanation is roundabout :) if you think about it side effects are pretty meaningless in macros. timing, printing, those have no effect over the code that is going to get generated. in the second (incorrect) version of time, you're just measuring the time to return a quoted list.

1:09 qbg: The problem with the macro is that time is being evaluated at the wrong time.

1:09 itistoday: dnolen: does a macro's body run at compiletime?

1:09 qbg: Yes!

1:09 itistoday: i.e. (demacro foo [] (+ 1 1))

1:09 scottj: arrummzen: an agent sounds like your swing thread example. you could send work for it to do from other worker threads.

1:10 qbg: (macroexpand '(foo)) there would return 2

1:12 itistoday: everything that's syntax quoted get's "macroexpanded" at compile time and the result of that is turned into a function?

1:12 (with the placeholders replaced with the called values?)

1:12 wherever there's a tilde?

1:13 qbg: This might sound confusing, but that happens at runtime

1:13 Only inside a macro's body, runtime is compile time...

1:14 itistoday: is there a document somewhere that explains this in depth?

1:14 arrummzen: scottj: Yep, that looks like what I'm searching for. Thanks.

1:15 qbg: Take for example (if nil `(~(throw (Exception. "Foo!"))))

1:15 itistoday: is that inside a macro?

1:15 qbg: If syntax-quote worked at compile time, this code would not compile

1:15 Just at the repl

1:16 Now try this: (defmacro death [] (throw (Exception. "Foo!")))

1:16 And then (if nil (death))

1:17 itistoday: throws an exception

1:17 qbg: Yes, because the macro throws an exception

1:17 itistoday: because the code is executed at compile time

1:17 qbg: Correct.

1:18 itistoday: syntax-quote is not executed at definition of macro

1:18 but it is replaced, by the compiler, when the function is called?

1:18 at compile time?

1:19 qbg: Correct, syntax-quote is run when the macro is expanded

1:19 (I'm assuming we are talking about the syntax quote in time2)

1:19 itistoday: sure

1:19 ok so there are two stages...

1:19 *both* in the compiler

1:20 stage 1 is macro definition, and at that stage anything that's not syntax-quoted is run

1:20 syntax quoted stuff is left as is as a list

1:20 correct so far?

1:20 qbg: By macro definition, do you mean defmacro?

1:21 itistoday: I mean when the compiler comes across a call to defmacro

1:21 tomoj: :(

1:21 qbg: defmacro is like defn in that its body is not evaluated when it is compiled

1:22 itistoday: okk...............

1:22 so 1 stage

1:22 not 2

1:22 let me try again

1:23 stage 1 (the only stage), happens when the compiler comes across a call to a macro

1:23 like: (foo), where foo is (defmacro foo [] (System/exit 0))

1:23 at that point its body is run?

1:23 so if i had a call to (foo) in my code it would fail to compile?

1:24 qbg: The compiler sees (foo) so it expands it

1:24 itistoday: err... evaluates it

1:24 qbg: The expansion function then quits the JVM

1:24 itistoday: there's nothing to expand there though right?

1:24 expand only refers to syntax quote?

1:25 qbg: Expand refers to when you run (System/exit 0) in your above case

1:25 itistoday: ok, so it expands/evaluates it

1:25 here expand is the same as evaluate

1:25 it compiles and runs the code = evaluates it

1:26 right?

1:26 qbg: expanding the macro doesn't evaluate the code the macro returns

1:26 That is the main difference

1:27 In the case of (foo), the macro doesn't return anything because you quit the JVM first.

1:27 itistoday: ok, so expanding is evaluating, but it's referring to evaluating the non-quoted portion

1:28 we need to get this terminology consistent :-)

1:28 something is being evaluated here

1:28 that would be (System/exit 0)

1:28 qbg: Expanding is running the function that defmacro defines

1:28 In this case, the function runs (System/exit 0)

1:29 Bahman: I'm trying to understand 'require', 'refer' and 'use'. Can anyone please tell me what is difference between 'loading' and 'refering to' a library?

1:30 itistoday: qbg: ok, fine, whatever. it runs the non-quoted part of the body?

1:30 qbg: Yes, it evaluates the body

1:33 itistoday: ok... i think i'm getting it

1:33 qbg: It is really simple once you get it, I promise. :)

1:34 itistoday: so, back to the time2 macro, it calls: (time `(dotimes [_# ~times] ~expr)) ?

1:34 qbg: Yes!

1:34 itistoday: which is basically: (time '(dotimes [_# ~times] ~expr)) ?

1:34 (at that point)

1:34 qbg: Syntax-quote does more than regular quote

1:34 itistoday: i.e., it calls time on a list with dotimes as its first element, an array as its second, ,etc

1:35 yes, but what does it do then

1:35 at that point in time, what does it look like?

1:35 qbg: It times how long it takes to turn `(dotimes ...) into (clojure.core/dotimes ...)

1:35 Think of syntax-quote as being a function call

1:36 itistoday: ok but what *exactly* is it

1:36 qbg: Like (quasiquote '(dotimes [_ (unquote times)] (unquote expr)) <environment>)

1:36 raek: good point

1:36 itistoday: ahhhhh, that's much nicer :-)

1:37 raek: ,(read-string "`(a ~b ~@c)")

1:37 clojurebot: (clojure.core/seq (clojure.core/concat (clojure.core/list (quote sandbox/a)) (clojure.core/list b) c))

1:38 qbg: (I wrote this in a language I'm hacking on in Clojure)

1:39 syntax-quote is just a really nice form for something that is essentially a function

1:39 raek: Bahman: require = make sure library is loaded, refer = make vars of another namespace available as if they were in the current namespace, use = require + refer

1:39 qbg: *function call

1:39 raek: import = like refer, but for java classes

1:40 itistoday: qbg: ok, but does it run quasiquote?

1:40 raek: load is a more low level construct

1:41 itistoday: in other words, it calls quasiquote, and times how long that takes?

1:41 qbg: Yes

1:42 (As raek showed above, Clojure doesn't use my quasiquote function, but the effect is the same)

1:42 raek: ,quasiquote

1:42 clojurebot: java.lang.Exception: Unable to resolve symbol: quasiquote in this context

1:43 qbg: How Clojure does it is an implementation detail

1:43 itistoday: well, i notice that it's evaluating b and c there

1:43 raek: ah, yes. in scheme, `(a ,b ,@c) turns into (quasiquote a (unquote b) (unquote-splicing c) or something

1:44 itistoday: so it times how long it takes to evaluate b and c and then call the function quasiquote, which returns something?

1:44 Bahman: raek: Thanks...but I don't understand 'loading' yet. Does 'refer' involve 'load'?

1:44 itistoday: or, in my macro, it times how long it takes to create a seq and evaluate times and expr?

1:44 raek: I think refer calls load under the hood

1:44 qbg: Yes

1:44 raek: if that library hasn't been loaded already

1:45 Bahman: Hmmm...

1:45 itistoday: ok and that's it right?

1:45 raek: (time `(a ~b ~@c)) is *exaclty the same* as (time (clojure.core/seq (clojure.core/concat (clojure.core/list (quote sandbox/a)) (clojure.core/list b) c)))

1:46 ,(read-string "(time `(a ~b ~@c))")

1:46 itistoday: qbg: there's nothing else right? to time2?

1:46 clojurebot: (time (clojure.core/seq (clojure.core/concat (clojure.core/list (quote sandbox/a)) (clojure.core/list b) c)))

1:46 itistoday: it times how long it takes to evaluate times, expr, and then to create a seq out of them?

1:46 raek: the syntax-quote to seq/concat/list/quote transformation is done when the expression is read

1:46 qbg: Time then returns that seq

1:47 So that becomes what the macro's body returns

1:47 And that is what the macro expands to.

1:47 Bahman: raek: If that's true why 'use' is introduced? Since 'refer' does the loading too.

1:47 qbg: That is all what time2 does

1:47 itistoday: qbg: OK... and that part gets run at runtime?

1:48 raek: Bahman: no, refer does not do the loading

1:48 qbg: Yes, the return value of time2's body is what is run at runtime

1:48 raek: one rarely uses that one by its own

1:48 'use' does its refering part by calling 'refer'

1:48 itistoday: qbg: OK. Thank you *SO* much for taking my shit and explaining this!

1:49 (and having patience)

1:49 qbg: Finally understanding?

1:49 itistoday: yes. i'm pretty sure. :-D

1:49 definitely good enough to write macros i think :-P

1:49 qbg: So eval is essentially (defn my-eval [form] (eval (macroexpand-all form)))

1:49 raek: and its loading part by calling 'load' (if not already loaded, or if :reload or :reload-all i given)

1:49 qbg: The form is expanded, and then later evaluated.

1:50 A macro is just a function.

1:50 That returns code.

1:50 raek: the point is: there's nothing macro-y about the evaluation of syntax-quote

1:51 itistoday: and in the end, it's evaluating byte-code, not interpreting a list at runtime, right?

1:51 raek: yes, and when its called in a macro, it gets passed the code instead of the valuesof its arguments

1:52 qbg: Yes, clojure is compiler only.

1:52 raek: when a function is read, it's compiled

1:52 Bahman: raek: Thank you. Didn't grasp it yet. Perhaps better to take a look at the source.

1:52 raek: Bahman: have you seen http://clojure.org/libs ?

1:53 Bahman: raek: No.

1:53 Now reading it.

1:53 itistoday: macros are plugins to the compiler, i love that analogy. :-)

1:53 raek: Bahman: peeking into the clojure source can be a very good thing to do every now and then

1:55 qbg: Just don't make your macros be this complicated: http://www.lispworks.com/documentation/lw51/CLHS/Body/m_loop.htm#loop

1:55 sergey_miryanov: hi all :)

1:55 itistoday: qbg: hehe, sure thing. :-)

1:55 qbg: i don't think you'll have to worry about that. ;-)

1:56 qbg: And they say lisp has no syntax...

1:56 raek: they just call it mini-languages instead...

1:57 well, there's still a difference. both ordinary code and mini-language code share the same surface syntax

1:57 lists

1:59 qbg: Writing a functional setf might be cool...

2:00 sergey_miryanov: why I can't rebind + in macro? it's a my bug or clojure?

2:00 http://paste.lisp.org/display/112063

2:01 raek: sergey_miryanov: that's symbol capture

2:01 qbg: For the let based solution, you want ~'+ instead of + or '+

2:01 raek: a thing clojure macos was built to avoid

2:01 qbg: binding doesn't work because + is being inlined

2:02 raek: because it can accidentally yield very strange results

2:03 if you let, say, the symbol 'x, every use of that in the macro body will now do something else

2:03 but in your case, this was maybe the point

2:03 sergey_miryanov: qbg, thanks!

2:03 raek: I also recommend looking into (binding [+ some-other-fn] ...code...)

2:03 this is a runtime construct

2:04 it dynamically rebinds + for the executing thread

2:04 sergey_miryanov: raek, yes, I want do something else in macro

2:04 raek: ,(binding [+ -] (+ 1 2))

2:04 clojurebot: 3

2:04 sergey_miryanov: but binding doesn't work with macro

2:04 itistoday: so, clojure is dynamically scoped?

2:04 Bahman: raek: Thanks for the help...Finally I seem to get how it works.

2:05 raek: hrm, why did that example not work...

2:05 tomoj: <qbg> binding doesn't work because + is being inlined

2:05 raek: /facedesk

2:05 right.

2:06 qbg: itistoday: Clojure has both lexical and dynamic scope.

2:06 raek: I should probably mention clojure.contrib.generic.arithmetic

2:06 not dynamically scoped variables, but dynamically bound

2:06 the scope is still lexical

2:07 that it, the way a symbol is resolved into a var

2:07 itistoday: that is kinda weird

2:07 example: (defn foo [] (println x))

2:07 that gives an error if x isn't defined

2:07 so i define x ahead of time

2:07 then i can define the function

2:08 but when i call the function it will print whatever is in 'x' at the time

2:08 that's dynamic binding, right?

2:08 qbg: Yes

2:08 raek: late binding at least

2:08 itistoday: so how do you create a closure in clojure? or do you not do that?

2:09 qbg: Like you do in scheme.

2:09 raek: (let [x 1] (fn [] x))

2:09 itistoday: ok, cool, so let creates a closure, anything else?

2:10 qbg: Technically the closure is created by (fn ...)

2:10 raek: well, fn closes over the environment it is made in

2:10 qbg: The way that Clojure handles dynamic scope is better than the way CL does

2:11 itistoday: no... it doesn't

2:11 raek: (defn make-counter [] (let [count (atom 0)] (fn [] (swap! count inc))))

2:11 itistoday: (def foo (fn [] (println x)))

2:11 that doesn't create a closure

2:11 (foo, not make-counter)

2:11 raek: (def c (make-counter))

2:11 (c) => 1

2:11 (c) => 2

2:11 itistoday: so it has to do with let, let creates the the closure... "over" fn

2:12 qbg: Let just creates a nested environment

2:12 itistoday: ohhhhhhhhhhhhhhhhh

2:12 qbg: (fn ...) closes over its lexical environment

2:12 itistoday: *clicks*

2:13 yes, sometimes i sounds like a 3rd grader :-p

2:13 and spell like one too

2:13 raek: (def x 5) (defn f [] x) (defn g [] (let [x 3] (f)))

2:13 if variables in clojure had dynamic scope, calling g would yield 3

2:14 qbg: Or if Clojure was CL

2:14 itistoday: great example, thanks

2:14 but calling g yields 5 because the original environment is what counts

2:14 raek: but which variable x refers to in f is determined lexically

2:14 qbg: Which is why Clojure > CL

2:14 raek: that is, from the structure of the code

2:15 qbg: Well, x in (defn f ...) is dynamically scoped

2:15 raek: the global var x can be dynamically rebound

2:15 itistoday: right

2:15 qbg: It is just that the x in (let [x 3] (f)) is another variable

2:15 itistoday: if you change x it will change what g returns

2:15 raek: yes, scoping is about "which variabel"

2:15 itistoday: that's what i said though

2:15 raek: but bidning is about "which value"

2:16 itistoday: so binding is totally dynamic

2:17 had it been (defn f [] (binding [x x] x)) it would return 3 when g is called right?

2:17 raek: can be if (binding) is used, so potentially, yes

2:17 qbg: No

2:17 raek: (binding [x x] ...) is basically a no-op

2:17 except that it allows x to be assigned to

2:18 because it now has a mutable thread-local binding

2:18 itistoday: assigned to using what?

2:18 qbg: The x is g is not the x from (def x 5)

2:18 raek: set!

2:19 itistoday: raek: is that done often?

2:19 * qbg points to the details at http://clojure.org/evaluation

2:19 raek: (def x 1) (binding [x x] (println x) (set! x 2) (println x)) (println x)

2:19 => 1, 2, 1

2:20 itistoday: not very often, no

2:20 qbg: I almost ever using binding

2:20 raek: but it can be handy when interfacing with callback-based apis

2:20 qbg: *never

2:20 itistoday: ok, well then back to the example with f and g functions, how do change that around so that g prints 3?

2:20 qbg: (defn g [] (binding [x 3] (f)))

2:21 raek: (defn g [] (let [x 3] (f))) -> (defn g [] (binding [x 3] (f)))

2:21 itistoday: :-)

2:21 raek: x in f still refers to the global var x, which value is rebound to 3

2:21 itistoday: duh, i should've remembered that

2:21 ok, i think my brain is tired

2:21 raek: ok, ok. I just wanted to be clear :)

2:21 itistoday: you guys should be payed to teach clojure :-p

2:22 appreciate the help much!

2:22 raek: oh, I read "duh, i remembered that"

2:23 anyway, thread local bindings introduced by 'binding' is... thread local

2:23 so they avoid the concurrency issue, rather than adressing it

2:23 qbg: binding + lazy sequences = a recipe for trouble

2:24 raek: hrm, yeah

2:24 the next element can be forced in any thread

2:24 some of them might have some of the vars rebound

2:24 that doesn't sound very nice

2:24 itistoday: interesting... but a lot of code isn't very multithreaded though

2:25 qbg: And it can be force outside of the current dynamic scope

2:25 itistoday: you guys have seen this right: http://meshy.org/2009/12/13/widefinder-2-with-clojure.html

2:25 raek: itistoday: using the other concurrency primitives (atoms, refs, agents) is still recommended, thoug

2:26 itistoday: raek: right, but sometimes if you really want performance you can avoid them but be careful (like in that link)

2:27 raek: where does it use set! ?

2:28 qbg: Well as it is 1:30 am where I live, good night all

2:28 sergey_miryanov: nigth!

2:28 itistoday: qbg: night!

2:28 raek: hrm, nevermind

2:28 night

2:29 itistoday: raek: you're right, it uses some Java stuff, but not set!...

2:30 well anyway, it's just one possible way of getting performance, i'll know better later though, after i've spent more than 48 hours with clojure :-p

2:31 qbg is in the timezone to the left of me if you're viewing earth straight on with north at the top.

2:31 erm.. i mean it's 2:30 AM, time for bed

2:31 thanks for the help! ciao for now

3:52 LauJensen: Good morning all

4:00 DarthShrine: Evening, LauJensen

4:47 esj: (greetings)

4:48 DarthShrine: Yarr.

5:45 cais2002: ,"hello"

5:45 clojurebot: "hello"

5:46 cais2002: ,'does-leiningen-work-in-cygwin?

5:46 clojurebot: does-leiningen-work-in-cygwin?

5:47 zmila: leiningen works in command line

5:47 cais2002: I am getting this error "Exception in thread "main" java.lang.NoClassDefFoundError: jline/ConsoleRunner", am I supposed to manually configure CLASSPATH to point to clojure.jar?

5:48 lein.bat works

5:48 but lein.sh does not work inside cygwin

5:48 zmila: as windows user i don't know about .sh

5:49 cais2002: yeah, I can run lein.bat under a normal command prompt

5:52 esj: cais2002: just guessing here but it could be to do with the different in classpath delimiters in win vs linux. One one its : and the other is ; , causing it not to understand the classpath ?

5:52 cais2002: I never got it to work right.

5:55 cais2002: there is a leiningen for powershell with which I had much better luck

5:55 cais2002: one stupid question, how do I exit from the REPL?

5:56 esj: control C or D

5:59 cais2002: hmm, control D just gives ^D as input on REPL, Control C terminates the entire shell window, running it in Git Bash. ^D works if running from normal Windows command prompt

6:14 ,(System/exit 0)

6:14 clojurebot: java.security.AccessControlException: access denied (java.lang.RuntimePermission exitVM.0)

6:14 cais2002: this is what I have to do to come outt of the REPL in cygwin

6:20 Chousuke: try ^Z

6:29 cais2002: ^Z works

6:30 ^D works when I run REPL via jline

7:43 bartj: cemerick: does docuharvest extract (skills, experience, etc.) out of job resumes ?

7:43 cemerick: bartj: indeed, one of the verticals we're working on

7:44 bartj: cemerick: I have just uploaded a job CV and it wasn't able to extract any data...or am I choosing the wrong option

7:45 cemerick: bartj: No document-type-specific processing is live on the public site yet.

7:45 bartj: cemerick: when will it be ?

7:47 cemerick: bartj: when it's ready ;-) We're finishing up first cuts of the simple imaging-related stuff first, and then we'll be focusing on packaging all the structured data extraction stuff we've accumulated.

7:48 bartj: Which job type did you try just now, form data extraction?

7:49 bartj: cemerick: yes

7:50 cemerick: bartj: right, so that's only for interactive PDF forms (i.e. those that you can edit directly in Acrobat, etc)

7:51 bartj: cemerick: no sorry, the extract pdf form data

7:52 cemerick: right, same thing

7:52 bartj: If you haven't already, subscribe to the mailing list or follow @docuharvest to get new service announcements. I'll likely not post announcements in clojure-related forums.

7:53 bartj: cemerick: cool, thanks!

8:40 thetafp: (fn i [x] x)

8:45 chouser: a.k.a. identity

9:46 dr_benway: hello all. newbie question: i've built a jar with "lein jar", attempting to run it (with clojure jars on the classpath) results in java.lang.NoClassDefFoundError: clojure/lang/IFn

9:46 creating an uberjar and running it works fine, so it's clearly something wrong with my classpath, but can't figure out what... any tips?

9:46 ohpauleez: yeah, weird, I was just going to try to tell you to do that

9:46 arohner: dr_benway: sounds like clojure.jar is not on your classpath

9:47 how are you starting the process?

9:48 dr_benway: java -cp lib/clojure-1.1.0-master-20091231.150150-10.jar:lib/clojure-contrib-1.0-20091212.214557-33.jar -jar euler.jar

9:49 arohner: dr_benway: -cp and -jar are not compatible

9:50 chouser: -cp is ignored if you specify -jar

9:50 dr_benway: ...really!?

9:50 well, i've tried setting the CLASSPATH environment variable too - same problem

9:51 chouser: -jar causes all other classpath specs to be ignored

9:51 dr_benway: how *are* you supposed to set the classpath if you're using -jar?

9:51 LauJensen: chouser: I just checked the man page for java, and it says

9:51 By default, the first non-option argument is the name of the class to be invoked. A fully-qualified class name should be used. If

9:51 the -jar option is specified, the first non-option argument is the name of a JAR archive containing class and resource files for the

9:51 application, with the startup class indicated by the Main-Class manifest header.


9:51 The Java runtime searches for the startup class, and other classes used, in three sets of locations: the bootstrap class path, the

9:51 installed extensions, and the user class path.


9:51 Doesnt that lead you to believe that it checks the jar, and the user class path ?

9:53 chouser: those paragraphs don't seem to address the point. In my experience, -jar is useless except for uberjars that have everything you need.

9:54 LauJensen: I guess logically, the point of a jar is defeated if you have to call in resources from outside

9:55 dr_benway: so is there any way to "run" a (non-uber) jar?

9:55 there must be some mechanism for resources to be loaded from the class path, right?

9:55 LauJensen: dr_benway: No, and I dont think its intended. Jars are to be embedded, uberjars are to be run

9:57 chouser: dr_benway: sure, just list all the .jars with -cp and then name the class you want to launch.

9:57 dr_benway: chouser: thanks, i'll give that a try

9:58 chouser: java -cp clojure.jar:contrib.jar:euler.jar euler.MyMainClass ...or whatever

9:58 dr_benway: chouser: yep, that got it - thanks a lot :)

10:00 LauJensen: ah right, sorry I forgot the obvious :)

11:36 jcromartie: so I think my images-in-REPL idea could happen with a simple hack in Emacs

11:36 considering this is possible: http://julien.danjou.info/blog/2010.html#M%2Dx%20google%2Dmaps

11:37 er, this is a better link http://julien.danjou.info/google-maps-el.html

11:44 arohner: ,( (fn [[]] (println "hello world!")))

11:44 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (0) passed to: sandbox$eval4826$fn

11:45 arohner: ,( (fn [[]] (println "hello world!")) 1)

11:45 clojurebot: hello world!

11:45 arohner: I find that very strange

11:48 hiredman: ,( (fn [& []] (println "hello world!")))

11:48 clojurebot: hello world!

12:00 Licenser: jcromartie: I think there is a graphical REPL already

12:00 hiredman: you know whenever I read your name I'm thinking 'contractkiller'

12:01 hiredman: Licenser: right

12:02 Licenser: don't ask me why, but seriousely

12:02 did I discover your try identity and you try to kill me now? :P

12:02 if so can you wait untill I've eaten my pudding, it would be frustrating to makeit and then get killed before being able to eat it

12:05 hiredman: in william gibson's book, count zero, an ai posing as a voodoo diety possesses a girl and refers to mercenary she is traveling with as "hired man"

12:07 Licenser: that of cause is a perfectly simple and logical explenation of your name, and there I was about to go all esotheric and guess you're a guy whith a job

12:15 jcromartie: Licenser: it displays images? like DrScheme?

12:15 Licenser: yes it did

12:15 I'm not sure who made it so

12:16 but not in the EMACS REPL, it was a stand alone one

12:19 hiredman: http://github.com/hiredman/Repl

12:21 * technomancy needs to re-read count zero.

12:21 technomancy: it's just that every time I read Neuromancer it's so intense that I need a break.

12:21 * pjstadig needs to read some Gibson

12:22 pjstadig: its on The List

12:23 technomancy: pjstadig: you can pick a new nick from Mona Lisa Overdrive; then we'll have the Sprawl trilogy covered.

12:24 esj: "Anathem" by Stephenson, part of that gang, is awesome.

12:24 pjstadig: technomancy: nice

12:24 wait? what's wrong with my current nic ?!?

12:24 hehe

12:25 mattrepl: real name vs. screen name, can never decide

12:44 alexyk: how do I get the CPU time of the current process at a given point in the program?

12:46 i.e. is there any equivalent in the JVM for the venerable unix tools to that extent?

12:47 * alexyk the silence o the JVM is deafening

12:47 * fogus has never read Gibson

12:53 alexyk: did I miss informative anwers on CPU time?

12:53 fogus: go you mean Gibbon?

12:53 do you

12:54 fogus: alexyk: I mean William Gibson

12:55 alexyk: ok. I still didn't read Gibbon but we all should!

13:04 arete: alexyk: http://nadeausoftware.com/articles/2008/03/java_tip_how_get_cpu_and_user_time_benchmarking

13:04 alexyk: arete: yep, my google got there first! :)

13:04 so (time ...) is just clock time?

13:05 wall?

13:07 AWizzArd: alexyk: time is a macro, so you can expand it

13:08 ,(macroexpand-1 '(time nil))

13:08 clojurebot: (clojure.core/let [start__3913__auto__ (. java.lang.System (clojure.core/nanoTime)) ret__3914__auto__ nil] (clojure.core/prn (clojure.core/str "Elapsed time: " (clojure.core// (clojure.core/double (clojure.core/- (. java.lang.System (clojure.core/nanoTime)) start__3913__auto__)) 1000000.0) " msecs")) ret__3914__auto__)

13:08 alexyk: AWizzArd: is nanoTime wall clock then? :)

13:09 AWizzArd: Lookup the System class in the documentation.

13:10 slyrus: so how do I tell my leiningen project to use _my_ clojure.jar not some random jar maven downloads from the internets?

13:13 AWizzArd: though the funny thing is: why is it (clojure.core/nanoTime)? As if this were a fn, and as if this had to be wrapped in a list.

13:14 ,(. System bock.bock.bock/nanoTime)

13:14 clojurebot: 1278004962007300000

13:14 AWizzArd: ,(. System (master.of.barakesh/nanoTime))

13:14 clojurebot: java.lang.RuntimeException: java.lang.ClassNotFoundException: master.of.barakesh

13:14 alexyk: which animal makes the "bock bock bock" sound?

13:14 is it a badjer?

13:15 Hodapp: a chicken?

13:15 alexyk: Hodapp: is it the official chicken sound in English?

13:15 AWizzArd: In my Clojure funnily (. System (master.of.barakesh/nanoTime)) works :)

13:16 ,(System/nanoTime)

13:16 clojurebot: 1278005065829352000

13:16 alexyk: AWizzArd: then you have the said master present in your clojure! :)

13:16 Hodapp: alexyk: I don't believe there is an "official" chicken sound in English.

13:16 "cluck" is probably the closest to what we have.

13:16 alexyk: Hodapp: there are, e.g. a horsey says neigh, while in Russian it's игого.

13:16 AWizzArd: Surprisingly I have no such master ns in my clj. But anyway, I wonder why it is not simply (System/nanoTime), but this clojure.core/nanoTime instead.

13:17 alexyk: childrens' books define the official animal sounds in each language

13:17 Hodapp: that example proves nothing about its officiality >_<

13:17 alexyk: Hodapp: look up kids' books! they are very standard-conforming.

13:18 Hodapp: right, cluck preempts bock.

13:18 bock is a fork of cluck.

13:18 * alexyk still waits for the badger sound

13:20 AWizzArd: rhickey: is that clojure.core/nanoTime still a relict from pre 1.0 versions?

13:24 hiredman: AWizzArd: . maybe ignore the namespace part of symbols for easy use inside macros

13:25 ,`(. foo (bar))

13:25 clojurebot: (. sandbox/foo (sandbox/bar))

13:27 slyrus: answering my own question, use dev-dependencies instead of dependencies

14:02 Licenser: a very different question what is the difference between (. object method) and (. object (method))?

14:20 chouser: Licenser: no difference, except perhaps the latter can never be a field lookup

14:41 yacin: is there an easy way to make certain levels of clojure.contrib.logging go to a file?

14:41 so (info ...) will go to a file, but the others won't?

14:41 or they go to different files?

14:47 DeusExPikachu: Chousuke: continuing our conversation from yesterday, I couldn't extend the type returned by reify because I didn't have a reference to the type's class, but we didn't consider the function (class x) which should allow us to use extend-type on it. Also just tried it and it worked. Thought just wanted to mention that

14:52 Drakeson: what is the difference between re-matches and re-find?

14:52 ,(re-find #"a(b(c))" "abc")

14:53 clojurebot: ["abc" "bc" "c"]

14:53 Drakeson: ,(re-matches #"a(b(c))" "abc")

14:53 clojurebot: ["abc" "bc" "c"]

14:53 chouser: ,(re-find #"c" "abc")

14:53 clojurebot: "c"

14:53 chouser: ,(re-matches #"c" "abc")

14:53 clojurebot: nil

14:53 chouser: with matches the regex must match the *whole* string

14:53 ,(re-matches #"a" "abc")

14:53 clojurebot: nil

14:53 chouser: ,(re-matches #"a.." "abc")

14:53 clojurebot: "abc"

14:54 Drakeson: chouser: I see, thanks

15:04 Licenser: chouser: tank you (belately)

15:04 chouser: Licenser: :-)

15:05 Licenser: Sometimes I wonder what it is that got me stuck with clojure, the language o the comunity

15:05 or the glue that the I dripped on my c, l and j keys

15:19 rys: both

15:19 For me anyway

15:29 Licenser: rys: I gave 3 options you can't say both in a response

15:30 actually you can but its evil and mean

15:30 rys: My c, l and j keys are glue free ;)

15:30 Be hard to write clojure without them

15:31 Licenser: well you still have them but you have three fingers fixed there :P

15:32 rys: The language is excellent, but surely the reason people keep hacking on it, or at least did in the last 2yrs or so, was because of this place and the mailing list?

15:33 Licenser: *nods* my feeling too, it is a good language but the comunity is what it makes it exeptional beyond other good langages

15:35 rys: I don't say much in here, but I read almost everything, and it's an epic way to pick various things up and learn by example. Every time someone comes in and asks a Q, I get something for free from the answer. Same with the ML

15:38 bhenry: i try to help in here every time i think i know the answer. and i learn a great deal from people correcting me.

15:40 * Licenser nods

16:15 kencausey: 14

16:15 oops

16:35 puredanger: I was on here a while back and someone (Rich?) said that there would be a generated method on records to allow you to create a record with a map (of possibly partial keys) instead of using the (Foo. etc etc)

16:35 anyone know if that exists yet and if so how to use it?

16:35 OR when it does exist, what will it be called?

16:36 we've rolled our own atm but would be nice to throw that away

16:37 rhickey: puredanger: that did not make it into 1.2

16:37 will follow shortly

16:37 puredanger: rhickey: damn, that is tragic

16:37 I loathe having (Foo. nil nil nil nil nil nil) etc all over

16:39 qbg: How close is 1.2?

16:39 puredanger: we used something like (defn set-record-fields [initial value-map]

16:39 (reduce (fn [source [key value]] (assoc source key value))

16:39 initial value-map))

16:39 rhickey: qbg: beta any day now

16:39 qbg: Nice.

16:39 puredanger: wrapped up in a helper to generate new ones from an empty record or an existing one

16:39 rhickey: puredanger: that's pretty inefficient

16:40 puredanger: rhickey: yes

16:40 rhickey: it would be better if it was in the generated class so I didn't have to write such inefficient code ;)

16:41 qbg: rhickey: Any plans for 1.3 yet?

16:42 dnolen: puredanger: would be pretty easy to write a write a macro that expand into a let, and a fn that uses this macro. then you can provide your initial values however you want mapped to whatever fields you want in whatever order you want.

16:42 rhickey: qbg: yeah, what we are talking about now, plus all that prim/num stuff

16:42 puredanger: dnolen: yes, we were trying to avoid that if a better built-in way was coming

16:43 dnolen: but given that, we'll probably bite the bullet on the macro as we need one per record for the empty case

16:44 rhickey: does this post correctly capture the best way to use records from another namespace? http://tech.puredanger.com/2010/06/30/using-records-from-a-different-namespace-in-clojure/

16:44 slyrus: one thing that annoys me about having to do "lein swank" and "slime-connect" is that I don't know where to go to debug things when slime hangs (as it inevitably seems to do). with an *inferior-lisp-buffer* (for other lisps) I can at least get stacktraces of my threads.

16:45 any suggestions on how to debug hanging swank sessions?

16:45 raek: how do you get it to hang?

16:45 qbg: slyrus: Where you launched lein swank

16:46 slyrus: raek: some command at the slime repl inevitably seems to hang it. In this case it was: (. q atoms) ... seemed innocuous enough

16:47 qbg: not sure what you mean. I launched it from a terminal window. I can C-c it, but I don't know how to interrupt it in a way such that I can query the state of it

16:48 raek: you are supposed to get a stack trace in our repl if anything goes wrong

16:48 unless you enter an infinite loop or something

16:48 qbg: slyrus: An alternative is to start a repl, (require 'swank.swank), and then (swank.swank/start-repl)

16:50 hiredman: raek: you don't actually get a stack trace in the clojure repl, you get the name of the exception and if you want the stack trace you need to call (.printStacktrace *e)

16:51 slyrus: ok, starting the repl manually looks promising. thanks everyone.

16:51 raek: I must have some other settings...

16:52 I get a "pop up buffer"

16:52 where I can select 0 for quit, 1 for cause, etc

16:52 in that buffer, the stack trace is shown

16:54 scottj: raek: that's slime

16:55 raek: oh, I misread

17:09 slyrus: ok, now I've got a hung slime connection and a (live) repl to my clojure process that's running swank. What's the clojure equivalent of (sb-thread:list-all-threads)?

17:10 chouser: ,(keys (Thread/getAllStackTraces))

17:10 clojurebot: java.security.AccessControlException: access denied (java.lang.RuntimePermission getStackTrace)

17:10 chouser: slyrus: that should do it.

17:11 slyrus: thanks!

17:13 hmm... now is there a way to make a thread throw me some sort of condition from which I can print a stack trace?

17:15 chouser: getAllStackTraces returns a map of threads to stack traces, so you can just print them from there

17:15 actually, on linux you can just type Ctrl-\ and it'll dump stack traces for all threads, plus other debugging info

17:16 slyrus: neat!

17:45 well, I never really figured out to debug that hanging process, but turning off slime-autodoc seems to fix the problem...

17:46 (and no, this isn't the old problem where any slime-autodoc would hang)

17:48 rntz: hm.

17:49 is there any good way to define two mutually recursive functions in clojure?

17:49 slyrus: leiningen, did you really just rm -rf my lib/dev directory when I did lein deps?

17:52 hugod: ,(doc trampoline)

17:52 clojurebot: "([f] [f & args]); trampoline can be used to convert algorithms requiring mutual recursion without stack consumption. Calls f with supplied args, if any. If f returns a fn, calls that fn with no arguments, and continues to repeat, until the return value is not a fn, then returns that non-fn value. Note that if you want to return a fn as a final value, you must wrap it in some data structure and unpack it after trampoline r

17:52 rntz: I'm not interested in avoiding stack consumption.

17:53 I'm interested in defining two mutually recursive functions that will, yes, eat up more stack space the more they nest

17:53 I'm just interested in not getting

17:53 java.lang.Exception: Unable to resolve symbol: bar in this context (NO_SOURCE_FILE:299)

17:53 hugod: ,(doc declare)

17:53 clojurebot: "([& names]); defs the supplied var names with no bindings, useful for making forward declarations."

17:54 rntz: :/ forward declarations? really? in the 21st century?

17:54 oh well

18:02 slyrus: technomancy: why does lein deps delete my lib/dev directory?

18:05 Licenser: coooookies!

18:05 rntz: it is kind of useful for scoping

18:13 rntz: Licenser: explain?

18:14 Licenser: well if you do (def x [] (y)) how do you can say 'there must be an x' but how do you decide in what scope x is visible

18:14 is it in the namespace or is it just in this functiony?

18:14 and with x I actually mean y

18:15 I could write (let [y +] (defn x [a b] (y a b))) for example where y is list locally for the funciton, or I could write (defn y [a b] (+ a b)) (defn x [a b] (y a b))

18:17 if you don't do forward declare y there the compiler can't decide how to handle y

18:21 rntz: Licenser: sure it can. when it sees (defn x [] (y)), and y is not bound, that means that y must have yet to be defined at whatever scope said definition is possible

18:21 ie: within this namespace

18:22 bhenry: ,(defn x [] (y))

18:22 clojurebot: DENIED

18:23 bhenry: user=> (defn x [] (y))

18:23 java.lang.Exception: Unable to resolve symbol: y in this context (NO_SOURCE_FILE:5)

18:25 technomancy: slyrus: otherwise if you upgrade some of your deps you'd end up with both versions in lib

18:26 Licenser: oh lein deps does that now :) I really need to update

18:26 lpetit: rntz: yes, a var could be automatically created, and the code for x compiled towards that var. We could then wait for the real runtime call before crashing. That's a possibility. One drawback, though, is that you don't benefit from type hints, for example

18:26 Licenser: rntz: that is guessing not knowing :P

18:27 slyrus: technomancy: perhaps I'm using dev-dependencies wrong. I'm using that for things that I don't want to get from some repo. is there a better way to manage local jars such that they won't get wiped when one does a lein deps?

18:27 rntz: lpetit: you could actually just wait until the module is done compiling, then check that all things referenced have been defined

18:27 I don't know much about type hints - can you explain?

18:27 technomancy: slyrus: you want to install it to your local mvn repo; I just added a description of how to do this to the faq in lein's readme.

18:28 lpetit: rntz: I've already have had this discussion with rhickey, and I lost. Searching through the ml should resurrect this. Or was it here in #clojure ? don't remember

18:28 * slyrus guesses he needs to stop hoping that if he ignores maven long enough it will go away

18:28 rntz: lpetit: heh. I guess I'll go look through the mailing list if I find the free time, then.

18:28 slyrus: perhaps chmod -w lib/dev will do the trick :)

18:28 technomancy: slyrus: nah; you don't really need to know much

18:28 lpetit: rntz: one of clojure goals is performance. To attain performance, one must avoid reflection

18:29 rntz: clojure does a good job of type inferencing at compile time, but sometimes, he can't guess the type, and must compile a code which will use clojure.lang.Reflector

18:30 rntz: lpetit: oh, interesting! but hold on, I can go back into a namespace once I've already defined things in it...

18:30 and then call def again...

18:30 which can change the type.

18:30 lpetit: rntz: one can make clojure's compiler warn when it compiled a code with reflection. Just (set! *warn-on-reflection* true) before emitting new code and you'll then have those warnings

18:31 Licenser: slyrus: it iwll go away!

18:33 lpetit: rntz: in fact, there's no such thing as "coming back into a namespace". There's the (eval) function, which takes a (read) object, compiles it. One of the first things it does while compiling is look at the clojure.core/*ns* var. The namespace in it will be used as the namespace part of any symbol which doesn't have a namespace part in the passed codedata

18:34 rntz: lpetit: well, I don't know what term I should be using, but whatever (in-ns) does

18:34 lpetit: rntz: interacting with clojure is an endless flow of evals done through some "channel". Either the REPL, either clojure.main's internal when passed files as options. Either via the explicit (compile) call which has the side effect of placing on the disk what has been compiled in memory

18:35 rntz: (in-ns) has a side-effect of changing the thread value of clojure.core/*ns*

18:36 rntz: right. My point is, though I can't, say (def pkg/func nil) if *ns* isn't 'pkg, I can (in-ns 'pkg) and then (def func nil)

18:36 lpetit: rntz: but yes, you can redefine a var, giving it a new "signature contract". The previously compiled code will not complain :)

18:36 rntz: ah

18:36 but then how can the previously compiled code not be using reflection?

18:36 how can type inference be helping you, if the type of a thing can be changed anyway?

18:37 lpetit: rntz: same for java. Compile class A with class B. save class A in another place. recompile class B with another version of class A. At runtime, place the old class A with the new class B. Clabamgo.

18:37 rntz: (well, not really the type of the thing itself, but the value stored in the var, and hence the type of the result of dereferencing)

18:38 lpetit: rntz: you'll have problem when executing the code which has been compiled with the old definition. Wrong number of arguments, class cast exception, etc.

19:51 DeusExPikachu: does anyone know where the str-utils2 version of partial is in the latest clojure.contrib?

19:54 nm, I'll just copy/paste

19:56 tomoj: what was a partial in str-utils2 for?

19:57 DeusExPikachu: tomoj: it was like partial but it didn't include the first argument, returns a new function whose first argument will be the first argument to f

20:00 tomoj: like (fn [f x & xs] (fn [& ys] (apply f x (concat xs ys)))) ?

20:00 oh, no, that's just like partial

20:01 huh, strange, I still see str-utils2/partial in my contrib

20:01 DeusExPikachu: (fn [f & args] (fn [s & more] (apply f s (concat args more))

20:01 tomoj: 20100615, guess it's kinda old

20:12 bortreb: Is there any way to compile a mutually dependent java and clj file to class files like you can with two plain old mutually dependent java files?

20:24 slyrus: ok, so now that I've figured out how to tell maven I want to install some jars, how do I tell it that I want to use the clojure.jar _I_ built?

20:25 DeusExPikachu: slyrus: is what you're doing pretty complicated? just curious

20:26 slyrus: I hope not. I just want to use the clojure and clojure-contrib I built, rather than some random version downloaded from some repository I know nothing about

20:26 DeusExPikachu: ah, so like built from git?

20:26 slyrus: yeah

20:27 DeusExPikachu: is the dependency 1.2.0-SNAPSHOT?

20:27 tomoj: you said you already knew how to install a jar into maven?

20:28 just install it with a special version string like 1.2.0-my-special-SNAPSHOT

20:28 or perhaps under your groupId instead of org.clojure

20:28 slyrus: ok, thanks

20:40 works like a charm. the kool-aid is starting to kick in.

20:52 dabd: once you start a swank server following the instructions here http://github.com/technomancy/swank-clojure how do you start a repl from within emacs?

20:53 DeusExPikachu: M-x slime-connect something like that

20:53 dabd: I ran slime-connect and I got an *inferior-lisp* buffer but no REPL...

20:55 DeusExPikachu: you have (require 'swank-clojure) and (require 'clojure-mode) in .emacs?

20:57 bortreb: another way to do it that I prefer is to launch everything from java on the command line

20:57 defn: lancepantz: around?

20:57 bortreb: you can totally control the classpath that way

20:58 java -Xmn200M -Xms220M -Xmx220M -server -cp "/home/r/Desktop/web:/home/r/Desktop/web/rlm-lib/*:/home/r/Desktop/web/lib/*" clojure.main -e "(do (require 'swank.swank)(use 'web) (serve) (swank.swank/start-repl))"

20:58 that's an example

20:59 slyrus: dabd: you need slime-repl in your .emacs

20:59 DeusExPikachu: dabd: again, you have (require 'swank-clojure) in your .emacs?

20:59 slyrus: (slime-setup '(slime-asdf slime-repl slime-presentations))

21:00 I don't think swank-clojure alone will get you the repl, just the inferior-lisp buffer. you need slime-repl, AFAIK

21:00 although you probably don't need slime-asdf and slime-presentations :)

21:00 DeusExPikachu: slyrus: haven't used slime/swank lately, but last time I did I never had to use slime-repl

21:01 slyrus: yeah, they changed the default such that the repl is now a contrib you need to explicitly enable

21:01 slime-fancy will get it for you though

21:02 tomoj: is this advice for someone using slime not from elpa?

21:02 no need to touch .emacs if you just want the elpa slime for clojure

21:02 slyrus: the question wasn't about elpa

21:02 DeusExPikachu: i just stick with inferior-lisp now, manual and simple

21:02 slyrus: the repl is nicer, IYAM

21:03 tomoj: what I meant was, was the question "I want X slime version or already have slime..."?

21:03 otherwise, elpa is stupid simple

21:03 slyrus: I assume _everybody_ already has slime installed for use with their favorite common lisp implementation. Then it's just a matter of hooking slime up to clojure :)

21:04 speaking of slime... how come slime-presentations aren't supported in swank-clojure?

21:04 I suppose I should wait for technomancy|away to return to ask that

21:05 dabd: I installed slime-repl from elpa

21:07 slyrus: and did that fix the problem?

21:07 tomoj: then don't touch your .emacs

21:08 robink: slyrus: He's sitting next to me

21:08 bigwavejake: how can I use the min function on a hash? I know which element I want to compare with (let's call it :x).

21:09 robink: slyrus: Although he doesn't want to deal with Swank right now.

21:09 slyrus: heh

21:09 not surprising :)

21:09 robink: slyrus: Local Clojure group is meeting

21:09 slyrus: have fun!

21:09 robink: Thanks :-)

21:09 defn: http://github.com/stilkov/jruby-rails-clojure

21:09 cool

21:09 slyrus: i have to admit, this whole java interop thing is pretty nice

21:10 dabd: slyrus: it fixed the problem but when I restart my emacs slime-repl is not available. Something must be wrong with elpa

21:12 tomoj: what makes you think slime-repl is not available?

21:13 dabd: tomoj: M-x slime-repl doesn't work

21:14 but if I evaluate M-x package-list-packages it says slime-repl is already installed

21:14 bortreb: :dabd if you start a swank server from the command line and then do M-x slime connect in emacs does it work?

21:14 tomoj: there is no M-x slime-repl

21:16 dabd: bortreb: now it doesn't work

21:16 before I restarted emacs it worked

21:16 at least I got an *inferior-lisp*

21:16 tomoj: 'M-x slime' should work for screwing around without a swank server

21:16 slyrus: dabd: you want slime-connect if you're connecting to a swank server started in another process

21:17 not M-x slime

21:17 dabd: slyrus: yes I start the swank server from the command line with 'lein swank'

21:17 slyrus: right. if you see an *inferior-lisp* buffer you're doing it wrong

21:17 dabd: then from emacs I connect with M-x slime-connect, but now I don't get an inferior lisp anymore

21:17 slyrus: M-x slime-connect is what you want, I think

21:18 right

21:18 you don't have an *inferior-lisp* buffer with slime-connect

21:18 dabd: and what does slime-connect give me?

21:18 how do I get a REPL?

21:18 bortreb: dabd: a clojure repl

21:18 slyrus: M-x slime-connect

21:19 bortreb: does it say something like "connection refused" or something?

21:19 you might run "killall java" and then start over

21:19 just to be sure there isn't some dead repl hogging up port 4005

21:22 dabd: unfortunately slime-connect doesn't work: no clojure REPL, nothing and there is no dead repl hogging up port 4005 either

21:22 so what is slime-repl for?

21:23 how did you install your slime-repl?

21:23 slyrus: dabd: slime-repl switches the focus to the slime-repl buffer

21:24 tomoj: you installed clojure-mode and slime-repl from elpa?

21:24 dabd: I just installed slime-repl from elpa

21:25 I installed clojure-mode from my distribution (arch linux)

21:25 tomoj: I don't guess that would make a difference

21:25 dabd: how did you install slime-repl?

21:25 tomoj: just curious, what version of clojure-mode do they have?

21:25 slyrus: dabd: you don't want to install slime-repl, per se, you want to install slime and swank-clojure

21:25 tomoj: arch, I mean

21:26 no, don't install swank-clojure :P

21:26 dabd: I install the git version so it is the latest

21:26 slyrus: If I were you, I'd get them from the upstream git sources. others here would tell you to get them from elpa.

21:26 how do you use slime without the swank-clojure back end?

21:27 and getting any of the above from a linux distro would be suboptimal, I would think

21:28 dabd: I have slime-cvs

21:28 tomoj: aha

21:28 this is what I mean about "I want X version of slime" above

21:28 slyrus: there's a nice git mirror at: git://sbcl.boinkor.net/slime.git

21:28 dabd: the thing is I also installed slime from elpa and this might be causing some conflict

21:28 tomoj: if you don't let elpa take care of everything it won't work

21:29 slyrus: swank-clojure in emacs is no longer necessary

21:30 dabd: yes the readme file for swank-clojure says you should install it from leiningen for example

21:30 slyrus: yeah, but you still need swank-clojure!

21:32 tomoj: you need the clojure stuff, yeah

21:32 dabd: I think I am going to uninstall elpa

21:32 tomoj: thought you meant the emacs stuff, sorry

21:33 fwiw, just installed slime-repl from elpa in a virgin emacs and it connects flawlessly to lein swank

21:33 but if you have your own slime.. good luck :(

21:44 dabd: ok I uninstalled swank-clojure-git and slime-cvs from my distribution, then I reinstalled elpa and from there I installed slime, slime-repl and swank-clojure and everything seems to be working now

21:45 at least slime-connect gives me a clojure repl

21:45 technomancy: clojurebot: swank-clojure?

21:45 clojurebot: I don't understand.

21:45 technomancy: clojurebot: swank?

21:45 clojurebot: swank is try the readme. seriously.

21:45 technomancy: sorry.

21:46 dabd: you shouldn't need swank-clojure from elpa; just clojure-mode and slime-repl.

21:46 hiredman: clojurebot: swank-clojure is <reply> see swank

21:46 clojurebot: Ik begrijp

21:47 dabd: technomancy: ok

21:47 thanks

21:58 thunk: Do you still need to (unload-feature 'slime-autodoc t) to get slime to play nice with compound expressions?

21:59 technomancy: thunk: you're installing slime from source?

22:00 thunk: Yup, but it's been a little while since I updated.

22:01 slyrus: hmm... isn't this supposed to work now? : (def z (clojure.java.io.output-stream (new java.io.File "moose")))

22:02 technomancy: thunk: oh, in that case I don't know =\

22:02 slyrus: thunk: I've been having problems with slime-autodoc and had to turn it off to get things stable

22:02 but then again I use slime from upstream, not from elpa

22:03 hiredman: slyrus: what?

22:03 slyrus: I can't seem to make clojure.java.io.output-stream work for me.

22:03 thunk: slyrus: Yeah, same here.

22:03 slyrus: i'm trying to open a file for writing

22:04 or where you asking about slime?

22:04 hiredman: output-stream is a function name

22:04 clojure.java.io is a namespace

22:05 slyrus: duh. / not .

22:05 thanks.

22:06 dabd: because I tend to forget this stuff I just summed up the steps for getting emacs + clojure working: http://pastebin.org/372744

22:06 thunk: slyrus: Well, swank-clojure I should have said. I was having the Hanging REPL mentioned here: http://www.mohegan-skunkworks.com/adding-clojure-to-an-existing-slime-setup-in-emacs.html

22:07 slyrus: thunk: yeah, that's the old problem I _used_ to have. that's been fixed-ish. but there's another intermittent hang that I think is related to the same issues.

22:17 dabd: my leiningen project.clj is using clojure 1.2.0-master-SNAPSHOT but if I evaluate *clojure-version* from the REPL it shows me version 1.1.0, why is this happening?

22:20 hiredman: you need to run lein clean and lein deps

22:20 you have an old clojure jar in lib/

22:20 dabd: I just ran lein deps

22:20 hiredman: you need to run clean

22:21 actually

22:21 dabd: ok it is fine now, thanks

22:21 hiredman: oh

22:21 good

22:22 (also older lein's had an issue with the repl task not using the right version)

22:36 technomancy: yeah, that's a known bug of lein 1.1.0

22:39 fixed in 1.2.0 RC

23:43 aedon: evening. is there an easy way to do reflection (list methods, etc) on java classes from the repl?

23:45 qbg: aedon: For starters, checkout show in clojure.contrib.repl-utils

23:46 aedon: qbg: many thanks

23:47 hiredman: ,(->> "foo" class .getMethods (map #(.getName %)))

23:47 clojurebot: ("hashCode" "compareTo" "compareTo" "indexOf" "indexOf" "indexOf" "indexOf" "equals" "toString" "length" "isEmpty" "charAt" "codePointAt" "codePointBefore" "codePointCount" "offsetByCodePoints" "getChars" "getBytes" "getBytes" "getBytes" "getBytes" "contentEquals" "contentEquals" "equalsIgnoreCase" "compareToIgnoreCase" "regionMatches" "regionMatches" "startsWith" "startsWith" "endsWith" "lastIndexOf" "lastIndexOf" "lastIn

23:48 ysph: what would be a good reference to start on following the logic for choosing dynamic typing in clojure?

23:49 qbg: http://clojure.org/rationale mentions it a little bit

23:54 aedon: hiredman: sorry if this is a particularly newb question, but what's ->>?

23:56 hiredman: ,(macroexpand-1 '(->> A (F E R T)))

23:56 clojurebot: (F E R T A)

23:56 aedon: hiredman: ahh, I think I saw that on hn a few weeks ago. got it.

Logging service provided by n01se.net