#clojure log - Feb 13 2011

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

0:02 _Vi: (defmacro qqq [] '(method-name [this] "qqq")) (reify Qqq (qqq)) ;; NullPointerException How to use macros inside reify/defobject?

0:08 In general, how to feed output of my macros to a system macros (without of writing a wrapper).

0:08 s/\./?/

0:08 sexpbot: <_Vi> In general, how to feed output of my macros to a system macros (without of writing a wrapper)?

0:12 _Vi: How to make my macros stronger than usual macros and expand before usual macros see it?

0:28 (deftype Qqq [var1] ...) ;; How to mention "var1" in macro? It says it not found in the namespace. Also referring it by #' fails.

0:40 jkdufair: how would i evaluate a string representation of a class name to a class

0:42 incandenza: (Class/forName "...") perhaps

0:44 jkdufair: thank you!

0:44 incandenza: np

0:54 alex_boisvert: n00b question: I want call "max" on a list

0:54 e.g.

0:54 (def xs [ 1 2 3])

0:54 (max xs) ; doesn't work, need to splat the list; don't know how ..

0:54 brandnewmath: clj

0:54 gregh: (apply max xs)

0:54 brandnewmath: ...doh, sorry

0:55 alex_boisvert: gregh: ah, ok, thanks!

3:59 kumarshantanu: is there a shorter way to transform keys in a map than this? -- (zipmap (map transform-fn (keys m)) (vals m))

4:00 brehaut: (into {} (map (fn [[k v]] [(transform k) v]) m))

4:02 replaca: (into {} (for [[k v] m] [(transform k) v])

4:02 by a few chars :)

4:04 kumarshantanu: berhaut: replace: which is supposed to be faster?

4:04 replaca: kumarshantanu: dunno. I think they're about the same

4:04 brehaut: ((comp (partial into {}) (partial map (juxt (comp inc first) (comp transform-fn second)))) m)

4:05 replaca: brehaut: now you're just being whacky!

4:05 brehaut: church of point free!

4:06 replaca: yeah, in haskell it would be beautiful :)

4:06 brehaut: yeah sadly not so much here

4:07 Scriptor: haskell, in theory at least, curries every function call, so it's natural :)

4:08 brehaut: i think that map is a tiny bit faster than for but the difference is less important than the readability

4:09 kumarshantanu: if you really need to know how fast something is

4:09 use time and dotimes

4:09 kumarshantanu: brehaut: replaca: i am writing a function to do this, so i guess i will go for performance

4:09 replaca: no - I'd love to see a syntax that combined what was beautiful in clojure with what was beautiful in haskell. Rich made some compelling arguments one night about why he though it wasn't possible

4:09 brehaut: kumarshantanu: that is basicly entirely the wrong answer

4:09 replaca: kumarshantanu: I'm with brehaut on this one :)

4:10 unless it's in an inner loop, the difference won't matter

4:10 brehaut: kumarshantanu: hard numbers and real stats after profiling, or use the nice code

4:10 kumarshantanu: you guys mean i should prefer readability even if i am wrapping this inside a function?

4:10 replaca: yup

4:10 brehaut: absolutely

4:11 replaca: in 6 months when you look at your code again to debug it, the quickness that you can absorb it with would be most important

4:11 kumarshantanu: hmm

4:11 replaca: if it were a 2x difference, then performance *might* be the deciding issue

4:12 kumarshantanu: i meant to say -- i am writing a function 'map-keys' that will do just this -- but yeah readability is a bigger gain since the perf difference will be tiny

4:12 replaca: but unless it's in an inner loop, it's unlikely to make more than a couple tenths of a percent difference in your runtime.

4:13 kumarshantanu: i agree

4:13 replaca: I found "for" to be very unreadable when I came to Clojure, but it's long since been second nature

4:14 brehaut: replaca: where did you come from?

4:14 replaca: everywhere :)

4:14 brehaut: haha

4:15 replaca: of course I'd used list comprehension in Python before but something about the difference in the form blocked the mapping in my brain for a couple of months

4:15 brehaut: kumarshantanu: heres a question: why do you think there is no map-keys in the standard lib?

4:15 replaca: map is the same as most every language that has it (esp. CL), so it was easy

4:16 brehaut: replaca: huh thats really interesting

4:17 replaca: yeah, dunno why. It seems so obvious now that the block is broken

4:20 LauJensen: Morning guys

4:20 brehaut: Morning Lau

4:22 Scriptor: morning LauJensen

5:25 _ulises: morning

5:29 anybody doing hadoop stuff with clojure? anybody got any recommendations regarding which libs to use, etc.?

5:32 LauJensen: _ulises: I blogged about one lib, 1) http://bestinclass.dk/index.clj/2010/01/hadoop-installation.html 2) http://bestinclass.dk/index.clj/2010/01/hadoop-feeding-reddit-to-hadoop.html

5:33 _ulises: thanks LauJensen :)

5:33 I was just trying to run the examples of the clojure-hadoop lib (alex ott's fork) but I get weird errors unfortunately, will read your posts, ta

5:39 cpfr: _ulises, cascalog

5:39 _ulises: cpfr: I did see that one, however I want to do plain hadoop for the moment but thanks anyway

6:09 is any of the clojure-hadoop libs on clojars the preferred one? according to LauJensen's post they are broken?

6:10 cpfr: i used stuart's lib

6:25 _ulises: right, I tried one of the forks but it didn't quite work for me; perhaps I should try Stuart's lib then

7:14 xkb: hello

7:14 Is anyone here using clj-oauth with delicious?

8:16 bulters: g'day all

8:48 _ulises: does anybody know how I can pass -XmxNNN to lein swank?

8:50 ah, found it, nm

8:54 Dranik: _ulises, how did you manage that?

8:54 _ulises: Dranik: JVM_OPTS=-Xmx1024M lein swank

8:55 from https://github.com/technomancy/leiningen/blob/stable/resources/script-template

8:55 Dranik: thanks

8:56 _ulises: np

9:12 hrm, I'm having a hard time making this clojure-hadoop thing work. If I run from the repl (run job) (where job was defined with defjob as per the wordcount examples) the jobs run fine, but the minute I try running a job from the command line with java -cp it all blows up, anybody got experience with this lib and is willing to give me a hand? :)

9:15 raek: is there any documentation for the contract of the .equiv method of clojure.lang.IPersistentCollection?

9:48 khaliG: is there a way to wrap a var on a struct?

9:55 dont know if my last message went through but i'm wondering if it's possible to wrap a Var on a struct. Otherwise i'm guessing you'd have to use an atom and access the fields in a sync block thing.

9:57 Cozey: is there something like (get-in ) but for vectors as well?

9:59 opqdonut: get-in works for vectors

9:59 ,(get-in [[0 1 2] [3 4 5]] [1 1])

9:59 clojurebot: 4

10:03 raek: khaliG: what do you mean by "wrap a Var on a struct"?

10:03 could you give an example on what you want to do?

10:04 khaliG: i mean (ref <a-struct>)

10:04 Chousuke: and?

10:04 that works just fine

10:04 though in most use cases you'll probably want a record instead of a struct

10:05 khaliG: ok

10:06 Chousuke: though I'm suspicious now. are you sure you need refs at all?

10:07 using refs just because you think you need to mutate something is usually wrong :)

10:07 khaliG: it's possible i'm wrong :)

10:07 Chousuke: that is, there might be a solution that doesn't require mutation at all

10:07 and you should prefer those

10:08 The less "mutable" elements your design contains, the easier life will be.

10:08 hmm, fewer*

10:08 khaliG: understood, though i dont know if i could do this without mutation, i'm accumulating some values

10:09 Chousuke: reduce?

10:09 raek: sounds like a job for reduce

10:09 Chousuke: your accumulator does not have to be mutable

10:11 khaliG: yea let me think but my gut feelign is it's not possible to do without mutation here

10:11 Chousuke: describe what you're trying to do and maybe we can help

10:12 khaliG: Ok. i have an exercise model which consists of tables of values for each exercise (sets, reps weight etc), and a workout model which consists of exercises and a few other datums. The data is entered by the user via a Swing UI, and i store the imputs in clojure structs and vectors

10:13 could i do away with mutation or do i need to provide more information?

10:13 Chousuke: so you need to update the models?

10:13 khaliG: correct

10:13 Chousuke: right, for that part, you'll need a ref or something

10:14 but that's only for the final storing of the updated value

10:14 most of the related code you can write without mutation

10:14 khaliG: yes i have written it that way :)

10:14 Chousuke: sounds like you're on the right track then

10:15 khaliG: atm i have this call (send data conj model) which would work fine if data was a vector, but its not a struct and that's where i got stuck

10:15 Chousuke: you can use update-in

10:15 khaliG: it worked fine before though as long as my data was in that vector (data)

10:15 ooh, let me read about update-in

10:15 Chousuke: (send data update-in [:key] conj whatever)

10:15 khaliG: that sounds perfect!

10:16 Chousuke: I like the chaining aspect of update functions

10:17 khaliG: i was unwittingly seeking somethign like that, now that've mentioned it

10:17 Chousuke: there's also assoc-in

10:17 khaliG: thank you

10:21 bulters: what's the current-easiest-way of doing the whole emacs-clojure-repl dance these days?

10:21 I keep losing track of which guide to read ;-)

10:22 khaliG: bulters, on which platform?

10:22 bulters: os x

10:23 khaliG: not sure about os x, but linux was painless using the emacs package installer thing. i had problems on windows though

10:24 _ulises: bulters: do you mean installing or running/devving?

10:24 bulters: _ulises: well, already got clojure installed (via leiningen)

10:25 _ulises: I usually add swank-clojure to my :dev-dependencies

10:25 and I just discovered a super-neat trick of leiningen, which is to have a checkouts/ dir in your project with symlinks to other projects you're hacking in parallel

10:26 leiningen picks those up automatically so you don't need to restart your swank server, etc. etc.

10:26 bulters: And I guess installing the swank-clojure and slime packages might help as well...

10:27 _ulises: yup, that's how I do it. I've tried eclipse but I'm sort of used to using emacs in my daily routine so...

10:27 khaliG: pretty much, and then you start swank in your clojure project, and M-x slime-connect in emacs

10:27 bulters: _ulises: you add them as git (or s/ by your favorite scm) submodules?

10:27 _ulises: bulters: atm I'm issuing lein jar as I'm testing launching my app through java

10:27 and that rebuilds the dependencies, etc.

10:29 bulters: cool

10:30 _ulises: if I have an fn [ args ] how can I detect if args is iterable/seqable? say I can either pass it a map or an fn?

10:30 there's fn? for that, but for maps?

10:31 bulters: oh this is nice... :D thanks for the quick pointer...

10:31 _ulises: ,(doc map?)

10:31 clojurebot: "([x]); Return true if x implements IPersistentMap"

10:31 _ulises: bleh

10:31 bulters: sure, np :)

10:41 rlb: I was looking at the tutorial posted here the other day (http://mmcgrana.github.com/2010/07/develop-deploy-clojure-web-applications.html), and for some reason, the POST handler isn't receiving any form arguments. They're {}. Any idea what I might be doing wrong?

11:05 raek: bulters: install clojure-mode, slime, slime-repl in emacs with package.el, :dev-dependencies [[swank-clojure "1.2.1"]] in project.clj, lein deps, lein swank and then M-x slime-connect from emacs

11:06 most importantly: do not use the deprecated swank-clojure _emacs_ package

11:07 khaliG: hm so don't install swank-clojure at all?

11:07 i've got 1.1.0 installed

11:07 raek: bulters: using technomancy's clojure-starter-kit gives you package.el with correct settings. see the docs on http://github.com/technomancy/swank-clojure/

11:07 khaliG: the clojure lib or the emacs package?

11:07 khaliG: emacs package

11:07 raek: no.

11:07 khaliG: oops, okay

11:07 raek: it is from pre-leiningen ties

11:07 *times

11:08 use durendal (another project of technomancy's) if you want a quick way of launching the swank server from emacs

11:48 bulters: raek: thanks, I've tried the starter kit; but decided to roll my own... part of the emacs learning process :P

11:51 durendal looks nice though...

12:27 xkb: Is anyone here using clj-oauth with delicious-api?

12:28 or anything requiring Authentication headers

12:34 thorwil: i'm trying to follow https://github.com/gcv/appengine-magic#readme. but how do i get into my applications core namespace on the repl?

12:35 raek: thorwil: you mean something like (in-ns 'the-namespace)?

12:36 thorwil: i guess with in-ns, but the right argument to not trigger a no-source eludes me

12:36 raek: (C-c M-p in emacs)

12:36 ah, you need to load it first (require 'the-namespace)

12:36 (C-c C-k in emacs)

12:37 (doto 'the-namespace require in-ns) is a nice combo

12:37 thorwil: ah, not sure what "lein repl" does or doesn't, in that regard

12:37 but i was also missing the '

12:37 raek: all it does is to launch clojure with the correct classpath. it does not load any namespaces except clojure.core

12:38 yeah, they are functions, so you have to quote the symbol.

12:38 (unlike the corresponding :require and :use features of 'ns')

12:38 thorwil: i know in principal, but i'm just starting with my first lisp here ;)

12:39 thanks!

12:39 raek: np.

12:40 xkb: aargh again wrong signature.. hmm oauth is bleh

12:40 raek: xkb: have you tried asking at the clojure or clojure-web-dev google groups?

12:43 xkb: raek: not yet, will keep on tinkering for about 1 hour. And if that fails, Ill ask :)

12:43 the fault is prob. in the encoding of the uri/params

12:45 raek: ring has some utility functions for param encoding in uris

12:45 khaliG: aw, slurp/spit wont work with Java Dates? :/

12:46 raek: khaliG: they operate on strings

12:46 khaliG: k

12:46 raek: so you need to do the string <-> date conversion yourself

12:46 khaliG: understood

12:46 its the only object remaining which isn't a readable string afaik

12:47 (in my code i mean)

12:47 raek: for clojure data structure, you can just use read-string and pr-str

12:48 khaliG: nice

12:48 raek: spit will call str (which corresponds to java's toString method) on its argument, which does not work for all kinds of data

12:49 khaliG: seems Date has a toString method

12:49 but i can't see a fromString

12:49 raek: ,(str (lazy-seq [1 2 3]))

12:49 clojurebot: "clojure.lang.LazySeq@7861"

12:49 raek: ,(pr-str (lazy-seq [1 2 3]))

12:49 clojurebot: "(1 2 3)"

12:50 khaliG: maybe i can use a different time structure, lets see if there are any clojure libs for that

12:50 raek: khaliG: Joda time is a much better lib for working with dates in java. the clojure port is called clj-time

12:50 khaliG: oh nice!

12:52 hm perhaps i can just write my dates as longs and then read them back

12:53 i'd rather not do any sort of marshalling though

12:53 i'll explore jodatime

12:53 thanks raek

12:53 raek: yeah, milliseconds since the epoch (in UTC time) as a long is a pretty universal representation

13:35 khaliG: i love how i'll make a change to a running swing program, move to restart it after making a change and realising i just need to recompile the changed method

13:46 pppaul: hey, i'm getting an error with spit

13:46 java.lang.Exception: Cannot change an open stream to append mode.'

13:46 i'm using conrtib/append-spit

13:53 raek: pppaul: is the file writable? also, you can use spit from clojure core since 1.2: (spit "file.txt" the-string :append true)

13:53 pppaul: oh, thanks

13:53 that's much cleaner

13:53 spit is making the file

13:54 i'll change my code to your suggestion

13:56 i don't get the error now

14:53 thorwil: is that normal that the repl in emacs doesn't react anymore after i started a jetty server (via appengine-magic)?

14:56 rlb: It looks like none of the :input parameters from the example are making it to the POST handler. Can I get jetty (or clojure) to be more verbose wrt the actual POST?

14:56 s/clojure/compojure/

14:56 sexpbot: <rlb> It looks like none of the :input parameters from the example are making it to the POST handler. Can I get jetty (or compojure) to be more verbose wrt the actual POST?

15:06 brehaut: rlb is there a logging middleware you could use?

15:13 bobo: what is a good way to do something that should run every 5sek in clojure? should i use executors and such from java?

15:15 brehaut: (doto (Thread. (fn [] (while true (let [t (calc time now)] (do-action) (Thread/sleep (- 5000 (- now t))))))) .start)

15:15 pretty blunt

15:16 i guess you could use an agent

15:16 instead of an explicit thread

15:17 bobo: Thread feels very blunt, then exexutors feels nicer

15:20 brehaut: (defn tick (agent nil)) (defn act [v] (do-something) (Thread/sleep 5000) (send tick act))

15:20 thats with agents and minus the math to make it a bit more precise

15:20 raek: bobo: there is a executor class for scheduling repeating tasks

15:21 http://download.oracle.com/javase/6/docs/api/java/util/concurrent/ScheduledExecutorService.html

15:22 http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Executors.html#newScheduledThreadPool(int)

15:22 bobo: also, cron4j works wonderfully when you need to schedule tasks as you would with unix cron

15:23 rlb: brehaut: don't know -- I was just trying the example posted here the other day. I'm not all that familiar with compojure/hiccup/ring/etc. yet.

15:24 the POST comes in, but :params is {}.

15:25 raek: thorwil: I don't know exactly how appengine-magic starts the jetty server, but if you start jetty manually, you can give it the :join? false option to not block until the server is shut down

15:27 cron4j example (I just love how simple it is):

15:27 (defonce scheduler (doto (it.sauronsoftware.cron4j.Scheduler.) (.schedule "30 16 * * 1-5" #'my-fn) (.start)))

15:28 this executes my-fn 4:30 PM every monday-friday

15:28 bobo: raek: yeh i know they ar ein java :-) just thought if there was something nice in clojure. but il use the java stuff then

15:28 brehaut: rlb: what middleware do you have running?

15:29 _Vi: Why when I issue "(ns ...)" in REPL I lose access to "doc" function?

15:29 rlb: brehaut: ring.adapter.jetty? Starting it like this: (run-jetty #'main/app {:port 8080})

15:29 brehaut: rlb thats your adapter rather than middleware

15:29 replaca: raek: do you have the leiningen :depends line for cron4j handy?

15:30 brehaut: i dont know of compojure automatically includes ring.middleware.params or similar

15:30 rlb: brehaut: Other than that, just using compojure and hiccup. See here:

15:30 brehaut: hiccup isnt relevant here

15:30 rlb: http://mmcgrana.github.com/2010/07/develop-deploy-clojure-web-applications.html

15:31 raek: bobo: well, I made a library that does some of these stuff (not the Scheduled vareity of executors though) by some pretty redundant functions: https://github.com/raek/lcug-concurrency/blob/master/src/se/raek/lcug/concurrency.clj#L208

15:31 rlb: I adjusted the POST handler like this: (POST "/" x (prn x) ...)

15:31 raek: replaca: I found this: [org.clojars.ghoseb/cron4j "2.2.1"]

15:31 rlb: so I could see x, and I can see that params is {}

15:32 bobo: raek: il take a look!

15:32 raek: iirc, it wasn't in the maven repo, but someone had pushed it to clojars

15:32 rlb: (on stdout)

15:32 I just wondered if that example might be stale somehow, i.e. the form set up wrong or whatever...

15:32 raek: bobo: basically, all the fns look like this: (defn submit [exe task] (.submit exe task))

15:33 brehaut: rlb im not an expert on compojure sorry

15:33 raek: I'm thinking about generating clojure/autodoc-style docs from javadocs

15:33 so that people don't miss what's directly usable from java...

15:34 bobo: also, did you see my post re executors in clojure?

15:34 brehaut: raek: that would be handy for the not-from-java people like me

15:34 bobo: raek: i dont think i did?

15:34 raek: http://blog.raek.se/2011/01/24/executors-in-clojure/

15:35 rlb: brehaut: np, and thanks.

15:37 brehaut: rlb may i suggest putting together a simple middleware to print out the entire request before it goes into compojure?

15:37 there is an example in the tutorial you are working through that shows how to install ring middleware with compojure

15:38 your middleware will be approximately (defn log-request [handler] (fn [req] (prn req) (handler req)))

15:53 mreynolds: newb question : I'm doing (doseq (keys map) ...) and I'm getting this error : error: java.lang.IllegalArgumentException: doseq requires a vector for its binding (core.clj:12)

15:53 Do I have to wrap the returned seq in a vector (or convert it?)?

15:54 opqdonut: (doseq [k (keys map)] ...)

15:54 now the variable k will get bound to each key of the map in turn

15:54 mreynolds: duh

15:54 Thanks

15:59 thorwil: raek: seems :join? did the trick. strange how without, some operations work and other just hang there. thanks!

16:00 rlb: brehaut: ok, thanks again.

16:15 brehaut: post prints as {... "application/x-www-form-urlencoded" ... :body #<Input org.mortbay.jetty.HttpParser$Input@5f4f5a31>}

16:18 brehaut: rlb can you put the ring.middleware.params/wrap-params middleware in before your logging middleware?

16:23 rlb: brehaut: like this? (def app (-> #'handler (wrap-params) (log-request)))


16:24 brehaut: swap wrap-params and log-request

16:24 shortlord: are there any simple RPC frameworks for clojure? (I just need something to call clojure functions remotely on client and server)

16:25 brehaut: shortlord: what kind of RPC?

16:25 raek: rlb: the last middleware will be the one that sees the request first and the response last

16:25 moustache reverses this in its syntax

16:26 ...since it becomes the outermost wrapping middleware

16:27 brehaut: shortlord: if its not for real work then i have an xml-rpc library that works with ring and provides both sides of the rpc stack, but i dont like xml-rpc and wouldnt recommend it for a real world system

16:27 shortlord: brehaut: I have an application that I need to split into a server and a client that renders the server contents and calls some server functions depending on user input. Nothing fancy, simply calling clojure functions remotely (both client and server are clojure-based) would be enough (similar to java RMI)

16:28 technomancy: shortlord: try clojure.contrib.server-socket/socket-repl

16:28 shortlord: brehaut: priority is not performance, but fast and easy integration into existing non-distributed code

16:28 technomancy: though I guess you would rather have socket-rep

16:28 rlb: brehaut, raek: thanks - that fixed it. I was starting with the first example on that page, and it doesn't use middleware (wrap-params, etc.).

16:29 brehaut: shortlord: github.com/brehaut/necessary-evil

16:29 if technomancy's solution doesnt work for you

16:29 shortlord: but i wouldnt recommend it

16:30 shortlord: brehaut: ok, thx a lot

16:31 I've thought about using a simple remote repl, but it would be quite insecure to pass any kind of string and evaluate it. So I guess I would have to build a custom check that only allows the execution of predefined functions, right? Does something like that already exist?

16:32 brehaut: shortlord: if you use a repl yeah you'd have restrict it somehow. cljail might help there

16:33 you need to explicitly expose functions with necessary-evil

16:35 shortlord: brehaut: searching for cljail does not give me any results, do you mean clj-sandbox?

16:35 brehaut: shortlord: honestly im not sure. whatever raynes and amalloy's project is called

16:36 https://github.com/Raynes/clojail

16:38 mreynolds: More newbness : What's the idiomatic way to lookup data from nested maps? Like {:a {:b "b" :c "c"}}, where I want to get :c's value.

16:39 brehaut: ,(get-in [:a :c] {:a {:b "b" :c "c"}})

16:39 clojurebot: nil

16:39 raek: making a custom interpreter for a limited command set (possibly using the clojure reader) sound much more secure

16:39 shortlord: brehaut: cool, thx a lot for the link

16:40 mreynolds: nice, thanks!

16:40 brehaut: ,(get-in {:a {:b "b" :c "c"}} [:a :b])

16:40 clojurebot: "b"

16:40 brehaut: mreynolds: if i got it round the right way :P

16:40 mreynolds: brehaut: No worries, I'm still mapping out functions, so just having the pointer is good enough

16:40 brehaut: mreynolds: its part of a family including assoc-in and update-in

16:41 mreynolds: clojuredocs.org/quickref/Clojure%20Core

16:41 mreynolds: brehaut: I'll go check those out. I bought clojure in action and joy of clojure and I've been piece-meal making my way through them.

16:44 brehaut: I sort of wish the clojure docs would have an alternate structure similar to how the code is laid out. I find myself looking at the source often and seeing the functions that are "similar" to that function (as you mentioned, assoc-in and update-in are right next to each other), but aren't in the docs

16:47 brehaut: mreynolds: projects using marginalia have that

16:47 mreynolds: brehaut: Haven't used that yet, I'll go look at it

17:14 Similar question : I'm building a data structure to allow people to specify files to "watch" in special ways. I was building nested data structures ({:stuff {:type "dir", :other-type "otherdir}}) and get-in let me get those nested pieces of data easily. I now want to, basically, walk the data structure, looking at the "dir"s and replace them with actual File objects. I thought about doing this with zippers, but I wanted to ask

17:16 chouser: zippers would work

17:17 mreynolds: you might also try clojure.walk

17:17 mreynolds: chouser: I'll look at both, thanks for the pointers

17:18 chouser: Walk looks pretty damned perfect

17:18 chouser: Thanks

17:18 chouser: np

18:00 replaca: raek: belated thank you!

18:03 rata_: hi

18:07 aleksander: hi

18:09 michaeljaaka: hi

18:09 is there anyone live?

18:10 brehaut: michaeljaaka: probably

18:10 michaeljaaka: :) thanks, I thought that i have something wrong configuration

18:10 no welcome message, no activity messages

18:10 etc.

18:48 _Vi: Is there somewhere official use case lists for Atoms, Agents and Refs? E.g. a task where only Atom suits (but not Agent or Ref), a task for Agent...

18:50 jacortinas: _Vi: afraid not, but that would be pretty awesome resource

18:52 _Vi: For example logging somewhere from multiple threads. Agents are OK, but atoms and refs are likely not.

19:08 gfrlog: I wonder if agents are implemented with atoms

19:26 _Vi: Why "alter" and "send" do not end with exclamation point, but "swap!" does?

19:27 pdk`: it's just a typical little idiosyncracy i guess

19:27 _Vi: Having trailing "!" makes feeling of some unsafety.

19:28 pdk`: i dunno why there can't just be some sort of update! function that works on refs/atoms/agents all alike

19:28 Chousuke: alter and send are safe in dosync

19:28 pdk`: maybe have a keyword arg for it when you need send-off style behavior or something

19:28 Chousuke: swap! isn't

19:29 _Vi: When I writing my own functions, when should I finish their names with "!"? Is there some convention there?

19:31 pdk`: ! implies that the function is destructive or carries side effects beyond returning a value

19:32 it's an old convention from scheme where the functions that did destructive stuff with lists had !

19:32 and since refs/agents/atoms are the only mutable forms of data you'll be working with often in clojure outside of java interop well

19:33 _Vi: pdk`, For example, should some "printDebugLog" be "printDebugLog!"?

19:33 pdk`: it doesn't seem necessary there

19:33 though note that lisp function naming convention would favor print-debug-log over printDebugLog

19:34 Chousuke: well actually

19:34 _Vi: Is the rule like "put ! if it have side effects and it is not obvious"?

19:34 Chousuke: the convention is to use ! if the function is unsafe in dosync and it's not obvious

19:34 pdk`: you'd be fine with that route i think

19:35 in scheme ! was basically a warning that the function you were using could modify the list you passed to it in-place without any other advance warning

19:35 Chousuke: eg. spit etc. are unsafe, but it's obvious so there is no bang

19:35 _Vi: (BTW should it be "unsafely-check-some-condition?!" or "unsafely-check-some-condition!?")

19:35 pdk`: and in clojure none of the basic data structures are mutable outside of storing them in refs/agents/atoms

19:36 Chousuke: but swap! has the bang because you might not think that it's unsafe in dosync forms

19:36 _Vi: have two functions? :P

19:36 (predicate? (some-unsafe-stuff!))

19:37 _Vi: Chousuke, Means the "predicate" with side effects.

19:37 Chousuke: predicates shouldn't have side-effects :/

19:37 pdk`: the idea he's getting at is to have a function that does the unsafe stuff and returns some value

19:37 then checking that value against a safe predicate

19:38 _Vi: Also: Should I consider the function side effects free if it actually have debug-only side effects (such as printing in some log or incrementing statistics counter)?

19:38 Chousuke: no

19:39 unless you can disable that behaviour in production code

19:39 _Vi: For example, when debugging is switched off (release version) it becomes truly side-effects-free.

19:40 Chousuke: you'll get some funky debug output if you use such functions in transactions though :)

19:40 dnolen: _Vi: ! is really to indicate changing a "place" in a way that that doesn't specify any "time management" strategy. alter doesn't need it, they are inside dosync. agents imply uncoordinated concurrency.

19:41 Chousuke: dosync handles sends specially, which is why send doesn't have the bang

19:43 pdk`: i wouldn't bother if it doesn't change anything that's relevant to an outside caller of the function

19:43 if it's closed over some counter that's just there for debugging and doesn't affect the behavior of any functions or modify other outside state then whatever basically

19:46 Chousuke: well, yeah.

19:46 as long as the side-effect is inconsequential to the program it's fine I guess :P

19:47 _Vi: Chousuke, So I can add "invocation counter" statistics without fear being bad guy.

19:47 s/fear/fear of/

19:47 sexpbot: <_Vi> Chousuke, So I can add "invocation counter" statistics without fear of being bad guy.

19:48 Chousuke: _Vi: it's just a bit dirty, but I guess you can.

19:48 _Vi: at least use a macro or something you can easily disable :)

19:49 then when you ship a release version, just define the macro to return nil or something :P

19:49 in essence making it a comment

19:55 _Vi: What should I do if I want to have a macro that expands in two (or more) forms? (and I cannot use "(do ...)" because of it is not a code)

19:56 brehaut: _Vi, use do

19:56 _Vi: brehaut, This is not a code. It is either data or some internals of "reify" or "let" or whatever.

19:57 brehaut: then use functions

19:58 _Vi: The only not-so-nice solution I see is to wrap containing for in macros that will handle this duplication.

19:59 johnhunter: hi, I have a noob question

19:59 brehaut: johnhunter: you are welcome to ask it

20:00 johnhunter: thanks, i am writing a swing app, and i want in a text field to let the user write some clojure code - a dsl if you will

20:00 when I get the text, i call (eval text)

20:01 it seems eval runs from the clojure.core namespace, not my app's namespace

20:01 so none of my def'd data values are found

20:01 _Vi: johnhunter, Example:

20:01 (eval (read (java.io.PushbackReader. (java.io.StringReader. "(+ 4 5)"))))

20:02 johnhunter: yes, thanks, that is roughly what i am doing, and it works for (+ 4 5)

20:02 brehaut: johnhunter: there is a with-ns function defined somewhere

20:03 johnhunter: oh.. let me look that one up

20:03 brehaut: just cant workout where 'somewhere' is

20:04 johnhunter: http://richhickey.github.com/clojure-contrib/with-ns-api.html

20:04 brehaut: that would be it

20:07 johnhunter: the only thing is eval seems to start from clojure.core, and it knows nothing about with-ns from contrib

20:07 i'm very fuzzy on all this namespace stuff

20:07 brehaut: i would have assumed that (with-ns namespace (eval ...)) would have fixed that?

20:07 alternatively

20:08 johnhunter: oh, i think you might be right... i just have to include that contrib in my main app

20:08 i'll try that, thanks

20:08 brehaut: (eval (concat (list with-ns namespace exp)))

20:08 wait madenes

20:08 (eval (list 'with-ns namespace exp))

20:09 philipo: clojure

20:18 johnhunter: it doesn't seem to resolve with-ns shouldn't i get it by including clojure-contrib in my project.clj like ... :dependencies [[org.clojure/clojure "1.2.0"]

20:18 [org.clojure/clojure-contrib "1.2.0"]]

20:18 brehaut: have you got a use or require in your ns?

20:18 johnhunter: :require

20:20 how do i check if it is in clojure.contrib 1.2?

20:20 brehaut: are you referencing with-ns with the fully qualified project?

20:20 it is

20:21 johnhunter: nope, just (with-ns myns.core (eval ....)

20:21 brehaut: there you go then; with a require you need to qualify any functions in that namespace

20:21 so if you have bare require, you need clojure.contrib.with-ns/with-ns

20:21 if you have an :as require

20:22 johnhunter: ah...

20:22 brehaut: (eg (:require [clojure.contrib.with-ns :as with-ns]))

20:22 you do just with-ns/with-ns

20:22 johnhunter: and what if i just want to call (with-ns ... ?

20:22 :use ?

20:22 brehaut: use use

20:23 IMO - dunno if its considered idiomatic - you should prefer requires to uses, and if you do decided to use a use, you should qualify all the imports with only

20:23 johnhunter: ok, for some reason this namespace stuff won't stick in my brain

20:23 brehaut: eg (:use [clojure.contrib.with-ns :only [with-ns]])

20:25 i generally use aliased requires except for some operators or forms that are cleaner (and clear where they from) when used

20:43 gfrlog: brehaut: now that I've waited a day, do I get to hear what you were thinking of?

20:43 brehaut: declare

20:43 perhaps with a with-ns ?

20:43 gfrlog: yes, I think that would do it

20:44 I tried it with a fully qualified symbol but I don't think that works

20:44 brehaut: however, given ive had a day, i think that probably i was wrong given your requirement to declare something in another ns

20:44 gfrlog: wrong how?

20:44 that hiredman wasn't thinking of that?

20:44 brehaut: that it might not work?

20:44 both

20:45 gfrlog: I'll see if it works...

20:45 brehaut: hiredman is much better at this than i am

20:45 absolutely worth a shot

20:45 gfrlog: do you think either you or him were suggesting that it's better code than my eval version? Or just that eval isn't strictly necessary?

20:46 brehaut: using eval is a fairly good sign somethings been overlooked

20:46 its more of an implementation tool than a usage tool

20:46 gfrlog: so you prefer several lines of non-eval code over one line of eval code?

20:46 brehaut: yeah typically

20:47 im not convinced you should need to fire up the compiler for small things

20:47 those couple of lines could be abstracted to declare-with-ns or soemthing and become a library function

20:47 * brehaut is no expert

20:47 tomoj: how do you avoid eval?

20:47 gfrlog: that's a good point

20:48 tomoj: apparently by using with-ns and declare

20:48 but actually I'm sure that wildly depends on what you're using it for

20:48 brehaut: tomoj: thats a guess on my part. i think hiredman was sure of a good way to do it though

20:48 gfrlog: ,(eval "2893")

20:48 clojurebot: DENIED

20:48 gfrlog: ,(Integer. "2893")

20:48 clojurebot: 2893

20:49 brehaut: yeah your not going to get to execute arbitrary code in the bots

20:49 gfrlog: (eval '(println "DENIED"))

20:49 ,(eval '(println "DENIED"))

20:49 clojurebot: DENIED

20:49 brehaut: haha

20:49 tomoj: there were ways with sexpbot recently

20:50 there may still be

20:50 gfrlog: brehaut: I had not thought of what I was doing as "firing up the compiler" until you put it that way

20:51 now I am a better man

20:51 brehaut: bbs coffee

20:52 tomoj: how would either of with-ns or declare help?

20:54 gfrlog: tomoj: that was specific to my case

20:55 for your question, you have to show how you're using eval first

20:55 tomoj: I believe I remeber your case

20:55 gfrlog: okay, well for my case...

20:55 tomoj: and don't see how it would help

20:55 gfrlog: he thought that the specific var whose value I wanted to execute could be created before the library is loaded

20:56 by... (with-ns 'my.namespace (declare go))

20:56 I just tried that on my code and got strange results

20:57 tomoj: I didn't actually remember your case

20:57 gfrlog: so apparently it doesn't do the same thing as ((var-get (find-var 'my.namespace/go)))

20:57 tomoj: since you were talking about eval too I thought you were the one eval'ing gui input

20:57 gfrlog: oh, no

20:57 my case is from yesterday

20:57 I have a program where most of the code is loaded at runtime

20:58 the entry point to that code is where I call (my.namespace/go)

20:58 but the compiler won't let me do that since it doesn't know about the namespace yet

20:58 so I was doing (eval '(my.namespace/go))

20:58 which worked just fine

20:58 but offended everybody's sense of decency

20:58 tomoj: right, I see

20:59 gfrlog: I'm still doing the (find-var) thing

21:04 rata_: gfrlog: I think it's not the compiler that doesn't know about the namespace

21:04 gfrlog: rata_ my being wrong would not surprise me, as the whole issue of the clojure compiler gets me fogged up -- what would you say that it is?

21:05 rata_: the evaluator

21:05 (if that's the name for what executes your code at runtime)

21:05 gfrlog: hmm

21:06 but my code should work at the time it's evaluated

21:06 rata_: and I thought yesterday hiredman was referring to the (intern ns name) fn

21:06 gfrlog: ,(doc intern)

21:06 clojurebot: DENIED

21:06 gfrlog: ew

21:06 rata_: do you get your error when compiling your code?

21:06 gfrlog: "lein compile" you mean?

21:06 rata_: ~(doc intern)

21:06 clojurebot: gitdoc is http://github.com/Lau-of-DK/gitdoc/tree/master

21:07 rata_: gfrlog: for example... or (compile ...)

21:07 gfrlog: I'll try lein compile

21:07 rata_: or C-c C-k en slime

21:09 gfrlog: rata_ my religion doesn't permit me to use slime

21:09 rata_: ok np

21:09 gfrlog: rata_: lein compile gives the expected ClassNotFoundException

21:09 rata_: ok, so it's the compiler effectively

21:09 my fault

21:10 gfrlog: np

21:11 rata_: when I try intern at the repl using symbols, it complains that the not-yet-existing namespace isn't found

21:11 rata_: then intern won't solve the problem either

21:11 gfrlog: I don't see it as a problem. Just a mystery of what hiredman was thinking of.

21:12 rata_: intern is a fn so it won't solve anything at compile-time I think

21:12 gfrlog: var-get and find-var are both fns, I assume, and they sufficed

21:14 rata_: yes, but you use them to not have to evaluate the symbol... you give the symbol quoted

21:15 (is that proper english?)

21:15 gfrlog: right -- you're hoping to find something that allows the symbol unquoted?

21:15 rata_: yes

21:15 gfrlog: sure looked like english to me

21:15 yeah, I guess a macro could work that out pretty easily. I guess then you're looking for an existing macro in clojure.core or something?

21:18 rata_: when I compile code that mentions a non-existent var or a non-existent namespace, it doesn't give me a ClassNotFoundException

21:19 gfrlog: ,(why.wont.this/work?)

21:19 clojurebot: java.lang.ClassNotFoundException: why.wont.this

21:19 gfrlog: like that?

21:20 rata_: hmmm strange I don't get that

21:20 perhaps an slime thing, but I don't think so

21:22 aha... I have tried with something like (a/b) but not (a.b/c)

21:22 gfrlog: ,(a/b)

21:22 clojurebot: java.lang.Exception: No such namespace: a

21:22 gfrlog: yeah

21:22 I get results based on that too

21:23 rata_: so I think the problem is the namespace, not the var

21:25 gfrlog: ,(clojure.core/rata_)

21:25 clojurebot: java.lang.Exception: No such var: clojure.core/rata_

21:25 gfrlog: so you think that would compile?

21:26 (but not eval of course)

21:26 rata_: no, but that gives another error

21:26 java.lang.Exception

21:26 gfrlog: even at compilation?

21:27 rata_: yes

21:28 I have just compiled it and gave me that error

21:28 gfrlog: this is an interesting contrast to other dynamic languages

21:28 ruby will let you call whatever made up function you want and doesn't object until it executes

21:29 rata_: perhaps the solution is (refer ...)

21:29 have you tried that?

21:29 (refer your.ns)

21:29 gfrlog: ,(doc refer)

21:29 clojurebot: "([ns-sym & filters]); refers to all public vars of ns, subject to filters. filters can include at most one each of: :exclude list-of-symbols :only list-of-symbols :rename map-of-fromsymbol-tosymbol ...

21:30 gfrlog: ,(refer rata.gfrlog)

21:30 clojurebot: java.lang.ClassNotFoundException: rata.gfrlog

21:30 gfrlog: so I'd probably get that?

21:31 rata_: yes =(

21:31 ,(doc load-string)

21:31 clojurebot: DENIED

21:33 rata_: I'm reading here http://clojure.org/Namespaces

21:33 ,(resolve a.b)

21:33 clojurebot: java.lang.ClassNotFoundException: a.b

21:34 rata_: ,(create-ns a.b)

21:34 clojurebot: java.lang.ClassNotFoundException: a.b

21:34 rata_: ,(create-ns 'a.b)

21:34 clojurebot: #<Namespace a.b>

21:34 rata_: haaa

21:34 ,(resolve 'a.b)

21:34 clojurebot: java.lang.ClassNotFoundException: a.b

21:34 gfrlog: clojurebot probably resets state every time

21:35 rata_: yes... just checking if the absence of the quote was significant before

21:35 gfrlog: try (create-ns 'your.ns)

21:36 gfrlog: okay

21:39 rata_: still get the classNotFoundException

21:39 yes, am quoting the ns name in create-ns

21:40 rata_: and you get the exception at the create-ns line or at the other line?

21:40 gfrlog: the other line

21:40 after create-ns

21:43 rata_: mmmm strange... I don't get that

21:43 (do (create-ns 'b.c) (b.c/a)) works for me

21:43 *compiles for me

21:43 gfrlog: maybe slime is "ruby mode"

21:44 rata_: hahaha could be

21:44 gfrlog: clojure: everything is dynamic at runtime, unless you do anything the normal way

21:46 rata_: load-string isn't at all normal I think

21:46 gfrlog: nope

21:46 but calling functions using symbols literals is

21:47 rata_: gfrlog: putting (create-ns a.b) (a.b/c) in a file and then executing that from the command line gives me a java.lang.Exception, not the ClassNotFoundException

21:47 the problem here is load-string

21:47 gfrlog: but the error happens before I ever use load-string

21:49 rata_: what?? then why are you calling something you haven't loaded yet?

21:50 gfrlog: the code doesn't get executed until the lib is loaded

21:50 but the code offends the compiler before the lib is loaded

21:52 (defmacro lenient-compiler [& forms] `(eval (do ~@forms)))

21:52 whoops

21:52 (defmacro lenient-compiler [& forms] `(eval '(do ~@forms)))

21:52 there we go

21:52 rata_: and did you put the create-ns thing before the offending code?

21:52 gfrlog: yes I did

21:52 you can imagine why it wouldn't make a difference:

21:53 the compiler doesn't execute create-ns

21:53 so it doesn't know whether or not it will actually result in the relevant namespace being created

21:53 all it knows is it still hasn't heard of that namespace

21:54 rata_: mmmm but for some reason when I execute (create-ns 'a.b) (a.b/c) it doesn't say anymore ClassNotFound

21:55 gfrlog: what context are you executing them in?

21:55 rata_: did you put it at the beginning of the file, after the ns macro?

21:55 gfrlog: no, just before the relevant statement

21:55 rata_: that's the whole file (create-ns 'a.b) (a.b/c)

21:55 gfrlog: does the second line in isolation still throw an error?

21:55 rata_: vim asdf.clj, put that, then execute

21:55 gfrlog: how do I "execute" it?

21:56 should I still call it asdf.clj if I use a dvorak keyboard?

21:56 rata_: java -cp clojure.jar clojure.main asdf.clj

21:57 gfrlog: yes, asdf is a beautiful combination of letters =P

21:57 when I put the second line alone it gives a ClassNotFoundException

21:57 gfrlog: lesse

21:57 lesee

21:57 let's see

21:58 so I get "no such var" -- which is what you get too?

22:00 rata_: yes

22:00 gfrlog: clojure is weird.

22:02 clojurebot: were you developed in a hammock?

22:02 clojurebot: Pardon?

22:10 rata_: gfrlog: well... a little step, but too little I think

22:10 gfrlog: what step?

22:11 rata_: to get a "no such var" instead of a ClassNotFound

22:11 gfrlog: well presumably the "no such var" is a runtime error rather than compile time

22:11 so in my context it wouldn't get thrown, since by runtime the var actually would exist

22:11 rata_: then try it

22:11 gfrlog: well I did and it doesn't compile

22:11 that's the whole weird thing about it

22:12 rata_: =(

22:12 yes weird

22:12 gfrlog: try executing your file with a (ns) at the top

22:12 for a different ns

22:12 rata_: ok

22:13 no such var

22:14 gfrlog: then add (load-string "(ns a.b) (defn c [] nil)") on the second line

22:24 rata_: gfrlog: works fine =)

22:24 gfrlog: clojure-version?

22:24 wait that shouldn't matter

22:24 rata_: 1.2

22:24 gfrlog: me too

22:25 rata_: but it works without create-ns too

22:25 gfrlog: ah

22:25 so we're all confused now

22:26 I think clojure probably has about 7 different ways it can execute your code

22:27 rata_: no... the thing is when you load-string, the namespace becomes available

22:27 and the var too

22:27 gfrlog: oooh I know

22:27 put both the load-string and the (a.b/c) in separate functions

22:28 then after they've both been defined, call them in order

22:28 rata_: for example (ns d) (load-string "(ns a.b) (declare c)") (defn e [] (a.b/c)) (load-string "(ns a.b) (defn c [] nil)") (e)

22:28 works

22:29 gfrlog: what about without the first load-string?

22:30 rata_: it doesn't compile... that load-string is required

22:32 gfrlog: that's strange

22:33 I guess the statements are executed in some sense

22:33 rata_: yeah

22:33 gfrlog: if you delayed execution of the load-string statement until after (defn e...) had been processed, it probably wouldn't work

22:34 anyhow, I gotta drop out for the night

22:34 thx for the sleuthin

22:34 rata_: ok

22:34 good night

22:53 mreynolds: More newbism : I'm trying to create a configuration file for my app, but I like the idea of having it be code (a la, most of the time it's convention, but if I need to, I can write an anonymous function). I've looked at leiningen's implementation and it seems... hard due to the limitations of load-file. Is there a better/simpler way of doing this? I'm about to start down the road of building a DSL, but that seems complex as wel

22:54 brehaut: the simplest way is just to have a settings namespace

22:55 if it doesnt need to be reloaded while the program is running its by far the easiest

22:55 mreynolds: brehaut: It doesn't. Can you give me more details for that? Is that just a matter of me including a namespace that is defined separately?

22:56 brehaut: yeah its just like any other clojure file in your project

22:56 i have as myproject.settings

22:56 and i def the settings to be clojure structures

22:56 mreynolds: brehaut: Ahh, heh. I've yet to actually use more than one ns (still learning). I'll dork around with that. Thanks!

23:34 chouser: wow, lazy-test's failure reports are *so much nicer* than clojure.test's.

23:35 sexpbot: tell stuartsierra

Logging service provided by n01se.net