2011-05-22
| 00: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? |
| 00:58 | dsantiago | 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. |
| 00:58 | dsantiago | Might be doing something stupid here. |
| 01: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 |
| 01:08 | symbole | desertman_: I've never used that library, but I suspect you need the actual driver in the classpath. |
| 01:09 | desertman_ | ok |
| 01:11 | symbole | desertman_: http://clojars.org/mysql/mysql-connector-java |
| 01:14 | desertman_ | symbole : cool |
| 01:15 | desertman_ | thanks |
| 01:15 | symbole | Np. |
| 02:08 | seancorfield | desertman_: if you're using leiningen, add this to your project dependencies: [mysql/mysql-connector-java "5.1.6"] |
| 02:08 | seancorfield | yeah, what symbole said :) |
| 02:09 | seancorfield | (dangers of catching up on irc late at night) |
| 02: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. |
| 02:26 | zakwilson | Oh, I see. I should be using or, not sql-or. |
| 06:48 | robonobo | is slurp lazy? |
| 06:48 | robonobo | 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 | TimMc | a_robbins: Try having a :main |
| 10:48 | a_robbins | TimMc: What would I put in it? |
| 10:49 | a_robbins | (in-ns 'namespace) ? |
| 10:49 | TimMc | https://github.com/timmc/CS4300-HW3/blob/master/project.clj |
| 10:49 | TimMc | So, in project.clj, :main mynamespace |
| 10:50 | TimMc | 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 | a_robbins | I guess :repl-init is for other stuff that you'd like to load, iff you are on the repl |
| 10:52 | a_robbins | 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 | thorwil | 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 | technomancy | there's room for some subtlety to be added in for sure |
| 11:31 | technomancy | plus it should tell you what it's bootstrapping; right now it's only slime and slime-repl |
| 11:33 | technomancy | a_robbins: actually that's a bug; repl-init is supposed to set the initial ns |
| 11:33 | technomancy | 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 | thorwil | "exited abnormally with code 1" |
| 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: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 | robonobo | and a helper-function that sets x to some value |
| 11:44 | robonobo | (defn foo-handy [& {:keys [y z]}] (foo x :y y :z z)) |
| 11:44 | robonobo | 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 | technomancy | 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 | technomancy | 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 | robonobo | 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 | a_robbins | 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 | a_robbins | 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 | robonobo | thanks guys |
| 12:00 | thorwil | technomancy: indeed: http://paste.pocoo.org/show/393172/ |
| 12:01 | thorwil | 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 | Vinzent | 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 | thorwil | 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 | thorwil | or wrap it in your own macro, just for assembling that path |
| 12:19 | thorwil | 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 | Vinzent | no_mind, then you should pass java.io.File |
| 12:30 | Vinzent | (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 | thorwil | i got rid of the lein swank plugin and rolled back my entire .emacs and .emacs.d |
| 14:35 | thorwil | and still get the same error |
| 14:36 | thorwil | java.lang.NullPointerException (init_repl.clj:0) |
| 14:36 | thorwil | http://paste.pocoo.org/show/393173/ |
| 14:51 | thorwil | 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 | raek | 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 | thorwil | 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 | amalloy | 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 | technomancy | I dimly recall the -snapshot package having lost its maintainer and being stuck in the past |
| 16:47 | technomancy | you can use it for its build-deps though |
| 16:48 | duncanm | amalloy: yeah, it's no longer up to date |
| 16:48 | duncanm | 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 | Cozey | 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 | technomancy | 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 | Cozey | or should one use (extend.. ) |
| 17:31 | Cozey | but then - this only extends one type, and not the whole hierarchy |
| 17:31 | Cozey | 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 | Cozey | 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 | dnolen | Cozey: yes. |
| 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 | Cozey | I'd love to see an example |
| 17:49 | dnolen | Cozey: allows adding custom dispatch for nil value. |
| 17:49 | dnolen | quite useful. |
| 17:50 | Cozey | but how do I extend a set of records this way? |
| 17:52 | Cozey | 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 | Cozey | 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 | Cozey | 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 | Cozey | 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 | dnolen | ,(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 | Cozey | 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 | amalloy | 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 | no_mind | storing config in clojure files is not an option when your app is going tobe installed and maintained by sys admins, |
| 21:34 | no_mind | 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 | amalloy | 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 | amalloy | 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 | wolfjb | usually, I'd say while ((count = in.read(...)) != -1) |
| 23:28 | wolfjb | but I would need to modify count in that case each time through the loop |
| 23:29 | wolfjb | 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 | amalloy | eg, (loop [] (let [count (...)] (when-not (= count -1) ...))) |
| 23:30 | wolfjb | ah |
| 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 | wolfjb | 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 | wolfjb | 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 | wolfjb | missed it then, I'll have to go find it |
| 23:37 | wolfjb | 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 | amalloy | 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 | amalloy | should probably look up how to use loop/recur |
| 23:43 | wolfjb | :-) |
| 23:43 | wolfjb | thanks, I'll look |
| 23:43 | amalloy | the general structure is (loop [loop-var init-value] (recur next-value)) |
| 23:47 | amalloy | 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 | ataggart | 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 | wolfjb | much cleaner than what I was trying |
| 23:50 | wolfjb | -- 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 | amalloy | and yeah, it looks like it should work |
| 23:51 | wolfjb | ah |
| 23:51 | wolfjb | you'd think I hadn't read a thing, but really I have! I promise! |
| 23:51 | wolfjb | :-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 | ataggart | 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) |