#clojure log - May 22 2011

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

0:57 dsantiago: Is there any way to use deftest to define a test, and then alter the metadata on the test function so that when a fixture you specify is run, it can access that metadata from the function passed in?

0:58 I can't seem to make it work using alter-meta! on the value in the test's var, or vary-meta on the symbol passed to deftest.

0:58 Might be doing something stupid here.

1:05 desertman_: hi, i am trying to use the sql library , i have mysql running on port 3306 , however i get No suitable driver found error , https://gist.github.com/985192

1:08 symbole: desertman_: I've never used that library, but I suspect you need the actual driver in the classpath.

1:09 desertman_: ok

1:11 symbole: desertman_: http://clojars.org/mysql/mysql-connector-java

1:14 desertman_: symbole : cool

1:15 thanks

1:15 symbole: Np.

2:08 seancorfield: desertman_: if you're using leiningen, add this to your project dependencies: [mysql/mysql-connector-java "5.1.6"]

2:08 yeah, what symbole said :)

2:09 (dangers of catching up on irc late at night)

2:23 zakwilson: Using ClojureQL, I want to do something like (select (table db :items) (apply sql-or (map (partial like :longdesc) ["foo" "bar"]))) and get sql like "select * from items where longdesc like 'foo' or longdesc like 'bar'", but I'm not getting anything of the sort.

2:26 Oh, I see. I should be using or, not sql-or.

6:48 robonobo: is slurp lazy?

6:48 or do i have to use slurp* from duck-streams for that?

10:36 a_robbins: Trying to setup lein so that 'lein repl' will automatically load and then activate a given namespace. :repl-init will load all the code from my file, but it doesn't switch my active namespace to that file, so I still need to call '(in-ns namespace-name) once I start. Any ideas?

10:47 TimMc: a_robbins: Let me check one of my projects...

10:48 a_robbins: Try having a :main

10:48 a_robbins: TimMc: What would I put in it?

10:49 (in-ns 'namespace) ?

10:49 TimMc: https://github.com/timmc/CS4300-HW3/blob/master/project.clj

10:49 So, in project.clj, :main mynamespace

10:50 I think it's intended for when you want a runnable JAR, but it definitely does what you want as well.

10:51 a_robbins: Yeah, that does do what I need. I also don't need :repl-init when I am using it

10:51 I guess :repl-init is for other stuff that you'd like to load, iff you are on the repl

10:52 TimMc: thanks!

10:54 TimMc: np

10:58 a_robbins: TimMc: So, after messing with it a little more, I guess I see a use case for :repl-init. I'm working on an appengine-magic project, so any time I start the repl I want 1)To load my core namespace, 2) to activate it and 3) to start the dev server. :main handles 1 and 2, but :repl-init can be pointed to a script that makes 3 happen. That way it'll only start if I'm at the repl, and not up on app engine

10:59 TimMc: Yeah, that sounds reasonable. I haven't used :repl-init for any projects so far.

11:18 thorwil: technomancy: hi! if it is normal that "lein plugin install swank-clojure 1.3.1" seems to hang for minutes until it finally prints something, then please consider to add a warning about that

11:21 technomancy: btw, what's not clear to me is the interplay or lack thereof with an already installed slime and paredit

11:22 a_robbins: thorwil: I think maven is down right now. That seems to be hanging a lot of lein commands

11:24 thorwil: oh, i would have expected an all or nothing, but "lein plugin install swank-clojure 1.3.1" took like 10 minutes to complete here. well, glad it worked, after all :)

11:29 a_robbins: thorwil: Yeah, maybe the server is responding to requests very, very slowly? http://repo1.maven.org/maven2/

11:31 technomancy: thorwil: yeah, stuff in jack-in completely overrides anything that's already there right now

11:31 there's room for some subtlety to be added in for sure

11:31 plus it should tell you what it's bootstrapping; right now it's only slime and slime-repl

11:33 a_robbins: actually that's a bug; repl-init is supposed to set the initial ns

11:33 it's just that I never use the repl task, so I did't notice

11:33 thorwil: installing clojure-mode via elpa led to a complaint about a paredit reference

11:34 a_robbins: technomancy: oh, good to know. Also, is there any easy way to switch leiningen to use the uk maven mirror for now? I'm hoping for some kind of global maven-url setting.

11:34 thorwil: clojure-jack-in briefly tells me that it exited with abnormal status

11:35 "exited abnormally with code 1"

11:36 * thorwil thinks error messages shouldn't vanish like that

11:37 a_robbins: technomancy: or, instead of giving maven a new url, dropping it from the lookup list for a little while. Many of my lein commands just hang at '[INFO] artifact org.clojure:clojure: checking for updates from central'

11:38 * thorwil remembers there's a *Messages* buffer

11:39 robonobo: is there a way to pass all :keys from a function to another function?

11:42 thorwil: robonobo: what do you mean with :keys from a function?

11:43 robonobo: when you have a general function (defn foo [x & {:keys [y z]}] ...)

11:43 and a helper-function that sets x to some value

11:44 (defn foo-handy [& {:keys [y z]}] (foo x :y y :z z))

11:44 is there a way to do that shorter?

11:45 technomancy: thorwil: there's also a bug where it'll get confused if there are multiple versions of swank in ~/.lein/plugins

11:45 possibly fixed in clojure-mode 1.9.1, but it's something to look for

11:46 thorwil: technomancy: swank-clojure-1.3.1.jar is the only content of ~/.lein/plugins here

11:47 technomancy: a_robbins: you can try :omit-default-repositories true and then add in :repositories {"mvn-uk" "http:[...]"} I think

11:47 haven't tried it myself

11:47 thorwil: robonobo: i'm not sure what you are trying to do, but have you considered using partial?

11:47 robonobo: thorwil: i'll look into that

11:47 thanks

11:48 technomancy: thorwil: hm; hard to say what's going on. you might get more detailed output from regular lein swank

11:48 a_robbins: robonobo: maybe you should do the destructuring inside the helper function instead of in the outer function?

11:49 robonobo: If you are pulling it apart to get the keys, and then wanting to put the keys back together to pass them, maybe they don't need to be pulled apart?

11:50 robonobo: wait, can i just do (defn foo-hany [& opts] (apply foo x-default opts))?

11:50 technomancy: huh; the CLU language introduced iterators. that must be why they named the villain in Tron Legacy after it.

11:52 a_robbins: robonobo: I think this would do what you want: (defn foo-hany [& opts] (apply foo (merge x-default opts)))

11:52 robonobo: actually, I think you could drop the apply

11:53 robonobo: why not just (apply foo x-default opts) ?

11:55 Vinzent: (apply foo x-default opts) is ok, you can also (def foo-helper (partial foo x-default))

11:55 a_robbins: robonobo: It depends on how foo works I guess. My version used a hashmap to track all the different options, which would be destructured inside foo.

11:57 robonobo: ok, it works now

11:57 thanks guys

12:00 thorwil: technomancy: indeed: http://paste.pocoo.org/show/393172/

12:01 technomancy: the referenced file: http://paste.pocoo.org/show/393173/

12:05 technomancy: thorwil: yeah, gotta make that more exposed from emacs.

12:06 Vinzent: in enlive, I had some troubles when i tried to deftemplate\defsnippet with filename from the fn (e.g. (deftemplate foo (path "file.html") ...)): snippets was always returning empty seq (like no metched segments found), but no NullPointerException was thrown (like when file not found on cp)

12:07 Have anyone encountered similar problems?

12:07 thorwil: technomancy: any idea what the problem at hand is? could it be an appengine-magic swank 1.3.1 incompatibility?

12:10 Vinzent: where does the (path) from come from? use just the path in quotes, with the templates in resources

12:15 Vinzent: thorwil, (defn path [filename] (str "long/path/to/templates/dir" filename)) just for shorteness

12:16 thorwil: Vinzent: deftemplate is a macro and you would have to use eval, or something

12:18 or wrap it in your own macro, just for assembling that path

12:19 then again, I would expect a NullPointerException if that is the problem, so maybe i'm talking bs

12:22 Vinzent: thorwil, lol, it's much easier: by distraction, I forget to add filename to the str form

12:23 thorwil: heh

12:25 no_mind: anyone used clojure.contrib.find-namepspaces ? I cannot figure out the input params for find-namespaces-in-dir ? If I pass a string as dir name, it says it needs java.io.File

12:26 Vinzent: so i've passed path to directory to the deftemplate; funny that it was working and returns something like "<html><body>layout.html\npost.html\n etc :)

12:29 no_mind, then you should pass java.io.File

12:30 (find-namespaces-in-dir (java.io.File. "src")) works fine for me

12:31 no_mind: I get an error ava.lang.ClassCastException: java.lang.Class cannot be cast to clojure.lang.IFn

12:31 raek: no_mind: sounds you are missing the last dot... :)

12:31 Vinzent: no_mind, note dot in the end of the class name

12:31 no_mind: k

12:57 Vinzent: With appengine-magic I have to recompile whole program after changes made; why? I'm passing var to the def-appengine-app

14:34 thorwil: awesome. so i had a working setup, but wanted to try http://technomancy.us/149 to have something repeatable, a way to recommend to others. somehow doesn't work with my appengine-magic project.

14:34 i got rid of the lein swank plugin and rolled back my entire .emacs and .emacs.d

14:35 and still get the same error

14:36 java.lang.NullPointerException (init_repl.clj:0)

14:36 http://paste.pocoo.org/show/393173/

14:51 if i remove the init-script from project.clj to do things manually, (ae/serve tlog-app) leads to "java.lang.NullPointerException (NO_SOURCE_FILE:0)"

15:04 raek: thorwil: can you post the complete stacktrace?

15:04 thorwil: raek: java.lang.NullPointerException (NO_SOURCE_FILE:0) is all it says now

15:05 raek: in the repl?

15:05 thorwil: yes

15:05 raek: try (.printStackTrace *e)

15:07 thorwil: http://paste.pocoo.org/show/393270/

15:08 zakwilson: So I dove head first in to ClojureQL last night, and my first impression is that it is amazing and wonderful. All query languages should be like that.

15:11 raek: thorwil: no old files in classes/ lying around or something?

15:11 the NPE from the java.io.File constructor seems suspicious

15:12 thorwil: raek: removing everything in classes is the solution. thank you!

15:13 now ofcourse i have to wonder if the new setup would have worked after clearing classes, too :/

16:17 polypus: ~ping

16:17 clojurebot: PONG!

16:27 duncanm: technomancy: how did you install emacs24 on your ubuntu laptop?

16:41 amalloy: duncanm: sudo apt-get install emacs-snapshot probably works, and building it from source isn't that hard either

16:42 do a little research, though; i'm not 100% sure snapshot is 24

16:46 technomancy: duncanm: I built from the github mirror. pretty easy to do.

16:47 I dimly recall the -snapshot package having lost its maintainer and being stuck in the past

16:47 you can use it for its build-deps though

16:48 duncanm: amalloy: yeah, it's no longer up to date

16:48 technomancy: thanks

17:02 Cozey: Hello. I'm not sure if i got it right: is it possible to make a class hierarchy with defrecord? Or otherwise how do I provide just one implementation for a protocol P, implemented by Parent class and its Descendants?

17:03 should I use a multimethod for this? It seemed to me that defrecord is not to be used with multimethods... is it?

17:13 technomancy: how many clojure libraries are there with native components?

17:13 I only know of three: penumbra, serial-port, and the arduino one

17:25 dnolen: technomancy: overtone.

17:28 amalloy: Cozey: building a class hierarchy feels like the wrong way to approach the problem. if you only want one implementation, just define it as a plain function that takes a Parent object as its first arg

17:30 Cozey: ok. on the other hand - is it a good practice to use protocols with multimethods?

17:30 or should one use (extend.. )

17:31 but then - this only extends one type, and not the whole hierarchy

17:31 say I'd like to have a method (save-to-db ) for a hierarchy of records like Person, Order, etc.

17:31 technomancy: dnolen: thanks

17:31 Cozey: what would be the Clojure approach to this?

17:32 I'm a little lost in the 'function only multimethod' and protocols/record/types new speedy paradigms

17:38 dnolen: Cozey: you can compose default implementations w/ function maps and extend-type.

17:38 Cozey: extend-type applies to records, not just types

17:38 dnolen: Cozey: however for I/O bound stuff like saving to a db, multimethods are fast enough.

17:39 Cozey: yes.

17:41 * technomancy has never run into a situation where multimethods are a bottleneck

17:42 Cozey: thanks; so this means a class generated by defrecord will always get an implementation from a protocol it implements or from it's definition; inheritance between records is not used to implement polymorphism? And the way to write an implementation of a protocol is to extend on a specific type (how to extend many types implementing one protocol?)

17:43 dnolen: Cozey: Clojure adopts the stance "inheritance considered harmful"

17:46 Cozey: ok. so I use multimethods - and this way can give a different implementation for different part of some hierarchy - is there a way to achieve the same using the 'optimized' methods defined with defrecord/deftype?

17:48 dnolen: Cozey: extend-type can take a map filled /w fns, these are composable - they are just maps.

17:48 Cozey: what's the semantics of (extend nil Proto ... ) - with nil instead of type ?

17:49 I'd love to see an example

17:49 dnolen: Cozey: allows adding custom dispatch for nil value.

17:49 quite useful.

17:50 Cozey: but how do I extend a set of records this way?

17:52 Say I have a (defprotocol Sleep (sleep [this] ... )) and then I have (defrecord Animal) (defrecord Person), (defrecord Vampire) - how do I specify an implementation of sleep, which would work with animals, persons and vampires?

17:52 or should I just use a normal method hinted with ^Sleep (I could do that?)

18:25 dnolen: Cozey: 2 ways to accomplish the same thing, https://gist.github.com/985965, https://gist.github.com/985967. I recommend getting comfortable w/ the later first.

18:28 Cozey: Ah! Thank You so much

18:28 just one more question - how about a defmulti on a protocol ?

18:36 dnolen: Cozey: I think initially it's wise to consider multimethods and deftype/record/protocols as two completely distinct systems. It may seem like they overlap in functionality, but certain types of performant programs are simply not possible w/ multimethods.

18:36 Cozey: ok - in which case the 'sleep-shared' pattern is to be used

18:37 enough of dissecting this problem! Thank You for the examples on gist :-)

18:40 dnolen: Cozey: No in the highest perf situation sleep-shared is also a not an insignificant perf hit. You simply just have to reimplement the function for each type (or macro it away). This is a good thing, inheritance just causes too many bigger problems compared to this inconvenience.

18:42 Cozey: ok, btw: is there a predicate to test if a record implements a protocol?

18:42 dnolen: Cozey: I do have some hope that invokeDynamic can allow for objects to be cleanly composed via delegation, but this a ways off.

18:43 ,(doc satisfies?)

18:43 clojurebot: "([protocol x]); Returns true if x satisfies the protocol"

18:43 Cozey: It says that defprotocol creates an interface as well - but the Foo protocol is actually some structure

18:43 cool

21:16 no_mind: is there a library for parsing config files in clojure ?

21:18 amalloy: no_mind: well, clojure is such a library, if you store your config files as clojure data structures

21:18 if you have a specific config format in mind, now's the time to say so :)

21:19 no_mind: yes, ini files

21:19 storing config in clojure files is not an option when your app is going tobe installed and maintained by sys admins,

21:34 using find-namespaces/find-namespaces-in-dir I can find out which namespaces exists in a given dir. But how do I load selective namespaces from the result of find-namespaces-in-dir ?

22:02 mefesto: no_mind: for parsing ini files you could use [commons-configuration/commons-configuration "1.6"] http://commons.apache.org/configuration/

22:39 desertmen: hi, i'm learning leiningen, if i created a project , whats the best way to run and test it. One tutorial has you compile it into a jar and run it from java everytime. Is that the best way, or can you run it from leiningen?

22:42 offby1: I'd do "lein --help" and see if it says anything about testing

22:45 amalloy: desertmen: it wouldn't be a bad idea to define actual *tests*, which you can run easily with "lein test" without requiring interaction

22:45 but you can also define a :main namespace in project.clj, which i believe is what lein run calls

22:46 desertmen: ok thanks

22:56 no_mind: Ok someone needs to tell me how to do this. I have a directory with bunch of .clj files. I want to selectively load the namespaces from those files. How do I do this ?

23:24 desertmen: hi, i (noob) am having some problem getting this sql connector example going -> https://gist.github.com/986166

23:26 alandipert: desertmen: looks like you need to add clojure.contrib.sql to your dependencies in project.clj

23:26 wolfjb: how do I alter the value of a local variable?

23:26 amalloy: alandipert: just clojure.contrib

23:27 wolfjb: don't

23:27 wolfjb: ok, then how do I read a file in a loop?

23:27 desertmen: ok, thanks

23:27 wolfjb: I want to read n bytes until there aren't any more

23:28 usually, I'd say while ((count = in.read(...)) != -1)

23:28 but I would need to modify count in that case each time through the loop

23:29 if I shouldn't modify a local variable, is there a better way to read a file?

23:29 amalloy: wolfjb: you don't need to modify it at all. a straightforward translation would be to create a new count variable at each iteration of your imperative loop

23:30 eg, (loop [] (let [count (...)] (when-not (= count -1) ...)))

23:30 wolfjb: ah

23:30 * wolfjb is still learning!

23:30 wolfjb: wonderful

23:31 amalloy: wolfjb: a nicer solution would depend on what you're actually doing with the bytes you read

23:31 wolfjb: so, is loop like the common lisp loop then?

23:31 amalloy: no, not at all

23:31 wolfjb: I'm zipping a file

23:31 this is "library" code in a larger project

23:32 amalloy: loop is just a nicer syntax around defining an anonymous function that calls itself recursively and "looks" more imperative

23:32 wolfjb: I'm using java.util.zip.ZipOutputStream and calling write(bytes, 0, count)

23:34 I'm rewriting some old common lisp code I have as an exercise to learn clojure

23:34 amalloy: okay. if you just want side effects based on the current chunk of bytes, loop/recur is probably a fine solution

23:35 wolfjb: wish there was a book to read, the 'Clojure In Action' I guess is still forth-coming

23:35 amalloy: wolfjb: there are several clojure books

23:35 wolfjb: ?

23:36 amalloy: the Joy of Clojure comes highly recommended and is also recent, which matters for a young language

23:36 wolfjb: must have missed them MEAP only had a couple and they look like they are still being written

23:36 amalloy: nah, JoC hit shelves a month or two ago

23:36 wolfjb: ah, cool!

23:37 missed it then, I'll have to go find it

23:37 wow, april 4! that is pretty recent

23:38 amalloy: (let [buf (byte-array 1024)] (loop [] (when-not (= -1 (.read in-stream buf 1024))) (.write out buf) (recur)))) ; a rough sketch

23:38 i guess not a very good sketch, since it doesn't pass a size to .write

23:41 ataggart: ,(doc clojure.java.io/copy)

23:41 clojurebot: "([input output & opts]); Copies input to output. Returns nil or throws IOException. Input may be an InputStream, Reader, File, byte[], or String. Output may be an OutputStream, Writer, or File. Options are key/value pairs and may be one of :buffer-size buffer size to use, default is 1024. :encoding encoding to use if converting between byte and char streams. Does not close any streams except thos...

23:42 amalloy: (inc ataggart)

23:42 sexpbot: ⟹ 1

23:42 wolfjb: (loop [count (.read in buf 1024) (when-not (= -1 count) (.write out buf count)(recur) ?

23:42 amalloy: nnnooooo, you've gotten the syntax there wrong in several ways

23:43 should probably look up how to use loop/recur

23:43 wolfjb: :-)

23:43 thanks, I'll look

23:43 amalloy: the general structure is (loop [loop-var init-value] (recur next-value))

23:47 ataggart: fwiw, sexpbot gists instead of truncating: ##(doc clojure.java.io.copy)

23:47 sexpbot: java.lang.Exception: Unable to resolve var: clojure.java.io.copy in this context

23:48 wolfjb: hmm... that copy thing looks cool

23:48 amalloy: &(doc clojure.java.io/copy)

23:48 sexpbot: ⟹ "([input output & opts]); Copies input to output. Returns nil or throws IOException. Input may be an InputStream, Reader, File, byte[], or String. Output may be an OutputStream, Writer, or File. Options are key/value pairs and may be one of :buffer-size buffer size t... http://gist.github.com/986197

23:48 ataggart: ##(doc clojure.java.io/copy)

23:48 nice

23:48 sexpbot: ⟹ "([input output & opts]); Copies input to output. Returns nil or throws IOException. Input may be an InputStream, Reader, File, byte[], or String. Output may be an OutputStream, Writer, or File. Options are key/value pairs and may be one of :buffer-size buffer size t... http://gist.github.com/986198

23:49 wolfjb: (let [in (new BufferedInputStream (new FileInputStream fileName) 1024)] (clojure.java.io/copy in out) (.close in))

23:49 much cleaner than what I was trying

23:50 -- assuming that would work and I didn't goof it up :-)

23:50 amalloy: wolfjb: (Foo. x) is a more usual way to write (new Foo x)

23:51 and yeah, it looks like it should work

23:51 wolfjb: ah

23:51 you'd think I hadn't read a thing, but really I have! I promise!

23:51 :-D

23:51 ataggart: and you can drop all that and replace it with clojure.java.io/file

23:52 amalloy: &(doc clojure.java.io/file)

23:52 sexpbot: ⟹ "([arg] [parent child] [parent child & more]); Returns a java.io.File, passing each arg to as-file. Multiple-arg versions treat the first argument as parent and subsequent args as children relative to the parent."

23:52 ataggart: gah, I mean input-stream

23:52 amalloy: &(doc clojure.java.io/input-stream)

23:52 sexpbot: ⟹ "([x & opts]); Attempts to coerce its argument into an open java.io.InputStream. Default implementations always return a java.io.BufferedInputStream. Default implementations are defined for OutputStream, File, URI, URL, Socket, byte array, and String arguments. If th... http://gist.github.com/986202

23:53 ataggart: e.g., (with-open [in (input-stream "foo.txt")] ...)

23:53 amalloy: or (doto (input-stream filename) (copy out) (.close))

23:53 ataggart: except manually handling the close is dumb

23:53 amalloy: ataggart: i should get to know clojure.java.io better

23:53 ataggart: :)

23:54 ya they did good work in there

23:55 amalloy: ataggart: yes, i like the with-open version better. but only a little, and i do like a chance to introduce doto

23:56 ataggart: the problem with the doto is what happens if an exception is thrown

23:56 amalloy: yes, all right. my version is horrible

23:56 ataggart: heh

23:56 amalloy: but it has doto!

23:56 ataggart: doto is mutation is bad

23:57 amalloy: *eyeroll* it's well-labeled and cleanly-written mutation

23:58 wolfjb: heh, I thought doto was a typo

23:58 ataggart: doto is lovely when having to deal with javaland, e.g., swing

23:59 amalloy: your with-open version does exactly as much mutating, but hides it. mind you, it does the mutating better than i did, but you can't really frown on mutation when recommending with-out

23:59 ataggart: though it's been about a decade since I wrote any swing

23:59 amalloy: wolfjb: ##(macroexpand '(doto (+ 1 3) println))

23:59 sexpbot: ⟹ (let* [G__14616 (+ 1 3)] (println G__14616) G__14616)

Logging service provided by n01se.net