#clojure logs

2010-07-01

00:00qbgTelling the compiler that time2 is a macro and that this is the function to call to get its expansion
00:00itistodaywhen it's compiled, what does it look like before it's called?
00:00qbgHere, the function executes (time `(dotimes [_# ~times] ~expr))
00:01qbgSay for instance the compiler is compiling (dotimes [n 10] (println n))
00:01qbgThe compiler sees that dotimes is a macro and replaces this form with:
00:01qbg,(macroexpand '(dotimes [n 10] (println n)))
00:02clojurebot(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)))))
00:02qbgAnd then proceeds to compile that form
00:02itistodaywait, but that's different, that doesn't have the backtick
00:02KirinDaveBacktick is just a fancy tick.
00:03qbgWhat the macro's function returns is what macroexpand returns
00:03KirinDaveQuasi-quote allows for symbols to have lexical annotations for additional processing.
00:03KirinDaveBut in the end it all is a quote.
00:05qbg(Actually it is what macroexpand-1 returns; macroexpand just expands that more)
00:06hiredmanKirinDave: it's called syntax-quote in #clojure
00:06itistodayok, 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?
00:06itistodaybefore it's called with anything
00:06qbgIn the case of (time2 (println "Hello") 10), the macro returns (for instance) (clojure.core/dotimes [___109__auto__ 10] (println "Hello"))
00:06itistodaymacroexpand isn't being called at that point
00:06hiredmanitistoday: do you understand how macros work?
00:07itistodayhiredman: no, that's what i'm trying to understand
00:07hiredmanitistoday: if you don't, the follow up is, do you understanding what quoting is?
00:07itistodayhiredman: yes
00:07qbgThe macro is only expanded when it is used
00:07hiredmanso if the second macro was not a macro, but a function, what would it return?
00:09itistodayhiredman: 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))
00:10itistodayand 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)
00:10itistodayso i'm guessing it calls: (time '(clojure.core/dotimes [___195__auto__ 100] 2))
00:10hiredmanwhat calls that?
00:10hiredmanright
00:11itistodayok, so a macro is: (time (eval (clojure.core/dotimes [___195__auto__ 100] 2))) ?
00:11hiredmanno
00:11itistodayerr: (time (eval '(clojure.core/dotimes [___195__auto__ 100] 2))) ?
00:11hiredmanso the compile sees a list (OP A1 A1)
00:12hiredmanif 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
00:12hiredmanand replaces the list (OP A1 A2) with the result and continues compiling
00:13itistodayso it's like an eval...? but it's more efficient?
00:13hiredmanno
00:14hiredmanit's like a compiler "plugin"
00:14qbgYou are essentially extending the compiler
00:14hiredmaneval still runs at runtime
00:15qbgMacros are source-to-source transformation
00:15hiredmanif the compile runs (OP A1 A2) and the result is (OP2 A3) the compiler examines that
00:15itistodayalright... so that brings me back to: (defn time2 [expr times] (time `(dotimes [_# ~times] ~expr)))
00:15hiredmanif OP2 is a macro then OP2's function is valled with A3
00:15itistodayit's assume dotimes is a function and not a macro
00:15itistoday*let's
00:15hiredmanno
00:16itistodayerr... rather: (defmacro time2 [expr times] (time `(dotimes [_# ~times] ~expr)))
00:16hiredmanno
00:16itistodayand assume dotimes is a function
00:16hiredmanno
00:16itistodaystop saying no
00:16itistoday:-p
00:16itistodaywhat's wrong with that? you haven't heard my question
00:17itistodaythat's perfectly legitimate code, i'm trying to understand what happens when time2 is called if it's defined like that
00:18qbgSay the compiler is compiling (time2 2 5) in this case.
00:19qbgIt then calls the macro function that defmacro defined for you
00:19qbgLets simplify things and say it is essentially (fn [expr times] (time `(dotimes [_# ~times] ~expr)))
00:20qbgIt then calls that fn with 2 and 5 (both unevaluated, but that doesn't make a difference here)
00:20itistodayk
00:20qbgThe function runs, and the execution of the body of time is timed
00:20qbgAnd the return value of the body is returned from the function
00:21qbgIn this case, (clojure.core/dotimes [___109__auto__ 5] 2)
00:22itistodaybut i just called it and it returned nil
00:22itistodaywhen i used macroexpand-1 on it, then it returned that
00:22qbgNow the compiler replaces (time2 2 5) with that, and continues by compiling that
00:23qbgCorrect, because when you run (time2 2 5), it gets macroexpanded, and that returned code is then run
00:23qbgAnother way to think about it:
00:23qbgSuppose eval didn't know about macros
00:24qbgBut you wanted macros, so you wrote a function macroexpand-all that would perform the above transformation
00:25qbgSo if it saw (time2 2 5) nested in its argument, it replaces it with (clojure.core/dotimes ...)
00:25qbgNow, we can define a macroexpanding eval as (defn my-eval [form] (eval (macroexpand-all form)))
00:26qbgSo when you run (time2 2 5) in the repl, it is essentially running (my-eval '(time2 2 5))
00:27qbgWhich is essentially (eval '(clojure.core/dotimes ...))
00:27qbgOr nil, because that is what dotimes returns
00:27qbgNow the macro is incorrect because time executes before the code is actually evaluated!
00:28itistodayoh that's another problem i had, i thought dotimes returned the last thing inside the body
00:28qbgAre you starting to understand?
00:29itistodayqbg: i'm going to re-read your statements with my understanding of dotimes return val, one sec
00:30qbg(Above time runs before you get to (eval '(clojure.core/dotimes ...)))
00:31dnolenitistoday: dotimes is all about side effects, it always returns nil.
00:31dnolen,mexpand-all
00:31clojurebotjava.lang.Exception: Unable to resolve symbol: mexpand-all in this context
00:31dnolendarn
00:32dnolen,clojure.contrib.macro-utils.mexpand-all
00:32clojurebotjava.lang.ClassNotFoundException: clojure.contrib.macro-utils.mexpand-all
00:32itistodaypart 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
00:33qbgYou are invoking the compiler at runtime
00:34itistodaydoesn't eval evoke the compiler?
00:34itistodayso in the repl this is essentially the same as eval?
00:34qbgYes
00:34itistoday*invoke
00:34qbgThe 'e' in repl stands for eval...
00:34itistodayhehehe
00:35qbgYou could call it the rmepl, (m = macroexpand), but that isn't as sexy.
00:35dnolen,(macroexpand-1 '(dotimes [_ 10] 1))
00:35clojurebot(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 _)))))
00:37dnolenone of the major features preventing me from leaving Emacs is the ability to macroexpand anything underneath the cursor
00:38itistodayis calling (time2 2 10) in this case the same as calling (time nil)?
00:39qbgNo
00:39itistodayok good
00:39itistodayso, here's my understanding so far, let me know where i'm wrong:
00:39itistodayin the repl, I call: (time2 2 10)
00:41itistodaya new function is created: (defn time2-autogen [] (time (dotime [__auto 10] 2))
00:41itistodayby the compiler
00:41qbgNo
00:41itistodayok, so what is created by the compiler?
00:41qbgWhen time2 is defined, the extra function is created
00:42itistodayalright, let me try that:
00:44itistodayi 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))) ?
00:44itistodayno, that doesn't seem right
00:44qbgNo
00:45dnolenitistoday: a macro is just a regular function that is used to take unevaluated code and transform it into something else.
00:45qbgIt creates (defn time2-autogen [expr times] (time `(dotimes [_# ~times] ~expr))
00:45dnolenisittoday: http://gist.github.com/459585
00:45qbg)
00:46tomojwhat's this autogen stuff?
00:46itistodaydnolen: thanks, but that's not the macro
00:46qbg(It actually isn't named that)
00:46itistodaydnolen: the syntax quote is on the outside of dotimes, not time
00:47dnolenitistoday: but it's incorrect if it's not outside of time
00:47qbg(Just simplifying it a bit for explanation)
00:47qbgdnolen: That is the point
00:49itistodayqbg: ok, how about this: time2-autogen is a "placeholder", that's expanded as the compiler encounters calls to time2?
00:49qbgtime2-autogen is called when the compiler encounters a call to time2
00:52itistodayqbg: http://paste.pocoo.org/show/232109/
00:52qbgNo
00:52arrummzenIn 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).
00:53itistodayqbg: well what then??
00:53qbgWhen the compiler sees, (time2 2 10), the compiler calls (time2 '2 '10)
00:53qbgRight at that time. Not at run time.
00:53qbg(time2-autogen '2 '10) that is
00:54qbgtime2-autogen runs like any other function
00:54qbgtime does its thing and prints "Elapsed time: x msecs"
00:55dnolenitistoday: http://gist.github.com/459585
00:55dnolenupdated my gist showing both version of the macro
00:55dnolennotice that lot of code does not get generated in the second version.
00:55qbgtime2-autogen then returns (clojure.core/dotimes ...)
00:56scottjarrummzen: you could probably call whatever method you do in java and pass a function since they implement Runnable
00:56dnolenanyways guessing or trying to intuit what is going on is much harder than just seeing what code gets generated.
00:56qbgThe compiler then works on that instead of (time2 2 10)
00:56itistodayqbg: time measured the time of what then?
00:57qbgThe execution of `(dotimes [_# ~times] ~expr)
00:57itistodaydnolen: thanks, looking it over
00:57qbgWhich is very fast
00:57itistodayqbg: what does that sentence mean? "The execution of `(dotimes [_# ~times] ~expr)"
00:57itistodayhow does that execute?
00:58itistodayis it the creation of a list? is it macroexpansion? what is it?
00:58qbg`(dotimes ...) executes and returns (clojure.core/dotimes ...)
00:58itistodayso it measures the time it takes macroexpand to run?
00:58qbgIt creates the list, fully qualifies the symbols, etc.
00:59qbgBut it does not execute the resulting the list
01:00itistodayqbg: ?
01:00arrummzenI 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) .
01:00qbgLets do (defn make-code [expr times] `(dotimes [_# ~times] ~expr)))
01:01qbgWhat is happening then is that time2-autogen is basically executing (time (make-code expr times))
01:01qbgSo it just timing how long it takes (make-code ...) to execute
01:01itistodayqbg: "so it measures the time it takes macroexpand to run?"
01:02qbgClose
01:02itistodaywhat's the difference?
01:03qbgMacroexpand here isn't really doing anything other than executing `(dotimes ...)
01:03itistodaybut that's what you said!
01:03itistodaysaid by qbg: "The execution of `(dotimes [_# ~times] ~expr)"
01:04qbgBut time isn't timing how long macroexpansion actually takes
01:04itistodayargh...
01:05qbgIf the macro's body was (let [foo (really-long-computation)] (time `(dotimes ...)))
01:05qbgThen macroexpansion would take much longer than what time would report
01:05qbgAs time is only timing `(dotimes ...)
01:06qbgAnd not how long it takes time2-autogen to run
01:07qbgThis is really fine nitpicking though...
01:07dnolenitistoday: 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.
01:09qbgThe problem with the macro is that time is being evaluated at the wrong time.
01:09itistodaydnolen: does a macro's body run at compiletime?
01:09qbgYes!
01:09itistodayi.e. (demacro foo [] (+ 1 1))
01:09scottjarrummzen: an agent sounds like your swing thread example. you could send work for it to do from other worker threads.
01:10qbg(macroexpand '(foo)) there would return 2
01:12itistodayeverything that's syntax quoted get's "macroexpanded" at compile time and the result of that is turned into a function?
01:12itistoday(with the placeholders replaced with the called values?)
01:12itistodaywherever there's a tilde?
01:13qbgThis might sound confusing, but that happens at runtime
01:13qbgOnly inside a macro's body, runtime is compile time...
01:14itistodayis there a document somewhere that explains this in depth?
01:14arrummzenscottj: Yep, that looks like what I'm searching for. Thanks.
01:15qbgTake for example (if nil `(~(throw (Exception. "Foo!"))))
01:15itistodayis that inside a macro?
01:15qbgIf syntax-quote worked at compile time, this code would not compile
01:15qbgJust at the repl
01:16qbgNow try this: (defmacro death [] (throw (Exception. "Foo!")))
01:16qbgAnd then (if nil (death))
01:17itistodaythrows an exception
01:17qbgYes, because the macro throws an exception
01:17itistodaybecause the code is executed at compile time
01:17qbgCorrect.
01:18itistodaysyntax-quote is not executed at definition of macro
01:18itistodaybut it is replaced, by the compiler, when the function is called?
01:18itistodayat compile time?
01:19qbgCorrect, syntax-quote is run when the macro is expanded
01:19qbg(I'm assuming we are talking about the syntax quote in time2)
01:19itistodaysure
01:19itistodayok so there are two stages...
01:19itistoday*both* in the compiler
01:20itistodaystage 1 is macro definition, and at that stage anything that's not syntax-quoted is run
01:20itistodaysyntax quoted stuff is left as is as a list
01:20itistodaycorrect so far?
01:20qbgBy macro definition, do you mean defmacro?
01:21itistodayI mean when the compiler comes across a call to defmacro
01:21tomoj:(
01:21qbgdefmacro is like defn in that its body is not evaluated when it is compiled
01:22itistodayokk...............
01:22itistodayso 1 stage
01:22itistodaynot 2
01:22itistodaylet me try again
01:23itistodaystage 1 (the only stage), happens when the compiler comes across a call to a macro
01:23itistodaylike: (foo), where foo is (defmacro foo [] (System/exit 0))
01:23itistodayat that point its body is run?
01:23itistodayso if i had a call to (foo) in my code it would fail to compile?
01:24qbgThe compiler sees (foo) so it expands it
01:24itistodayerr... evaluates it
01:24qbgThe expansion function then quits the JVM
01:24itistodaythere's nothing to expand there though right?
01:24itistodayexpand only refers to syntax quote?
01:25qbgExpand refers to when you run (System/exit 0) in your above case
01:25itistodayok, so it expands/evaluates it
01:25itistodayhere expand is the same as evaluate
01:25itistodayit compiles and runs the code = evaluates it
01:26itistodayright?
01:26qbgexpanding the macro doesn't evaluate the code the macro returns
01:26qbgThat is the main difference
01:27qbgIn the case of (foo), the macro doesn't return anything because you quit the JVM first.
01:27itistodayok, so expanding is evaluating, but it's referring to evaluating the non-quoted portion
01:28itistodaywe need to get this terminology consistent :-)
01:28itistodaysomething is being evaluated here
01:28itistodaythat would be (System/exit 0)
01:28qbgExpanding is running the function that defmacro defines
01:28qbgIn this case, the function runs (System/exit 0)
01:29BahmanI'm trying to understand 'require', 'refer' and 'use'. Can anyone please tell me what is difference between 'loading' and 'refering to' a library?
01:30itistodayqbg: ok, fine, whatever. it runs the non-quoted part of the body?
01:30qbgYes, it evaluates the body
01:33itistodayok... i think i'm getting it
01:33qbgIt is really simple once you get it, I promise. :)
01:34itistodayso, back to the time2 macro, it calls: (time `(dotimes [_# ~times] ~expr)) ?
01:34qbgYes!
01:34itistodaywhich is basically: (time '(dotimes [_# ~times] ~expr)) ?
01:34itistoday(at that point)
01:34qbgSyntax-quote does more than regular quote
01:34itistodayi.e., it calls time on a list with dotimes as its first element, an array as its second, ,etc
01:35itistodayyes, but what does it do then
01:35itistodayat that point in time, what does it look like?
01:35qbgIt times how long it takes to turn `(dotimes ...) into (clojure.core/dotimes ...)
01:35qbgThink of syntax-quote as being a function call
01:36itistodayok but what *exactly* is it
01:36qbgLike (quasiquote '(dotimes [_ (unquote times)] (unquote expr)) <environment>)
01:36raekgood point
01:36itistodayahhhhh, that's much nicer :-)
01:37raek,(read-string "`(a ~b ~@c)")
01:37clojurebot(clojure.core/seq (clojure.core/concat (clojure.core/list (quote sandbox/a)) (clojure.core/list b) c))
01:38qbg(I wrote this in a language I'm hacking on in Clojure)
01:39qbgsyntax-quote is just a really nice form for something that is essentially a function
01:39raekBahman: require = make sure library is loaded, refer = make vars of another namespace available as if they were in the current namespace, use = require + refer
01:39qbg*function call
01:39raekimport = like refer, but for java classes
01:40itistodayqbg: ok, but does it run quasiquote?
01:40raekload is a more low level construct
01:41itistodayin other words, it calls quasiquote, and times how long that takes?
01:41qbgYes
01:42qbg(As raek showed above, Clojure doesn't use my quasiquote function, but the effect is the same)
01:42raek,quasiquote
01:42clojurebotjava.lang.Exception: Unable to resolve symbol: quasiquote in this context
01:43qbgHow Clojure does it is an implementation detail
01:43itistodaywell, i notice that it's evaluating b and c there
01:43raekah, yes. in scheme, `(a ,b ,@c) turns into (quasiquote a (unquote b) (unquote-splicing c) or something
01:44itistodayso it times how long it takes to evaluate b and c and then call the function quasiquote, which returns something?
01:44Bahmanraek: Thanks...but I don't understand 'loading' yet. Does 'refer' involve 'load'?
01:44itistodayor, in my macro, it times how long it takes to create a seq and evaluate times and expr?
01:44raekI think refer calls load under the hood
01:44qbgYes
01:44raekif that library hasn't been loaded already
01:45BahmanHmmm...
01:45itistodayok and that's it right?
01:45raek(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)))
01:46raek,(read-string "(time `(a ~b ~@c))")
01:46itistodayqbg: there's nothing else right? to time2?
01:46clojurebot(time (clojure.core/seq (clojure.core/concat (clojure.core/list (quote sandbox/a)) (clojure.core/list b) c)))
01:46itistodayit times how long it takes to evaluate times, expr, and then to create a seq out of them?
01:46raekthe syntax-quote to seq/concat/list/quote transformation is done when the expression is read
01:46qbgTime then returns that seq
01:47qbgSo that becomes what the macro's body returns
01:47qbgAnd that is what the macro expands to.
01:47Bahmanraek: If that's true why 'use' is introduced? Since 'refer' does the loading too.
01:47qbgThat is all what time2 does
01:47itistodayqbg: OK... and that part gets run at runtime?
01:48raekBahman: no, refer does not do the loading
01:48qbgYes, the return value of time2's body is what is run at runtime
01:48raekone rarely uses that one by its own
01:48raek'use' does its refering part by calling 'refer'
01:48itistodayqbg: OK. Thank you *SO* much for taking my shit and explaining this!
01:49itistoday(and having patience)
01:49qbgFinally understanding?
01:49itistodayyes. i'm pretty sure. :-D
01:49itistodaydefinitely good enough to write macros i think :-P
01:49qbgSo eval is essentially (defn my-eval [form] (eval (macroexpand-all form)))
01:49raekand its loading part by calling 'load' (if not already loaded, or if :reload or :reload-all i given)
01:49qbgThe form is expanded, and then later evaluated.
01:50qbgA macro is just a function.
01:50qbgThat returns code.
01:50raekthe point is: there's nothing macro-y about the evaluation of syntax-quote
01:51itistodayand in the end, it's evaluating byte-code, not interpreting a list at runtime, right?
01:51raekyes, and when its called in a macro, it gets passed the code instead of the valuesof its arguments
01:52qbgYes, clojure is compiler only.
01:52raekwhen a function is read, it's compiled
01:52Bahmanraek: Thank you. Didn't grasp it yet. Perhaps better to take a look at the source.
01:52raekBahman: have you seen http://clojure.org/libs ?
01:53Bahmanraek: No.
01:53BahmanNow reading it.
01:53itistodaymacros are plugins to the compiler, i love that analogy. :-)
01:53raekBahman: peeking into the clojure source can be a very good thing to do every now and then
01:55qbgJust don't make your macros be this complicated: http://www.lispworks.com/documentation/lw51/CLHS/Body/m_loop.htm#loop
01:55sergey_miryanovhi all :)
01:55itistodayqbg: hehe, sure thing. :-)
01:55itistodayqbg: i don't think you'll have to worry about that. ;-)
01:56qbgAnd they say lisp has no syntax...
01:56raekthey just call it mini-languages instead...
01:57raekwell, there's still a difference. both ordinary code and mini-language code share the same surface syntax
01:57raeklists
01:59qbgWriting a functional setf might be cool...
02:00sergey_miryanovwhy I can't rebind + in macro? it's a my bug or clojure?
02:00sergey_miryanovhttp://paste.lisp.org/display/112063
02:01raeksergey_miryanov: that's symbol capture
02:01qbgFor the let based solution, you want ~'+ instead of + or '+
02:01raeka thing clojure macos was built to avoid
02:01qbgbinding doesn't work because + is being inlined
02:02raekbecause it can accidentally yield very strange results
02:03raekif you let, say, the symbol 'x, every use of that in the macro body will now do something else
02:03raekbut in your case, this was maybe the point
02:03sergey_miryanovqbg, thanks!
02:03raekI also recommend looking into (binding [+ some-other-fn] ...code...)
02:03raekthis is a runtime construct
02:04raekit dynamically rebinds + for the executing thread
02:04sergey_miryanovraek, yes, I want do something else in macro
02:04raek,(binding [+ -] (+ 1 2))
02:04clojurebot3
02:04sergey_miryanovbut binding doesn't work with macro
02:04itistodayso, clojure is dynamically scoped?
02:04Bahmanraek: Thanks for the help...Finally I seem to get how it works.
02:05raekhrm, why did that example not work...
02:05tomoj<qbg> binding doesn't work because + is being inlined
02:05raek/facedesk
02:05raekright.
02:06qbgitistoday: Clojure has both lexical and dynamic scope.
02:06raekI should probably mention clojure.contrib.generic.arithmetic
02:06raeknot dynamically scoped variables, but dynamically bound
02:06raekthe scope is still lexical
02:07raekthat it, the way a symbol is resolved into a var
02:07itistodaythat is kinda weird
02:07itistodayexample: (defn foo [] (println x))
02:07itistodaythat gives an error if x isn't defined
02:07itistodayso i define x ahead of time
02:07itistodaythen i can define the function
02:08itistodaybut when i call the function it will print whatever is in 'x' at the time
02:08itistodaythat's dynamic binding, right?
02:08qbgYes
02:08raeklate binding at least
02:08itistodayso how do you create a closure in clojure? or do you not do that?
02:09qbgLike you do in scheme.
02:09raek(let [x 1] (fn [] x))
02:09itistodayok, cool, so let creates a closure, anything else?
02:10qbgTechnically the closure is created by (fn ...)
02:10raekwell, fn closes over the environment it is made in
02:10qbgThe way that Clojure handles dynamic scope is better than the way CL does
02:11itistodayno... it doesn't
02:11raek(defn make-counter [] (let [count (atom 0)] (fn [] (swap! count inc))))
02:11itistoday(def foo (fn [] (println x)))
02:11itistodaythat doesn't create a closure
02:11itistoday(foo, not make-counter)
02:11raek(def c (make-counter))
02:11raek(c) => 1
02:11raek(c) => 2
02:11itistodayso it has to do with let, let creates the the closure... "over" fn
02:12qbgLet just creates a nested environment
02:12itistodayohhhhhhhhhhhhhhhhh
02:12qbg(fn ...) closes over its lexical environment
02:12itistoday*clicks*
02:13itistodayyes, sometimes i sounds like a 3rd grader :-p
02:13itistodayand spell like one too
02:13raek(def x 5) (defn f [] x) (defn g [] (let [x 3] (f)))
02:13raekif variables in clojure had dynamic scope, calling g would yield 3
02:14qbgOr if Clojure was CL
02:14itistodaygreat example, thanks
02:14itistodaybut calling g yields 5 because the original environment is what counts
02:14raekbut which variable x refers to in f is determined lexically
02:14qbgWhich is why Clojure > CL
02:14raekthat is, from the structure of the code
02:15qbgWell, x in (defn f ...) is dynamically scoped
02:15raekthe global var x can be dynamically rebound
02:15itistodayright
02:15qbgIt is just that the x in (let [x 3] (f)) is another variable
02:15itistodayif you change x it will change what g returns
02:15raekyes, scoping is about "which variabel"
02:15itistodaythat's what i said though
02:15raekbut bidning is about "which value"
02:16itistodayso binding is totally dynamic
02:17itistodayhad it been (defn f [] (binding [x x] x)) it would return 3 when g is called right?
02:17raekcan be if (binding) is used, so potentially, yes
02:17qbgNo
02:17raek(binding [x x] ...) is basically a no-op
02:17raekexcept that it allows x to be assigned to
02:18raekbecause it now has a mutable thread-local binding
02:18itistodayassigned to using what?
02:18qbgThe x is g is not the x from (def x 5)
02:18raekset!
02:19itistodayraek: is that done often?
02:19raek(def x 1) (binding [x x] (println x) (set! x 2) (println x)) (println x)
02:19raek=> 1, 2, 1
02:20raekitistoday: not very often, no
02:20qbgI almost ever using binding
02:20raekbut it can be handy when interfacing with callback-based apis
02:20qbg*never
02:20itistodayok, well then back to the example with f and g functions, how do change that around so that g prints 3?
02:20qbg(defn g [] (binding [x 3] (f)))
02:21raek(defn g [] (let [x 3] (f))) -> (defn g [] (binding [x 3] (f)))
02:21itistoday:-)
02:21raekx in f still refers to the global var x, which value is rebound to 3
02:21itistodayduh, i should've remembered that
02:21itistodayok, i think my brain is tired
02:21raekok, ok. I just wanted to be clear :)
02:21itistodayyou guys should be payed to teach clojure :-p
02:22itistodayappreciate the help much!
02:22raekoh, I read "duh, i remembered that"
02:23raekanyway, thread local bindings introduced by 'binding' is... thread local
02:23raekso they avoid the concurrency issue, rather than adressing it
02:23qbgbinding + lazy sequences = a recipe for trouble
02:24raekhrm, yeah
02:24raekthe next element can be forced in any thread
02:24raeksome of them might have some of the vars rebound
02:24raekthat doesn't sound very nice
02:24itistodayinteresting... but a lot of code isn't very multithreaded though
02:25qbgAnd it can be force outside of the current dynamic scope
02:25itistodayyou guys have seen this right: http://meshy.org/2009/12/13/widefinder-2-with-clojure.html
02:25raekitistoday: using the other concurrency primitives (atoms, refs, agents) is still recommended, thoug
02:26itistodayraek: right, but sometimes if you really want performance you can avoid them but be careful (like in that link)
02:27raekwhere does it use set! ?
02:28qbgWell as it is 1:30 am where I live, good night all
02:28sergey_miryanovnigth!
02:28itistodayqbg: night!
02:28raekhrm, nevermind
02:28raeknight
02:29itistodayraek: you're right, it uses some Java stuff, but not set!...
02:30itistodaywell 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
02:31itistodayqbg is in the timezone to the left of me if you're viewing earth straight on with north at the top.
02:31itistodayerm.. i mean it's 2:30 AM, time for bed
02:31itistodaythanks for the help! ciao for now
03:52LauJensenGood morning all
04:00DarthShrineEvening, LauJensen
04:47esj(greetings)
04:48DarthShrineYarr.
05:45cais2002,"hello"
05:45clojurebot"hello"
05:46cais2002,'does-leiningen-work-in-cygwin?
05:46clojurebotdoes-leiningen-work-in-cygwin?
05:47zmilaleiningen works in command line
05:47cais2002I 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?
05:48cais2002lein.bat works
05:48cais2002but lein.sh does not work inside cygwin
05:48zmilaas windows user i don't know about .sh
05:49cais2002yeah, I can run lein.bat under a normal command prompt
05:52esjcais2002: 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 ?
05:52esjcais2002: I never got it to work right.
05:55esjcais2002: there is a leiningen for powershell with which I had much better luck
05:55cais2002one stupid question, how do I exit from the REPL?
05:56esjcontrol C or D
05:59cais2002hmm, 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
06:14cais2002,(System/exit 0)
06:14clojurebotjava.security.AccessControlException: access denied (java.lang.RuntimePermission exitVM.0)
06:14cais2002this is what I have to do to come outt of the REPL in cygwin
06:20Chousuketry ^Z
06:29cais2002^Z works
06:30cais2002^D works when I run REPL via jline
07:43bartjcemerick: does docuharvest extract (skills, experience, etc.) out of job resumes ?
07:43cemerickbartj: indeed, one of the verticals we're working on
07:44bartjcemerick: I have just uploaded a job CV and it wasn't able to extract any data...or am I choosing the wrong option
07:45cemerickbartj: No document-type-specific processing is live on the public site yet.
07:45bartjcemerick: when will it be ?
07:47cemerickbartj: 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.
07:48cemerickbartj: Which job type did you try just now, form data extraction?
07:49bartjcemerick: yes
07:50cemerickbartj: right, so that's only for interactive PDF forms (i.e. those that you can edit directly in Acrobat, etc)
07:51bartjcemerick: no sorry, the extract pdf form data
07:52cemerickright, same thing
07:52cemerickbartj: 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.
07:53bartjcemerick: cool, thanks!
08:40thetafp(fn i [x] x)
08:45chousera.k.a. identity
09:46dr_benwayhello 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
09:46dr_benwaycreating an uberjar and running it works fine, so it's clearly something wrong with my classpath, but can't figure out what... any tips?
09:46ohpauleezyeah, weird, I was just going to try to tell you to do that
09:46arohnerdr_benway: sounds like clojure.jar is not on your classpath
09:47arohnerhow are you starting the process?
09:48dr_benwayjava -cp lib/clojure-1.1.0-master-20091231.150150-10.jar:lib/clojure-contrib-1.0-20091212.214557-33.jar -jar euler.jar
09:49arohnerdr_benway: -cp and -jar are not compatible
09:50chouser-cp is ignored if you specify -jar
09:50dr_benway...really!?
09:50dr_benwaywell, i've tried setting the CLASSPATH environment variable too - same problem
09:51chouser-jar causes all other classpath specs to be ignored
09:51dr_benwayhow *are* you supposed to set the classpath if you're using -jar?
09:51LauJensenchouser: I just checked the man page for java, and it says
09:51LauJensenBy default, the first non-option argument is the name of the class to be invoked. A fully-qualified class name should be used. If
09:51LauJensen the -jar option is specified, the first non-option argument is the name of a JAR archive containing class and resource files for the
09:51LauJensen application, with the startup class indicated by the Main-Class manifest header.
09:51LauJensen
09:51LauJensen The Java runtime searches for the startup class, and other classes used, in three sets of locations: the bootstrap class path, the
09:51LauJensen installed extensions, and the user class path.
09:51LauJensen
09:51LauJensenDoesnt that lead you to believe that it checks the jar, and the user class path ?
09:53chouserthose paragraphs don't seem to address the point. In my experience, -jar is useless except for uberjars that have everything you need.
09:54LauJensenI guess logically, the point of a jar is defeated if you have to call in resources from outside
09:55dr_benwayso is there any way to "run" a (non-uber) jar?
09:55dr_benwaythere must be some mechanism for resources to be loaded from the class path, right?
09:55LauJensendr_benway: No, and I dont think its intended. Jars are to be embedded, uberjars are to be run
09:57chouserdr_benway: sure, just list all the .jars with -cp and then name the class you want to launch.
09:57dr_benwaychouser: thanks, i'll give that a try
09:58chouserjava -cp clojure.jar:contrib.jar:euler.jar euler.MyMainClass ...or whatever
09:58dr_benwaychouser: yep, that got it - thanks a lot :)
10:00LauJensenah right, sorry I forgot the obvious :)
11:36jcromartieso I think my images-in-REPL idea could happen with a simple hack in Emacs
11:36jcromartieconsidering this is possible: http://julien.danjou.info/blog/2010.html#M%2Dx%20google%2Dmaps
11:37jcromartieer, this is a better link http://julien.danjou.info/google-maps-el.html
11:44arohner,( (fn [[]] (println "hello world!")))
11:44clojurebotjava.lang.IllegalArgumentException: Wrong number of args (0) passed to: sandbox$eval4826$fn
11:45arohner,( (fn [[]] (println "hello world!")) 1)
11:45clojurebothello world!
11:45arohnerI find that very strange
11:48hiredman,( (fn [& []] (println "hello world!")))
11:48clojurebothello world!
12:00Licenserjcromartie: I think there is a graphical REPL already
12:00Licenserhiredman: you know whenever I read your name I'm thinking 'contractkiller'
12:01hiredmanLicenser: right
12:02Licenserdon't ask me why, but seriousely
12:02Licenserdid I discover your try identity and you try to kill me now? :P
12:02Licenserif 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:05hiredmanin 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:07Licenserthat 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:15jcromartieLicenser: it displays images? like DrScheme?
12:15Licenseryes it did
12:15LicenserI'm not sure who made it so
12:16Licenserbut not in the EMACS REPL, it was a stand alone one
12:19hiredmanhttp://github.com/hiredman/Repl
12:21technomancyit's just that every time I read Neuromancer it's so intense that I need a break.
12:22pjstadigits on The List
12:23technomancypjstadig: you can pick a new nick from Mona Lisa Overdrive; then we'll have the Sprawl trilogy covered.
12:24esj"Anathem" by Stephenson, part of that gang, is awesome.
12:24pjstadigtechnomancy: nice
12:24pjstadigwait? what's wrong with my current nic ?!?
12:24pjstadighehe
12:25mattreplreal name vs. screen name, can never decide
12:44alexykhow do I get the CPU time of the current process at a given point in the program?
12:46alexyki.e. is there any equivalent in the JVM for the venerable unix tools to that extent?
12:53alexykdid I miss informative anwers on CPU time?
12:53alexykfogus: go you mean Gibbon?
12:53alexykdo you
12:54fogusalexyk: I mean William Gibson
12:55alexykok. I still didn't read Gibbon but we all should!
13:04aretealexyk: http://nadeausoftware.com/articles/2008/03/java_tip_how_get_cpu_and_user_time_benchmarking
13:04alexykarete: yep, my google got there first! :)
13:04alexykso (time ...) is just clock time?
13:05alexykwall?
13:07AWizzArdalexyk: time is a macro, so you can expand it
13:08AWizzArd,(macroexpand-1 '(time nil))
13:08clojurebot(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:08alexykAWizzArd: is nanoTime wall clock then? :)
13:09AWizzArdLookup the System class in the documentation.
13:10slyrusso how do I tell my leiningen project to use _my_ clojure.jar not some random jar maven downloads from the internets?
13:13AWizzArdthough 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:14AWizzArd,(. System bock.bock.bock/nanoTime)
13:14clojurebot1278004962007300000
13:14AWizzArd,(. System (master.of.barakesh/nanoTime))
13:14clojurebotjava.lang.RuntimeException: java.lang.ClassNotFoundException: master.of.barakesh
13:14alexykwhich animal makes the "bock bock bock" sound?
13:14alexykis it a badjer?
13:15Hodappa chicken?
13:15alexykHodapp: is it the official chicken sound in English?
13:15AWizzArdIn my Clojure funnily (. System (master.of.barakesh/nanoTime)) works :)
13:16AWizzArd,(System/nanoTime)
13:16clojurebot1278005065829352000
13:16alexykAWizzArd: then you have the said master present in your clojure! :)
13:16Hodappalexyk: I don't believe there is an "official" chicken sound in English.
13:16Hodapp"cluck" is probably the closest to what we have.
13:16alexykHodapp: there are, e.g. a horsey says neigh, while in Russian it's игого.
13:16AWizzArdSurprisingly 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:17alexykchildrens' books define the official animal sounds in each language
13:17Hodappthat example proves nothing about its officiality >_<
13:17alexykHodapp: look up kids' books! they are very standard-conforming.
13:18alexykHodapp: right, cluck preempts bock.
13:18alexykbock is a fork of cluck.
13:20AWizzArdrhickey: is that clojure.core/nanoTime still a relict from pre 1.0 versions?
13:24hiredmanAWizzArd: . maybe ignore the namespace part of symbols for easy use inside macros
13:25hiredman,`(. foo (bar))
13:25clojurebot(. sandbox/foo (sandbox/bar))
13:27slyrusanswering my own question, use dev-dependencies instead of dependencies
14:02Licensera very different question what is the difference between (. object method) and (. object (method))?
14:20chouserLicenser: no difference, except perhaps the latter can never be a field lookup
14:41yacinis there an easy way to make certain levels of clojure.contrib.logging go to a file?
14:41yacinso (info ...) will go to a file, but the others won't?
14:41yacinor they go to different files?
14:47DeusExPikachuChousuke: 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:52Drakesonwhat is the difference between re-matches and re-find?
14:52Drakeson,(re-find #"a(b(c))" "abc")
14:53clojurebot["abc" "bc" "c"]
14:53Drakeson,(re-matches #"a(b(c))" "abc")
14:53clojurebot["abc" "bc" "c"]
14:53chouser,(re-find #"c" "abc")
14:53clojurebot"c"
14:53chouser,(re-matches #"c" "abc")
14:53clojurebotnil
14:53chouserwith matches the regex must match the *whole* string
14:53chouser,(re-matches #"a" "abc")
14:53clojurebotnil
14:53chouser,(re-matches #"a.." "abc")
14:53clojurebot"abc"
14:54Drakesonchouser: I see, thanks
15:04Licenserchouser: tank you (belately)
15:04chouserLicenser: :-)
15:05LicenserSometimes I wonder what it is that got me stuck with clojure, the language o the comunity
15:05Licenseror the glue that the I dripped on my c, l and j keys
15:19rysboth
15:19rysFor me anyway
15:29Licenserrys: I gave 3 options you can't say both in a response
15:30Licenseractually you can but its evil and mean
15:30rysMy c, l and j keys are glue free ;)
15:30rysBe hard to write clojure without them
15:31Licenserwell you still have them but you have three fingers fixed there :P
15:32rysThe 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:33Licenser*nods* my feeling too, it is a good language but the comunity is what it makes it exeptional beyond other good langages
15:35rysI 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:38bhenryi try to help in here every time i think i know the answer. and i learn a great deal from people correcting me.
16:15kencausey14
16:15kencauseyoops
16:35puredangerI 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:35puredangeranyone know if that exists yet and if so how to use it?
16:35puredangerOR when it does exist, what will it be called?
16:36puredangerwe've rolled our own atm but would be nice to throw that away
16:37rhickeypuredanger: that did not make it into 1.2
16:37rhickeywill follow shortly
16:37puredangerrhickey: damn, that is tragic
16:37puredangerI loathe having (Foo. nil nil nil nil nil nil) etc all over
16:39qbgHow close is 1.2?
16:39puredangerwe used something like (defn set-record-fields [initial value-map]
16:39puredanger (reduce (fn [source [key value]] (assoc source key value))
16:39puredanger initial value-map))
16:39rhickeyqbg: beta any day now
16:39qbgNice.
16:39puredangerwrapped up in a helper to generate new ones from an empty record or an existing one
16:39rhickeypuredanger: that's pretty inefficient
16:40puredangerrhickey: yes
16:40puredangerrhickey: it would be better if it was in the generated class so I didn't have to write such inefficient code ;)
16:41qbgrhickey: Any plans for 1.3 yet?
16:42dnolenpuredanger: 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:42rhickeyqbg: yeah, what we are talking about now, plus all that prim/num stuff
16:42puredangerdnolen: yes, we were trying to avoid that if a better built-in way was coming
16:43puredangerdnolen: but given that, we'll probably bite the bullet on the macro as we need one per record for the empty case
16:44puredangerrhickey: 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:44slyrusone 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:45slyrusany suggestions on how to debug hanging swank sessions?
16:45raekhow do you get it to hang?
16:45qbgslyrus: Where you launched lein swank
16:46slyrusraek: some command at the slime repl inevitably seems to hang it. In this case it was: (. q atoms) ... seemed innocuous enough
16:47slyrusqbg: 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:48raekyou are supposed to get a stack trace in our repl if anything goes wrong
16:48raekunless you enter an infinite loop or something
16:48qbgslyrus: An alternative is to start a repl, (require 'swank.swank), and then (swank.swank/start-repl)
16:50hiredmanraek: 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:51slyrusok, starting the repl manually looks promising. thanks everyone.
16:51raekI must have some other settings...
16:52raekI get a "pop up buffer"
16:52raekwhere I can select 0 for quit, 1 for cause, etc
16:52raekin that buffer, the stack trace is shown
16:54scottjraek: that's slime
16:55raekoh, I misread
17:09slyrusok, 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:10chouser,(keys (Thread/getAllStackTraces))
17:10clojurebotjava.security.AccessControlException: access denied (java.lang.RuntimePermission getStackTrace)
17:10chouserslyrus: that should do it.
17:11slyrusthanks!
17:13slyrushmm... now is there a way to make a thread throw me some sort of condition from which I can print a stack trace?
17:15chousergetAllStackTraces returns a map of threads to stack traces, so you can just print them from there
17:15chouseractually, on linux you can just type Ctrl-\ and it'll dump stack traces for all threads, plus other debugging info
17:16slyrusneat!
17:45slyruswell, I never really figured out to debug that hanging process, but turning off slime-autodoc seems to fix the problem...
17:46slyrus(and no, this isn't the old problem where any slime-autodoc would hang)
17:48rntzhm.
17:49rntzis there any good way to define two mutually recursive functions in clojure?
17:49slyrusleiningen, did you really just rm -rf my lib/dev directory when I did lein deps?
17:52hugod,(doc trampoline)
17:52clojurebot"([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:52rntzI'm not interested in avoiding stack consumption.
17:53rntzI'm interested in defining two mutually recursive functions that will, yes, eat up more stack space the more they nest
17:53rntzI'm just interested in not getting
17:53rntzjava.lang.Exception: Unable to resolve symbol: bar in this context (NO_SOURCE_FILE:299)
17:53hugod,(doc declare)
17:53clojurebot"([& names]); defs the supplied var names with no bindings, useful for making forward declarations."
17:54rntz:/ forward declarations? really? in the 21st century?
17:54rntzoh well
18:02slyrustechnomancy: why does lein deps delete my lib/dev directory?
18:05Licensercoooookies!
18:05Licenserrntz: it is kind of useful for scoping
18:13rntzLicenser: explain?
18:14Licenserwell 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:14Licenseris it in the namespace or is it just in this functiony?
18:14Licenserand with x I actually mean y
18:15LicenserI 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:17Licenserif you don't do forward declare y there the compiler can't decide how to handle y
18:21rntzLicenser: 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:21rntzie: within this namespace
18:22bhenry,(defn x [] (y))
18:22clojurebotDENIED
18:23bhenryuser=> (defn x [] (y))
18:23bhenryjava.lang.Exception: Unable to resolve symbol: y in this context (NO_SOURCE_FILE:5)
18:25technomancyslyrus: otherwise if you upgrade some of your deps you'd end up with both versions in lib
18:26Licenseroh lein deps does that now :) I really need to update
18:26lpetitrntz: 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:26Licenserrntz: that is guessing not knowing :P
18:27slyrustechnomancy: 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:27rntzlpetit: you could actually just wait until the module is done compiling, then check that all things referenced have been defined
18:27rntzI don't know much about type hints - can you explain?
18:27technomancyslyrus: 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:28lpetitrntz: 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:28rntzlpetit: heh. I guess I'll go look through the mailing list if I find the free time, then.
18:28slyrusperhaps chmod -w lib/dev will do the trick :)
18:28technomancyslyrus: nah; you don't really need to know much
18:28lpetitrntz: one of clojure goals is performance. To attain performance, one must avoid reflection
18:29lpetitrntz: 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:30rntzlpetit: oh, interesting! but hold on, I can go back into a namespace once I've already defined things in it...
18:30rntzand then call def again...
18:30rntzwhich can change the type.
18:30lpetitrntz: 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:31Licenserslyrus: it iwll go away!
18:33lpetitrntz: 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:34rntzlpetit: well, I don't know what term I should be using, but whatever (in-ns) does
18:34lpetitrntz: 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:35lpetitrntz: (in-ns) has a side-effect of changing the thread value of clojure.core/*ns*
18:36rntzright. 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:36lpetitrntz: but yes, you can redefine a var, giving it a new "signature contract". The previously compiled code will not complain :)
18:36rntzah
18:36rntzbut then how can the previously compiled code not be using reflection?
18:36rntzhow can type inference be helping you, if the type of a thing can be changed anyway?
18:37lpetitrntz: 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:37rntz(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:38lpetitrntz: 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:51DeusExPikachudoes anyone know where the str-utils2 version of partial is in the latest clojure.contrib?
19:54DeusExPikachunm, I'll just copy/paste
19:56tomojwhat was a partial in str-utils2 for?
19:57DeusExPikachutomoj: 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:00tomojlike (fn [f x & xs] (fn [& ys] (apply f x (concat xs ys)))) ?
20:00tomojoh, no, that's just like partial
20:01tomojhuh, strange, I still see str-utils2/partial in my contrib
20:01DeusExPikachu(fn [f & args] (fn [s & more] (apply f s (concat args more))
20:01tomoj20100615, guess it's kinda old
20:12bortrebIs 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:24slyrusok, 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:25DeusExPikachuslyrus: is what you're doing pretty complicated? just curious
20:26slyrusI 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:26DeusExPikachuah, so like built from git?
20:26slyrusyeah
20:27DeusExPikachuis the dependency 1.2.0-SNAPSHOT?
20:27tomojyou said you already knew how to install a jar into maven?
20:28tomojjust install it with a special version string like 1.2.0-my-special-SNAPSHOT
20:28tomojor perhaps under your groupId instead of org.clojure
20:28slyrusok, thanks
20:40slyrusworks like a charm. the kool-aid is starting to kick in.
20:52dabdonce 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:53DeusExPikachuM-x slime-connect something like that
20:53dabdI ran slime-connect and I got an *inferior-lisp* buffer but no REPL...
20:55DeusExPikachuyou have (require 'swank-clojure) and (require 'clojure-mode) in .emacs?
20:57bortrebanother way to do it that I prefer is to launch everything from java on the command line
20:57defnlancepantz: around?
20:57bortrebyou can totally control the classpath that way
20:58bortrebjava -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:58bortrebthat's an example
20:59slyrusdabd: you need slime-repl in your .emacs
20:59DeusExPikachudabd: again, you have (require 'swank-clojure) in your .emacs?
20:59slyrus(slime-setup '(slime-asdf slime-repl slime-presentations))
21:00slyrusI don't think swank-clojure alone will get you the repl, just the inferior-lisp buffer. you need slime-repl, AFAIK
21:00slyrusalthough you probably don't need slime-asdf and slime-presentations :)
21:00DeusExPikachuslyrus: haven't used slime/swank lately, but last time I did I never had to use slime-repl
21:01slyrusyeah, they changed the default such that the repl is now a contrib you need to explicitly enable
21:01slyrusslime-fancy will get it for you though
21:02tomojis this advice for someone using slime not from elpa?
21:02tomojno need to touch .emacs if you just want the elpa slime for clojure
21:02slyrusthe question wasn't about elpa
21:02DeusExPikachui just stick with inferior-lisp now, manual and simple
21:02slyrusthe repl is nicer, IYAM
21:03tomojwhat I meant was, was the question "I want X slime version or already have slime..."?
21:03tomojotherwise, elpa is stupid simple
21:03slyrusI 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:04slyrusspeaking of slime... how come slime-presentations aren't supported in swank-clojure?
21:04slyrusI suppose I should wait for technomancy|away to return to ask that
21:05dabdI installed slime-repl from elpa
21:07slyrusand did that fix the problem?
21:07tomojthen don't touch your .emacs
21:08robinkslyrus: He's sitting next to me
21:08bigwavejakehow can I use the min function on a hash? I know which element I want to compare with (let's call it :x).
21:09robinkslyrus: Although he doesn't want to deal with Swank right now.
21:09slyrusheh
21:09slyrusnot surprising :)
21:09robinkslyrus: Local Clojure group is meeting
21:09slyrushave fun!
21:09robinkThanks :-)
21:09defnhttp://github.com/stilkov/jruby-rails-clojure
21:09defncool
21:09slyrusi have to admit, this whole java interop thing is pretty nice
21:10dabdslyrus: it fixed the problem but when I restart my emacs slime-repl is not available. Something must be wrong with elpa
21:12tomojwhat makes you think slime-repl is not available?
21:13dabdtomoj: M-x slime-repl doesn't work
21:14dabdbut if I evaluate M-x package-list-packages it says slime-repl is already installed
21:14bortreb:dabd if you start a swank server from the command line and then do M-x slime connect in emacs does it work?
21:14tomojthere is no M-x slime-repl
21:16dabdbortreb: now it doesn't work
21:16dabdbefore I restarted emacs it worked
21:16dabdat least I got an *inferior-lisp*
21:16tomoj'M-x slime' should work for screwing around without a swank server
21:16slyrusdabd: you want slime-connect if you're connecting to a swank server started in another process
21:17slyrusnot M-x slime
21:17dabdslyrus: yes I start the swank server from the command line with 'lein swank'
21:17slyrusright. if you see an *inferior-lisp* buffer you're doing it wrong
21:17dabdthen from emacs I connect with M-x slime-connect, but now I don't get an inferior lisp anymore
21:17slyrusM-x slime-connect is what you want, I think
21:18slyrusright
21:18slyrusyou don't have an *inferior-lisp* buffer with slime-connect
21:18dabdand what does slime-connect give me?
21:18dabdhow do I get a REPL?
21:18bortrebdabd: a clojure repl
21:18slyrusM-x slime-connect
21:19bortrebdoes it say something like "connection refused" or something?
21:19bortrebyou might run "killall java" and then start over
21:19bortrebjust to be sure there isn't some dead repl hogging up port 4005
21:22dabdunfortunately slime-connect doesn't work: no clojure REPL, nothing and there is no dead repl hogging up port 4005 either
21:22dabdso what is slime-repl for?
21:23dabdhow did you install your slime-repl?
21:23slyrusdabd: slime-repl switches the focus to the slime-repl buffer
21:24tomojyou installed clojure-mode and slime-repl from elpa?
21:24dabdI just installed slime-repl from elpa
21:25dabdI installed clojure-mode from my distribution (arch linux)
21:25tomojI don't guess that would make a difference
21:25dabdhow did you install slime-repl?
21:25tomojjust curious, what version of clojure-mode do they have?
21:25slyrusdabd: you don't want to install slime-repl, per se, you want to install slime and swank-clojure
21:25tomojarch, I mean
21:26tomojno, don't install swank-clojure :P
21:26dabdI install the git version so it is the latest
21:26slyrusIf I were you, I'd get them from the upstream git sources. others here would tell you to get them from elpa.
21:26slyrushow do you use slime without the swank-clojure back end?
21:27slyrusand getting any of the above from a linux distro would be suboptimal, I would think
21:28dabdI have slime-cvs
21:28tomojaha
21:28tomojthis is what I mean about "I want X version of slime" above
21:28slyrusthere's a nice git mirror at: git://sbcl.boinkor.net/slime.git
21:28dabdthe thing is I also installed slime from elpa and this might be causing some conflict
21:28tomojif you don't let elpa take care of everything it won't work
21:29tomojslyrus: swank-clojure in emacs is no longer necessary
21:30dabdyes the readme file for swank-clojure says you should install it from leiningen for example
21:30slyrusyeah, but you still need swank-clojure!
21:32tomojyou need the clojure stuff, yeah
21:32dabdI think I am going to uninstall elpa
21:32tomojthought you meant the emacs stuff, sorry
21:33tomojfwiw, just installed slime-repl from elpa in a virgin emacs and it connects flawlessly to lein swank
21:33tomojbut if you have your own slime.. good luck :(
21:44dabdok 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:45dabdat least slime-connect gives me a clojure repl
21:45technomancyclojurebot: swank-clojure?
21:45clojurebotI don't understand.
21:45technomancyclojurebot: swank?
21:45clojurebotswank is try the readme. seriously.
21:45technomancysorry.
21:46technomancydabd: you shouldn't need swank-clojure from elpa; just clojure-mode and slime-repl.
21:46hiredmanclojurebot: swank-clojure is <reply> see swank
21:46clojurebotIk begrijp
21:47dabdtechnomancy: ok
21:47dabdthanks
21:58thunkDo you still need to (unload-feature 'slime-autodoc t) to get slime to play nice with compound expressions?
21:59technomancythunk: you're installing slime from source?
22:00thunkYup, but it's been a little while since I updated.
22:01slyrushmm... isn't this supposed to work now? : (def z (clojure.java.io.output-stream (new java.io.File "moose")))
22:02technomancythunk: oh, in that case I don't know =\
22:02slyrusthunk: I've been having problems with slime-autodoc and had to turn it off to get things stable
22:02slyrusbut then again I use slime from upstream, not from elpa
22:03hiredmanslyrus: what?
22:03slyrusI can't seem to make clojure.java.io.output-stream work for me.
22:03thunkslyrus: Yeah, same here.
22:03slyrusi'm trying to open a file for writing
22:04slyrusor where you asking about slime?
22:04hiredmanoutput-stream is a function name
22:04hiredmanclojure.java.io is a namespace
22:05slyrusduh. / not .
22:05slyrusthanks.
22:06dabdbecause I tend to forget this stuff I just summed up the steps for getting emacs + clojure working: http://pastebin.org/372744
22:06thunkslyrus: 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:07slyrusthunk: 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:17dabdmy 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:20hiredmanyou need to run lein clean and lein deps
22:20hiredmanyou have an old clojure jar in lib/
22:20dabdI just ran lein deps
22:20hiredmanyou need to run clean
22:21hiredmanactually
22:21dabdok it is fine now, thanks
22:21hiredmanoh
22:21hiredmangood
22:22hiredman(also older lein's had an issue with the repl task not using the right version)
22:36technomancyyeah, that's a known bug of lein 1.1.0
22:39technomancyfixed in 1.2.0 RC
23:43aedonevening. is there an easy way to do reflection (list methods, etc) on java classes from the repl?
23:45qbgaedon: For starters, checkout show in clojure.contrib.repl-utils
23:46aedonqbg: many thanks
23:47hiredman,(->> "foo" class .getMethods (map #(.getName %)))
23:47clojurebot("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:48ysphwhat would be a good reference to start on following the logic for choosing dynamic typing in clojure?
23:49qbghttp://clojure.org/rationale mentions it a little bit
23:54aedonhiredman: sorry if this is a particularly newb question, but what's ->>?
23:56hiredman,(macroexpand-1 '(->> A (F E R T)))
23:56clojurebot(F E R T A)
23:56aedonhiredman: ahh, I think I saw that on hn a few weeks ago. got it.