#clojure log - Jun 18 2011

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

1:06 seancorfield__: raek: hey, did you see my response about the cyclic dependency? been kinda tied up today and not on IRC much...

2:47 cwmaguire: help

3:05 schasi: help?

3:05 clojurebot: http://www.khanacademy.org/

6:07 raek: seancorfield: yes, I saw it but was busy at the time. just re-read it from the logs now.

6:08 shtutgart: Hello, how can I get the length of the java array? Should I coerce it to seq?

6:09 raek: shtutgart: use alength

6:10 shtutgart: raek: of course! Thank you.

6:10 raek: if you call count on a seq, it will have to traverse the seq to count the elements. an array knows its size, so alength is constant time

6:12 tomoj: amalloy_: dude, thank you for implanting the urge to learn find in my brain

6:12 bsteuber: shtutgart: but if performance doesn't matter, just using count makes the function more flexible

6:12 as you can hand in all clojure seq types, too

6:14 shtutgart: bsteuber: perfomance isn't very important, but I'm writing java interfacing code, so I don't need support for the clojure types

6:14 bsteuber: shtutgart: ok makes sense :)

6:15 tomoj: count calls java.lang.reflect.Array/getLength

6:15 alength just does .length

6:15 constant factor difference on arrays

7:30 raek: any clojurians at dreamhack?

7:40 bsteuber: anyone got midje to work with clojure-1.3-alphas?

8:45 Moominpapa: Hi, I was taking a look at this article http://www.skuro.tk/2011/01/24/performance-boost-in-clojure-1-3/

8:46 I was wondering if using ^:static would do anything.

8:46 So I put it in between "defn" and tak.

8:47 It doesn't seem to make a blind bit a difference.

8:47 Am I doing something wrong, or is the unadorned one already performing the same optimization?

8:48 Better link to the function: https://raw.github.com/gist/788834/dd438ab2fbc2d1aff52eb1a380c5507caa6b7e2e/tak.clj

10:24 stirfoo: what would I use if I wanted a Java array of unsigned bytes [0, 255]? Seems as though byte-array uses signed bytes (or I'm doing something terribly wrong).

10:25 lucian: stirfoo: afaik, all java int-ish types are signed

10:26 there are some workarounds i believe

10:28 stirfoo: I could use shorts but it's for a core simulator, 8 bits would be much better

10:29 what's the range of char-array? (is there somewhere I can see what size these arrays actually hold?)

10:29 lucian: chars are unicode code points, i think

10:29 stirfoo: lucian: I was thinking the same from a bit of experimenting

10:30 lucian: so i think you're stuck with bytes, you can google for workarounds

10:30 stirfoo: ok, thanks lucian

11:08 sot: If I use a def form to bind a variable to the return value of a funtion, am I correct that the function will only ever be called once? My functionn return a zermq socket, and I do not want that code to be called more than once.

11:15 pdk: i don't see why binding a def stops the function from being called twice

11:16 maybe you should stick a precondition on the function that the value of the def you bound must be nil before it runs to prevent it from being run twice

11:17 adding pre/postconditions to a function looks like (defn x [args] {:pre [(condition-1) (condition-2)] :post [(postcondition-1) (postcondition-2)} (body ...))

11:19 sot: Thanks, have not see those :pre :post options before

11:21 stirfoo: there is defonce as well, not sure it that is applicable here

11:22 I like pre's and postees though, been using them quite a bit

11:24 pdk: basically

11:24 you write the pre/postconditions into vectors

11:25 say stuff like [(< 1 arg1) (even? arg2)] etc

11:25 in the precondition you can use argument names directly

11:25 in the postcondition you can use % to refer to the function's return value since postconditions kick in only after the function is done

11:26 in both cases it logical and's everything in the vector for the pre/postconditions

11:26 so all of the preconditions have to be true before it starts and all of the postconditions have to be true afterward or it throws an exception

11:26 sot: Perfect, many thanks

11:47 fliebel: Anyone knows NIO? I'm trying to convert this to Clojure, but it fails: http://www.javaworld.com/javaworld/jw-04-2003/jw-0411-select.html?page=4#resources When I call accept on the server socket, it gives me java.nio.channels.IllegalBlockingModeException

11:58 the-kenny: Which is the "beste" Clojure testing framework?

11:59 s/beste/best/

11:59 sexpbot: <the> Which is the "best" Clojure testing framework?

12:11 gfrlog: the-kenny: which is the "best" clojure data structure?

12:11 fliebel: (inc gfrlog)

12:11 sexpbot: ⟹ 2

12:11 the-kenny: This is surely the list :p ;)

12:11 fliebel: Nah, it's the finger tree.

12:11 gfrlog: lists of finger trees

12:12 the-kenny: if you want a real answer you'll have to be more specific about what you want to test :)

12:12 fliebel: the-kenny: But if you don't like choosing, clojure.test sounds like an easy choice :)

12:13 gfrlog: yeah. The worst thing that can happen is you'll get a better idea of what you want

12:13 the-kenny: gfrlog: That's the problem. I don't know what I want. I used lazytest for one project (mostly because of the autotest feature and because it generates nice reports), but one thing which drives me crazy is that 1.1.2 (Clojure 1.2.1 compatible) has swank-clojure as a dependency

12:14 I also like the (given ...) macro, but that'll be removed in future versions

12:14 deftest feels a bit raw compared to lazytest, but clojure-test-mode is definitely a plus

12:14 s/deftest/clojure.test/

12:14 sexpbot: <the> clojure.test feels a bit raw compared to lazytest, but clojure-test-mode is definitely a plus

12:15 lnostdal-laptop: is there some way to use lein only as a build/make type tool, so it doesn't download the same packages for each and every one of my new test projects but instead re-uses the common ones i already have stored locally here?

12:15 gfrlog: it is a bit raw. I normally end up making a macro or two to help

12:15 I thought lein/maven kept local copies around and used them when available...

12:16 the-kenny: gfrlog: It does

12:16 lnostdal-laptop: it copies the local copies

12:16 hm, i think

12:16 gfrlog: ah, you want to save disk space and not have all the duplicate jars?

12:16 lnostdal-laptop: well, i want to use git

12:16 gfrlog: eh? who doesn't use git?

12:17 you want your jars in the repo?

12:17 lnostdal-laptop: if i pull from some remote repo once i'll have to do that for each project

12:17 i don't want jars; i want source code and cached .class files .. maybe i just don't get this stuff

12:17 gfrlog: I don't think you normally want to version your .class files either

12:18 lnostdal-laptop: of course not

12:18 gfrlog: when you say "pull from some remote repo" are talking git-repo or maven-repo?

12:19 lnostdal-laptop: M-. .. ---> take me to the central code .. i fix some problem, and all projects should see the change

12:19 git

12:20 this feels so clunky .. sheesh

12:20 gfrlog: are you talking about when you have one lein project that uses another one?

12:21 lnostdal-laptop: yeah

12:21 gfrlog: ah hah

12:21 in that case lein has a "checkouts" feature

12:21 you create a "checkouts" directory in the root of a project that uses another project

12:21 (ignored by git)

12:21 and within "checkouts", you create symlinks to the root directory of the project you're using

12:23 lnostdal-laptop: is it possible to have a centralized place where lein looks for symlinks to local projects?

12:23 fliebel: lnostdal-laptop: Q: I want to hack two projects in parallel, but it's annoying to switch between them: https://github.com/technomancy/leiningen

12:24 gfrlog: lnostdal-laptop: well I suppose /checkouts could itself be a symlink...I don't know if that risks some kind of cyclic setup, but you can try it

12:24 lnostdal-laptop: ok, i'll try this .. thanks

12:25 gfrlog: yep

12:25 fliebel: Could anyone help me spot a bug in this NIO code? First file is my try at writing the second Java file in Clojure: https://gist.github.com/1033235

12:26 gfrlog: I didn't know you could have two files in one gist.

12:26 but now I do.

12:26 fliebel: what do you mean by bug? what's it do?

12:27 fliebel: gfrlog: Well, sit there and listen, echo stuff back, rot13 encoded. The clojure code has a comment on the line where it throws the error.

12:28 gfrlog: oh ha; didn't see the comment :)

12:28 looked for it though

12:30 okay I'm going to stop pretending I know enough about java networking to comprehend this

12:32 fliebel: gfrlog: Basically I'm just trying to replicate the Java stuff, so it's a matter of find the difference. I'm goin got go through it line by line another time.

12:34 lucian: fliebel: afaict getChannel blocks

12:35 lnostdal-laptop: lein can't use my already installed (and running) clojure? .. and load projects/dependencies within that?

12:35 fliebel: lucian: accept blocks as well, but the thing is that it should return instantaneously because NIO notified us it's ready.

12:35 * lucian doesn't really know NIO, just twisted

12:36 fliebel: lucian: Yea, same reactor pattern.

12:36 lnostdal-laptop: i thought the point of lisp is to work within lisp with an always up REPL .... *sigh*

12:36 why this lein stuff from the CLI ....

12:37 gfrlog: lnostdal-laptop: I think most people consider isolation to be a positive thing

12:39 lnostdal-laptop: i guess that's nice in some contexts .. need to think about this

12:40 tnbd: tnbd hi

12:40 gfrlog: tnbd: tnbd hi

12:40 lnostdal-laptop: oh, clojure is among the deps? .. what happens if one dep depends on one clojure version, and another dep depends on some other clojure version?

12:41 * gfrlog doesn't know what happens

12:41 tnbd: wrong command, please don't hurt me :)

12:42 gfrlog: lnostdal-laptop: you could run into that problem with any other dependency as well. That's why dependency management is complicated :)

12:43 lnostdal-laptop: true

12:43 lucian: gfrlog: except it's not! :)

12:44 lnostdal-laptop: which is why having checkouts in git is nice i guess .. if i apply local patches they won't be overwritten as i continue to follow upstream

12:44 * lucian is spoilt by apt, pip and friends

12:44 gfrlog: lucian: do go on

12:44 lucian: oh, and virtualenv

12:44 gfrlog: i can't even remember the last time i had trouble with dependencies

12:45 lnostdal-laptop: debian stable is easy because someone has already dealt with the dep problems for you; there's no magic there

12:45 gfrlog: lucian: I haven't had trouble, I just mean you can concoct complex situations

12:45 lucian: gfrlog: yes, but it's a solved problem. which i like

12:45 lnostdal-laptop: (same with ubuntu etc. etc.)

12:45 gfrlog: lucian: and the solution is?

12:45 lucian: gfrlog: lots of software to do it for us

12:45 gfrlog: to do what?

12:45 lnostdal-laptop: no, not software

12:46 lucian: gfrlog: dependency management

12:46 lnostdal-laptop: *sigH'

12:46 gfrlog: yes but how? what do you do when A -> B -> C.1 and A -> D -> C.2?

12:46 lucian: separate envs

12:46 gfrlog: the only solution I know of is to have your namespaces/packages versioned

12:47 lucian: "separate envs" is a solution within the jvm?

12:47 how does that work when there are global variables that C uses?

12:47 lucian: oh, i misread that

12:48 well, that's something you don't let happen

12:48 gfrlog: how do you prevent it?

12:48 lucian: your package manager will tell you

12:49 gfrlog: and then what do you do?

12:49 drop one of B or D?

12:49 lucian: yell at whoever did that :)

12:49 yes, the only sane solution

12:49 gfrlog: I think this is what I meant by "it's complex" :)

12:49 lucian: you said complicated

12:50 it is a fine distinction, but i think in this case pertinent

12:50 gfrlog: well then I will object to "it's a solved problem" as well :)

12:50 sounds to me like it's still a problem, you've just proved there isn't a solution

12:51 lucian: perhaps :)

12:51 gfrlog: or "decided" rather

12:51 when dependency conflicts can lead directly to "we can't do this project anymore", then I'd say that's worth calling a problem

12:51 lucian: i should've been more specific

12:52 preventing dependency conflicts from creating weird bugs is a solved problem

12:52 gfrlog: however I still don't know the answer to lnostdal's original question of what happens when you depend on two separate clojure versions

12:52 lucian: actually resolving conflicts, not entirely

12:52 gfrlog: not hard to find out though

12:55 I would think that kind of conflict would come up a lot in clojure development...I guess that suggests that lein silently makes decisions

12:55 since I've never seen it complain

12:57 fliebel: ... it seems I'm getting SelectionKey/OP_ACCEPT where I was expecting SelectionKey/OP_READ

13:02 yay! I wasn't clearing some piece of mutable state.

13:02 gfrlog: now you have a rot13 server?

13:03 fliebel: gfrlog: No, just a magic question mark printing machine :(

13:03 It's not so easy to turn a ByteBuffer into a string, it seems.

13:04 gfrlog: cannot be done by reading fewer than 4 javadoc pages

13:04 fliebel: But after I figure that out, I only have to port Twisted to conquer the world. :P

13:04 gfrlog: or, if you're doing it in Java/Eclipse, pressing random keys until it compiles

13:20 stirfoo: has anyone seen this brainf*ck compiler in Racket? http://hashcollision.org/brainfudge/

13:21 It's pretty neat what they're doing with the reader

13:22 The #lang line installs a reader, the bf code is then compiled into Racket proper by way of a few macros.

13:23 I've got the majority of it rewritten in clojure. It mapped over cleanly.

13:44 fliebel: Has anyone played with cljque recently? I want to see if I can use it, but it seems very much on the move.

13:44 ... and hasn't any examples or tests

13:45 Also, there was a discussion about asynchronous ring a while back, anyone knows what became of that?

14:36 Could anyone explain me a bit about vars, and how to change them? I'm still just guessing at the meaning of alter-var-root and set! and most of the time I get it wrong and Clojure bites me.

14:38 arohner: fliebel: a var is a box that contains a value

14:38 do you understand what I mean when I say "box"?

14:39 it's just an instance of a class that holds a reference

14:39 the var has one "root" value

14:39 then, each thread can override the value, on a thread-local basis, using binding

14:40 binding says "change the value of the var, in my thread only, during the score of the binding"

14:41 set! changes the thread-local value, but it's only allowed if you're already inside a binding

14:41 alter-var-root changes the root value that all threads see, but doesn't change their thread-local values, if any exist

14:42 fliebel: arohner: Ah! Why is it only allowed inside a binding?

14:42 arohner: I think because it makes things easier to reason about

14:43 once the binding leaves scope, the set gets undone as well

14:44 fliebel: Hm, okay. I guess I could use push-thread-bindings, if it's not private, or just stick with binding.

14:45 I'm dealing with some Java, and I want to figure out a way to give every thread its own instance of something.

14:47 I was thinking that tread-local bindings would be a nice way to construct the singleton counter-pattern.

15:22 zakwilson: Googling "clojure markdown" gets me half a dozen different ways to parse markdown in Clojure. Is there a generally preferred stable library?

15:57 ihodes: l

16:10 casper1: I'm having a bit of trouble understanding the append/insert-child methods of clojure.zip. I want to add a child to a leaf note basically. But this throws an exception. Any tips?

16:13 e.g. (zip/append-child (zip/next (zip/seq-zip '(1))) throws #<CompilerException java.lang.Exception: called children on a leaf node (NO_SOURCE_FILE:44)>

16:14 i can add it to the root but i want to add it below the 1 node

16:15 scgilardi: there's a function you need to provide that means "can have children" (whether or not it currently does) based on the error message, I'm guessing that function returned false for the node you're trying to add to. you'll need to arrange for it to return true.

16:16 casper1: hmm, i'm not sure how to do that

16:18 the zip/branch? fn returns false for the 1 node, but I don't how to get it to return true

16:20 scgilardi: the doc for clojure.zip/zipper (in zip.clj in the clojure source) has some info. yes, branch? is what you need. seq-zip's version of branch? is (seq?) and (seq? 1) is false.

16:25 casper1: Still not getting it i am afraid. Could you provide a tiny example of how to add a child node?

16:29 scgilardi: does this help? (I don't have a small example handy. branch? is written the way it is for seq because the corresponding make-node function relies on having a seq present for it to work.)

16:29 http://www.exampler.com/blog/2010/09/01/editing-trees-in-clojure-with-clojurezip/

16:31 (this also looks helpful: http://groups.google.com/group/clojure/browse_thread/thread/3291d54508cc0bbf)

16:32 casper1: I have been looking at that first one but it doesn't show how to actually insert a new child on a leaf note. Maybe i am just dense though and missing something obvious

16:33 the second one seems to do the opposite, which may help. I'll put on my thinking cap :)

16:34 scgilardi: clojure.contrib.struct-ed=> (clojure.zip/root (clojure.zip/insert-child

16:34 (clojure.zip/seq-zip (list 1)) 2))

16:34 (2 1)

16:34 (from the second)

16:56 jhickner: hello all. I'm trying to figure out how to serve a specific static (in compojure) from a wildcard path. For instance, any request to tiles/* should serve up tiles/tile.png. Most of the docs out there seem to be outdated. Any ideas?

16:56 static file that ids

17:04 gfrlog: ,:-D

17:04 clojurebot: :-D

17:05 jhickner: looks like this works, using ring.util.response/file-response: (GET "/tiles/*" [] (file-response "public/tiles/tile.png"))

19:07 davekong: I am trying to read a 120MB binary file of 32bit bytes into a vector (maybe array), is there a simple, efficient way to do this? I have this CL code for doing it: http://www.pastie.org/2089175

19:14 * gfrlog is not sure what a 32-bit byte is

19:15 gfrlog: davekong: you want to read 32-bit words?

19:15 as integers?

19:15 davekong: yea

19:16 gfrlog: I think we gotta do some java stuff

19:16 and probably things from clojure.java.io

19:19 okay. With clojure.java.io you can get an input stream with (input-stream (as-file "filename"))

19:20 then you'd want a helper function that reads a word from the input stream by calling (.read ...) 4 times and combining those together

19:20 (which depends on the endianness of your data)

19:21 then with that helper function you can use (loop) to build up a vector of words

19:24 davekong: alright, let me try to figure it out from here, thanks

19:24 gfrlog: np

21:29 tufflax: How do I write def-, a private def? I've been trying but I can't get it to work :p

21:30 gfrlog: tufflax: I don't think there's a shortcut for (def #^{:private true} my-thing ...)

21:30 pdk: defn- doesn't have def-/defmacro- equivalents

21:30 just attach metadata with :private true

21:30 gfrlog: in clojure 1.3 I think (def ^private my-thing ...) will work

21:30 tufflax: So, it's impossible to write it? :p

21:31 gfrlog: tufflax: you could makee your own with defmacro

21:31 tufflax: How? That's what I've been trying

21:31 gfrlog: (defmacro def- [& args] `(def #^{:private true} ~@args))

21:31 I think that could work

21:32 if it doesn't them something involving (with-meta) ...

21:32 tufflax: Isn't it just ^{:private true}? Instead of #^{...}?

21:33 gfrlog: I don't think so...

21:35 pdk: prob ^

21:35 scgilardi: http://clojure.org/reader

21:35 tufflax: hm both works but http://clojure.org/reader doesn't mention #^

21:35 scgilardi: (^ is the new syntax, #^ is the old, we may be in a transition period where both work)

21:36 tufflax: Anyway I tried (defmacro def- [& args] `(def #^{:private true} ~@args)), but it doesn't work

21:36 gfrlog: the cheatsheet calls ^ "Meta: ^form → (meta form)"

21:36 tufflax: okay let's see what with-meta does

21:36 ,(doc with-meta)

21:36 clojurebot: "([obj m]); Returns an object of the same type and value as obj, with map m as its metadata."

21:37 wonginator1221: Hi guys, I'm currently trying to learn clojure through project euler and I've created a function that returns #{1 2 5}. What is the #{ ... } a shorthand form of? Thanks.

21:37 scgilardi: clojure.contrib.def has some examples

21:37 gfrlog: wonginator1221: it's a set

21:37 a collection with no order or duplicates

21:38 ,(class #{1 2 5})

21:38 clojurebot: clojure.lang.PersistentHashSet

21:38 tufflax: but (def (with-meta a {...} 1)) doesn't work either if that's what you mean gfrlog

21:38 gfrlog: tufflax: I'm not quite sure what I mean. I'm looking up other metadata functions

21:38 tufflax: hehe

21:39 wonginator1221: gfrlog: Ah.. ok thanks. I'm also running into a problem where I have a recursive func that works fine for small values, but i'm guessing fills that stack on larger numbers. The stacktrace is too long for my terminal to capture. Any tips?

21:39 gfrlog: wonginator1221: for recursion check out (recur)

21:39 you generally can't do it directly like other languages

21:40 ...sorta

21:41 tufflax: maybe (defmacro def- [name thing] `(def ~name (with-meta ~thing {:private true})))

21:41 wonginator1221: gfrlog: i have some minor experience in scheme and i usually just called the function by name. Is recur the correct special form for recursion?

21:41 gfrlog: there's probably a better way to do that, because I think you'll end up losing the rest of tthe metadata that way

21:42 wonginator1221: yes, recur is used for tail-

21:42 recursion

21:42 if you're not doing tail-recursion, then you can use the name directly, but you're responsible for the stack size

21:42 wonginator1221: gfrlog: I am doing tail recursion so I guess I should look into recur.

21:42 gfrlog: the JVM does not optimize tail-calls, so that's why (recur) is used to make it explicit

21:43 wonginator1221: it's not hard, just use recur instead of the name of your function

21:43 wonginator1221: One last question. Is jline 1.0 terrible with the repl? My experience has been less than exhilarating. Is rlwrap the way to go?

21:44 gfrlog: wonginator1221: I think?

21:44 I use leiningen to launch the repl. I think it uses rlwrap.

21:44 tufflax: gfrlog I don't think that's right :p the metadata should be on the symbol...

21:44 gfrlog: tufflax: lemme pull out a repl...

21:45 okay I think the metadata should be on the var specifically

21:47 I think alter-meta! might do it better

21:48 (defmacro def- [name thing] `(do (def ~name ~thing) (alter-meta! (var ~name) assoc :private true)))

21:48 scgilardi: wonginator1221: lein falls back to jline if rlwrap is not available and notes that rlwrap is better. yes.

21:48 gfrlog: tufflax: ^ that works for me

21:48 wonginator1221: gfrlog: I've been trying to learn the netbeans IDE, but I honestly think it's a little overkill for some basic Project Euler problems.

21:48 tufflax: gfrlog what do you mean?

21:48 pdk: can always use vim

21:48 wonginator1221: Installing lein at the moment. Thanks for the help.

21:48 gfrlog: tufflax: I pasted some code

21:48 wonginator1221: no problem

21:49 tufflax: oh

21:49 gfrlog: pdk: what are you talking about nobody but me uses vim

21:49 wonginator1221: pdk: I've tried using the vimclojure plugin with very little success, but it's probably due to my lack of experience with vim.

21:52 tufflax: gfrlog thanks for the help. (defmacro def- [name val] (list `def (with-meta name (assoc (meta name) :private true)) val)) works too

21:52 gfrlog: tufflax: yeah that looks right

21:52 I think

21:53 I guess I can imagine how that would work

21:53 tufflax: hehe

21:53 gfrlog: it copies the meta from the symbol to the var

21:53 tufflax: yeah, it says exactly that in the docs :)

21:53 gfrlog: ,(meta 'name)

21:53 clojurebot: nil

21:54 gfrlog: probably you can replace (assoc (meta name) :private true) with {:private true}

21:54 since the symbol wouldn't have any meta to begin with

21:54 tufflax: maybe it has

21:54 gfrlog: oh I guess that's possible

21:54 tufflax: I guess it is possible

21:55 gfrlog: if you do (def- #^{:foo "bar"} ...) then maybe so

21:57 seancorfield: in clojure 1.3 you can just say (def ^:private thing 42) which isn't bad

21:58 gfrlog: ,(meta (var cond))

21:58 clojurebot: {:macro true, :ns #<Namespace clojure.core>, :name cond, :file "clojure/core.clj", :line 491, :arglists ([& clauses]), :added "1.0", :doc "Takes a set of test/expr pairs. It evaluates each test one at a\n time. If a test returns logical true, cond evaluates and returns\n the value of the corresponding expr and doesn't evaluate any of the\n other tests or exprs. (cond) returns nil."}

21:58 seancorfield: and metadata is additive in 1.3 so (def ^:private ^{:foo "bar"} thing 42) works as expected

21:58 gfrlog: so you could say (def ^:macro ...) as well

21:59 just to be weird

21:59 seancorfield: :)

22:01 * gfrlog just forgot how to multiply fractions

22:02 seancorfield: ,(clojure-version)

22:02 clojurebot: "1.2.0"

22:02 seancorfield: &(clojure-version)

22:02 sexpbot: ⟹ "1.2.0"

22:02 * seancorfield wonders why the bots don't get adventurous and use 1.3.0 :)

22:03 gfrlog: I approve of their behavior

22:05 it's most likely to match what folks wandering in with questions are using

22:05 seancorfield: it's interesting making code run on both 1.2 and 1.3... i didn't realize i'd let some 1.3-specific stuff into clojure.java.jdbc until aaron pointed it out (and fixed it - thankyou!)

22:06 and i tried to use congomongo but it relied on some contrib 1.2 stuff that doesn't run on 1.3 so i had to make a bunch of changes so congomongo would run on 1.3 as well

22:06 gfrlog: man we were just talking about why dependency management is hard earlier today

22:07 seancorfield: i think the move from 1.2 to 1.3 is going to be harder than it looks

22:07 mostly because of library dependencies

22:07 gfrlog: I've not tried it yet

22:08 seancorfield: some stuff is trivial, like *earmuffed* vars need ^{:dynamic true} to run on both 1.2 and 1.3 (or just ^:dynamic for 1.3)

22:08 gfrlog: all that math too

22:09 seancorfield: that depends on whether you stay within Long / Double ranges i guess

22:09 i think the 1.3 model is much better

22:09 gfrlog: that's pretty fundamental to just change how arithmetic works

22:09 without even bumping the major version number

22:10 seancorfield: i think it's the right behavior for "most" situations if clojure is really going to grow

22:10 gfrlog: which one is better is an orthogonal issue

22:10 seancorfield: i think it's also a religious issue :)

22:11 gfrlog: I likes me some bigints

22:11 kiras: if a function produces a lazy sequence and i do something like (take 5 (the-function 10)), where 10 specifies the number of elements potentially contained in the lazy-seq produced by the-function, i should only get a lazy-seq of five elements, right? or are there times when this is not the case?

22:11 gfrlog: kiras: five or less

22:11 ,(take 5 [1 2 3])

22:11 clojurebot: (1 2 3)

22:12 kiras: gfrlog: thanks, that's what i thought

22:12 i'm a little confused by something then

22:12 gfrlog: what's that?

22:13 kiras: hm... maybe i was just misunderstanding something...

22:14 i typed in this function from "the joy of clojure" at the repl and it always seems to give me the entire sequence back, even when i take a subset of it

22:15 gfrlog: share it with a pastie?

22:15 seancorfield: ,(take 5 (map #(do (println %) %) (range 10)))

22:15 clojurebot: 0

22:15 1

22:15 2

22:15 kiras: but maybe what i thought were the individual elements of the lazy-seq produced by the function are actually the entire element

22:15 clojurebot: 3

22:15 4

22:15 5

22:15 6

22:15 7

22:15 kiras: sure

22:15 clojurebot: 8

22:15 9

22:15 (0 1 2 3 4)

22:15 seancorfield: like that you mean?

22:15 although you only get 5 elements back, map is executed across more elements

22:16 gfrlog: ,(class (range 10))

22:16 clojurebot: clojure.lang.LazySeq

22:16 gfrlog: range returns a chunked seq I think

22:17 seancorfield: ,(chunked-seq? (range 10))

22:17 clojurebot: false

22:17 gfrlog: range does not return a chunked seq

22:17 seancorfield: ,(chunked-seq? (map identity (range 10)))

22:17 clojurebot: false

22:17 seancorfield: hmm...

22:17 gfrlog: I'm not sure why map would go over then

22:17 kiras: https://gist.github.com/1033674

22:18 gfrlog: kiras: what is this supposed to do?

22:19 kiras: gfrlog: if you call it like, (lz-rec-step [1 2 3 4]), you should get back something like [1 [2 [3 [4 []]]]]

22:19 seancorfield: yup

22:20 which has two elements, so (take 1 ...) will return the first but (take 2 ...) will return all of it

22:20 gfrlog: ,(inc seancorfield)

22:20 clojurebot: java.lang.Exception: Unable to resolve symbol: seancorfield in this context

22:21 gfrlog: that is not how that works

22:21 (inc seancorfield)

22:21 sexpbot: ⟹ 1

22:21 gfrlog: that is

22:21 kiras: hm... so it does...

22:21 gfrlog: kiras: and so if you take 5 elements, you also get both of them :)

22:21 kiras: gfrlog: yeah... lol

22:21 well, that makes more sense now

22:22 gfrlog: victory!

22:22 kiras: heh

22:22 seancorfield: lol... so sexpbot does karma points?

22:22 gfrlog: it does _something_

22:22 I'm not sure what it means.

22:22 let's see what happens when I do it again

22:22 (inc seancorfield)

22:22 sexpbot: ⟹ 2

22:22 seancorfield: &seancorfield

22:22 sexpbot: java.lang.Exception: Unable to resolve symbol: seancorfield in this context

22:22 gfrlog: (dec seancorfield)

22:22 sexpbot: ⟹ 1

22:22 seancorfield: :(

22:22 i have side effects! oh noes!

22:22 gfrlog: it was just an experiment. You get to keep the original one.

22:23 (inc gfrlog)

22:23 sexpbot: You can't adjust your own karma.

22:23 gfrlog: I wonder how I display it.

22:23 kiras: so how useful would that kind of function be, really?

22:23 in terms of taking advantage of laziness?

22:23 gfrlog: kiras: normally you don't have to assemble laziness so directly

22:23 seancorfield: kiras: looking at the text in the book, i think it's just an example of laziness

22:24 gfrlog: 97% of the time you'll just use a function that returns a lazy seq by default

22:24 like range

22:24 ,(take 5 (range 1000000000000))

22:24 clojurebot: java.lang.ExceptionInInitializerError

22:24 gfrlog: why does that happen.

22:24 ,(take 5 (range 1000000000))

22:24 clojurebot: (0 1 2 3 4)

22:25 gfrlog: &(take 5 (range 10000000000000000))

22:25 seancorfield: ,(take (range 1000000000000N))

22:25 sexpbot: java.lang.Exception: EvalReader not allowed when *read-eval* is false.

22:25 clojurebot: Invalid number: 1000000000000N

22:25 seancorfield: ?

22:25 gfrlog: works in my repl

22:26 ,(* 100000 100000 100000 100000)

22:26 clojurebot: 100000000000000000000

22:26 gfrlog: ,(take 5 (range (* 100000 100000 100000 100000)))

22:26 clojurebot: (0 1 2 3 4)

22:26 gfrlog: whatever

22:27 kiras: seancorfield: i agree that it's just an example, but i was a little surprised when take didn't act the way i expected. i now understand why, thanks to you and gfrlog, i was just thinking that in general, you probably wouldn't write a function producing a lazy-seq that could only ever have two elements, when the second element could be so large, right?

22:28 gfrlog: I'm having a hard time reasoning about whether you could interact with that thing in a partially-evaluated state... :/

22:28 seancorfield: kiras: well, it's certainly an odd example :)

22:28 kiras: hehe so it's not just me

22:28 gfrlog: kiras: I think it's probably the case that you don't get anything from laziness there

22:29 but the repl is acting differently

22:29 seancorfield: if you did (ffirst (rest (lz-rec-step (range 100000)))) it would only evaluate the first two parts of the range

22:30 gfrlog: apparently I'm wrong but I don't know why yet

22:30 okay I think I got it

22:31 yeah. So you CAN leave it unevaluated, but it's a bizarre and inconvenient structure for sure

22:32 seancorfield: kinda surprised they didn't use cons rather than building a lop-sided tree

22:33 gfrlog: it kind of is cons, just more primitive

22:33 cons is a lop-sided tree after all :)

22:34 or rather a list is

22:34 ,(class (list* (range 10)))

22:34 clojurebot: clojure.lang.ChunkedCons

22:34 gfrlog: ah that's where I got the chunking idea from

22:36 kiras: seancornfield: how would you have expected them to use cons and what would be the benefit of that method?

22:36 gfrlog: (cons (first s) (lz-rec-step (rest s)))

22:37 kiras: gfrlog in the "then" part of the if?

22:37 gfrlog: yeah

22:37 seancorfield: yup

22:37 then you'd get back a flat lazy sequence

22:37 kiras: i tried that a few minutes ago and it seems to act the same

22:38 gfrlog: ,(let [f (fn lz-rec-step [s] (lazy-seq (if (seq s) (cons (first s) (lz-lec-step (rest s))) [])))] (f (range 10)))

22:38 clojurebot: java.lang.Exception: Unable to resolve symbol: lz-lec-step in this context

22:38 gfrlog: ,(let [f (fn lz-rec-step [s] (lazy-seq (if (seq s) (cons (first s) (lz-rec-step (rest s))) [])))] (f (range 10)))

22:38 clojurebot: (0 1 2 3 4 5 6 7 8 9)

22:38 kiras: well, not entirely the same

22:38 gfrlog: pardon me

22:38 and from THAT list you can take 5 and only get back 5 :)

22:40 kiras: gfrlog: are you sure?

22:41 seancorfield: kiras: try this (defn lz-rec-step [s] (lazy-seq (if (seq s) (cons (first s) (lz-rec-step (rest s))) [])))

22:41 then (take 5 (lz-rec-step (range 10)))

22:41 gfrlog: kiras: I just did it, of course I'm sure :)

22:42 well sorta

22:42 ,(let [f (fn lz-rec-step [s] (lazy-seq (if (seq s) (cons (first s) (lz-rec-step (rest s))) [])))] (take 5 (f (range 10))))

22:42 clojurebot: (0 1 2 3 4)

22:42 gfrlog: there now I actually did it

22:44 kiras: but doesn't that not do what it's supposed to do anymore?

22:44 gfrlog: kiras: who knows what it's supposed to do? we're not quite sure why it's in the book.

22:45 kiras: you're right that it does something different

22:45 kiras: gfrlog: lol ok, sorry, i misunderstood what you were trying to do

22:45 seancorfield: it's still lazy tho', which is the main point (i hope)

22:46 gfrlog: of course even then it's still a weird example

22:46 because you're creating it from an already existing seq

22:46 seancorfield: we could ask chouser i guess? :)

22:47 kiras: hehe well, i thought the point was that it was supposed to take [1 2 3 4 5] and return [1 [2 [3 [4 [5]]]]] as a lazy-seq, which it does, but it seems like a strange lazy-seq to return...

22:47 so something like what you two are doing might have been a better example

22:47 gfrlog: kiras: if that's the point, then it does it quite well. I can't think of any application for that whatsoever though

22:47 even for my version, I STILL can't think of any application

22:48 turning an already-realized seq into a lazy seq seems pointless

22:48 kiras: he does have a simple-range example later that is clear enough though...

22:50 seancorfield: yeah, i guess part of the problem is finding a simple enough example to demonstrate laziness without distracting the reader with a lot of other stuff

22:50 mind you, that example is on page 116 so by that point readers have already seen a lot of stuff

22:51 gfrlog: yeah I can't say I'd have a better example

22:51 it's like how half of the stuff on 4clojure.com is just reimplementing clojure.core functions

22:51 seancorfield: and they're building on the example from page 115... (steps [1 2 3 4])

22:51 kiras: seancorfield: i agree, that's probably a tough aspect of writing a book like this. i have to wonder if it might not have been better to just use the simple-range example instead of having both though

22:52 gfrlog: I don't have the book in front of me so I'll have to trust you guys to deliver judgments :)

22:52 seancorfield: ,(reductions + [1 2 3 4])

22:52 clojurebot: (1 3 6 10)

22:52 seancorfield: ,(reductions cons [1 2 3 4])

22:52 clojurebot: java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Integer

22:52 * seancorfield thinks...

22:52 kiras: gfrlog: lol i'm in no position to be offering judgements, unless being new to the language and learning from the book counts as such a position.

22:52 gfrlog: ,(doc reductions)

22:52 clojurebot: "([f coll] [f init coll]); Returns a lazy seq of the intermediate values of the reduction (as per reduce) of coll by f, starting with init."

22:53 gfrlog: ,(reductions cons () [1 2 3 4])

22:53 clojurebot: java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Integer

22:53 gfrlog: ,(reductions conj () [1 2 3 4])

22:53 clojurebot: (() (1) (2 1) (3 2 1) (4 3 2 1))

22:53 seancorfield: ,(reductions conj [] [1 2 3 4])

22:53 clojurebot: ([] [1] [1 2] [1 2 3] [1 2 3 4])

22:53 seancorfield: jinx!

22:53 gfrlog: nah I used lists :P

22:53 kiras: you are in a much better position than me: you have the book ;)

22:54 seancorfield: ,(take 2 (reductions conj [] [1 2 3 4]))

22:54 clojurebot: ([] [1])

22:54 seancorfield: i was just thinking that steps is sort of close to reductions by way of example

22:54 ,(source reductions)

22:54 clojurebot: java.lang.Exception: Unable to resolve symbol: source in this context

22:54 gfrlog: ,(take 2 (shuffle (reductions conj () (range 1000))))

22:54 clojurebot: ((642 641 640 639 638 637 636 635 634 633 ...) (934 933 932 931 930 929 928 927 926 925 ...))

22:54 kiras: gfrlog: well, that is a point in my favor.

22:55 seancorfield: it's a good book... i bought it way back in the MEAP process... just bought chas's Clojure Programming in Rough Cuts too

22:55 i also have Clojure in Action MEAP

22:55 clojurebot: written in clojure is a huge selling point

22:56 gfrlog: only thing I've read is halloway's

22:56 where I learned to never write macros

22:56 seancorfield: Programming Clojure?

22:57 gfrlog: I think so

22:57 kiras: lol

22:57 yeah

22:57 gfrlog: the yellow book from a couple years ago

22:57 kiras: the first rule of macro club

22:57 seancorfield: written for 1.1 wasn't it?

22:57 gfrlog: at the latest, yeah

22:57 seancorfield: none of the 1.2 goodness :)

22:57 gfrlog: funny I don't even remember what the differences are

22:57 protocols and stuff I guess?

22:57 it's been so long....

22:57 kiras: i think the datatypes

22:57 seancorfield: i'm really liking what i see in Clojure Programming from emerick, carper and grand

22:58 clojure 1.2 changes: https://github.com/clojure/clojure/blob/1.2.x/changes.txt

22:59 gfrlog: woah, weak refs

23:00 I didn't really know about case...

23:00 kiras: is there a good book that covers some of the more practical areas of using clojure? like, a few weeks ago, i was in here asking about reading files and stuff. and it's kind of interesting, since you can just use java classes to do it and maybe initially that's what people did, but now it seems like you'd use clojure libraries to do so... and this will probably keep happening. so what might have been considered standard before falls

23:00 out of favor as time goes on.

23:02 so maybe a book would be the wrong medium for something like that for this language. i think there's a tendency for this to happen with any language, but i think it might be more pronounced with clojure, since using java directly is encouraged, but inevitably, ways of doing the same thing without leaving clojure are developed.

23:02 technomancy: kiras: I/O is one of the few places the language has changed since 1.0

23:03 kiras: technomancy: ah. well, you would definitely know better than i

23:03 technomancy: until 1.3 (or hopefully 2.0) is released, there will have been only 2 or 3 breaking changes in the past 2 years

23:04 gfrlog: technomancy: does that parenthesis mean that 1.3 might be renumbered 2.0?

23:04 kiras: i see things like see-saw and penumbra though, and i think they're good things, but before they were developed, would someone have been encouraged to just use opengl or swing directly?

23:05 technomancy: gfrlog: it's been suggested. it makes a lot of sense given that it's going to include a number of breaking changes, but I haven't heard anything about it recently

23:05 gfrlog: technomancy: (inc that-idea)

23:06 I was just telling seancorfield an hour ago that it bothered me

23:06 kiras: technomancy: well, i don't mean breaking changes, exactly. just that how you'd tend to do something in the language seems like it will keep changing from calling java directly to using clojure libraries that present a nicer way to do so. which is good, but it could be a challenge to keep up with. or not.

23:06 technomancy: gfrlog: scala 2.8 took a long time to get released, (lots of breaking changes) and by the time it came out, the developers wished they had called it 3.0

23:06 so it's ironic that we're making the same mistakes

23:06 gfrlog: technomancy: I feel like mucking with arithmetic is unusually fundamental

23:07 technomancy: kiras: yes, well most books avoid covering libraries outside the language itself

23:07 gfrlog: "it's okay, I'll just grep for wherever my code uses numbers."

23:07 technomancy: gfrlog: heh

23:07 kiras: technomancy: of course, the language is still fairly young and i haven't really been around other languages early on in their development.

23:08 gfrlog: technomancy: do you know if the integer changes in 1.3 effect rationals?

23:08 technomancy: gfrlog: I don't think so. but I haven't been tracking it closely

23:08 seancorfield: re: scala - as someone who started with 2.7 and endured the painful 2.8 process, i'll second that!

23:09 with scala 2.8, several RCs broke binary compatibility... so libraries constantly had to be recompiled

23:11 for clojure 1.3, the biggest issue for folks learning from books may be that all the examples in print will use contrib 1.2 stuff and contrib 1.2 doesn't run on clojure 1.3 - and the contrib library has been a) split up and b) many modules renamed

23:12 technomancy: we did learn our lesson pre 1.1 re: not assuming binary compatibility between releases

23:12 seancorfield: kiras: in particular, see http://dev.clojure.org/display/design/Contrib+Library+Names which shows how much contrib is changing...

23:12 technomancy: there was a lot more AOT going on for no good reason before that

23:12 seancorfield: technomancy: and that's one of the pillars of the 1.3 contrib shake up - no more binary libraries

23:13 all the "new" contrib stuff is source only and should run on 1.2 and 1.3

23:13 intended to encourage folks on 1.2 to start using the new contrib stuff...

23:13 not sure how successful that will be tho'...

23:14 mind you, i just went thru congomongo and switched that over to the new contrib libraries so i could use it with clojure 1.3

23:14 kiras: seancorfield: thanks. i'm sure that will be helpful pretty soon :)

23:15 technomancy: it would have been nice if the contrib dismantling had happened a year sooner

23:15 though it wasn't till 1.2 landed that using Clojure without contrib was even all that viable

23:15 seancorfield: i wonder if Clojure Programming will target 1.2 or 1.3?

23:16 ooh, 1.3!!

23:17 quote: (All of the code in this book expects v1.3.0 or higher.)

23:17 that's progress!

23:20 just commented on the clojure.contrib.sql section suggesting they update to clojure.java.jdbc :)

23:22 hugod: do all the new contrib libs have versions that are equivalent to what was in 1.2 contrib?

23:25 if not, it makes porting code to clojure 1.3 more onerous, as you need to update all your code to match a changed api as well

23:25 hiredman: I don't know that any clojure books offer much beyond what is available in programming clojure

23:26 davekong: Thoughts about "The Joy of Clojure"?

23:26 hiredman: what we need is Clojure: A Critique

23:27 do we really need a lot of books with nothing more than "this is what the literals look like, they are immutable, and here is a list of functions provided that you can do things with"

23:28 gfrlog: :)

23:31 yes. we need some more of those books.

23:31 one in every color.

23:32 kiras: gfrlog: to match the rainbow parentheses?

23:32 gfrlog: kiras: good point. Two in every color.

23:32 kiras: gfrlog: we would need two in every color then

23:32 heh

23:33 future authors, take note. the demand is there.

23:34 seancorfield: hugod: the guidance seems to be that the first release of any new contrib library should be a straight port of the old contrib equivalent, updated to run on both 1.3 and 1.2

23:35 however, some functions have moved around (so it's not just a rename of the lib in your use / require call)

23:35 and i think there are going to be _some_ breaking changes

23:36 hugod: right, just wanting to minimise it…

23:37 seancorfield: i'm looking hard at c.j.j to figure out how to make the functionality more extensible and then there's the whole binding / thread thing for *earmuffed* variables (which i admit i don't fully understand yet)

23:38 davekong: i like joy of clojure - it attacks the "why" of clojure - but clojure in action and clojure programming seem to be focusing more on "how to" stuff

23:39 hiredman: Clojure Programming has chapters on database access (c.c.sql, clojureQL, hibernate, couchdb), math / analysis and lots of other stuff beyond the basics

23:39 i haven't read Programming Clojure tho' to know what else it has beyond the basics

23:40 but Programming Clojure doesn't have anything on protocols, records and types, right? because it's based on 1.1?

23:41 technomancy: seancorfield: well, because of that and because it's 200 pages long

23:41 you really don't need that stuff in a 101-level introduction

23:42 seancorfield: joy of clojure was my "101" intro... :)

23:45 i just compared the ToC for Clojure in Action, Clojure Programming and The Joy of Clojure... hiredman could reasonably claim that CiA and JoC don't go far beyond the basics (although they have very different approaches) but CP is quite different

23:46 hiredman: what sort of stuff would you imagine being in Clojure: A Critique?

Logging service provided by n01se.net