#clojure log - Feb 26 2011

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

0:00 amalloy: ccw has a lot of the paredit functionality now, i believe

0:02 Lulu58e2: Yeah, I was using la-clojure in IDEA but I don't it sat idle for quite a while, not many features

0:02 * ... I think it sat idle ...

0:02 (My brain edits as I type and my hands get confused)

0:03 amalloy: try the other way around. let your fingers edit while your brain gets confused

0:05 Sgeo: Lulu58e2, each nick has a color

0:05 It's deterministic what nick becomes what color

0:05 seancorfield: Lulu58e2: i'm using whatever is the standard default on ubuntu :)

0:05 Lulu58e2: Sgeo: as in, the hash of the nick or some such?

0:05 Sgeo: And I don't see you as grey or blue. That's just for yourself

0:06 Lulu58e2, I don't know details

0:06 Lulu58e2: seancorfield: lol, gnome I think

0:06 Sgeo: But you're the same color as seancorfield

0:06 Lulu58e2: Sgeo: well that's good to know, thanks

0:06 I had a brilliant idea: rtfm ... lol

0:09 seancorfield: Lulu58e2: mostly i use linux on servers so i never see the GUI... and i generally have Macs for desktop / laptop

0:09 Lulu58e2: seancorfield: ah, lucky

0:09 seancorfield: i just bought a system76 starling netbook for traveling with and it has ubuntu netbook remix on it

0:09 which is what i'm on right now :)

0:11 Lulu58e2: seancorfield: very nice

0:18 Okay, so the xchat help didn't help, but someone on #xchat did.

0:25 amalloy: and?

0:25 Lulu58e2: Settings -> Advanced -> Text Events "has everything to do with it"

0:26 Colour and formatting codes for all events

0:26 amalloy: neat

0:47 Lulu58e2: lol

0:47 So easily distracted from the task at hand

0:56 Sgeo: I'm going to try to translate the PMD paper's demo to Clojure

1:54 cobol_expert: what are symbols of the form *symbol* called?

1:58 Sgeo: I think I like Haskell's State monad a little more than I like Clojure's -> macro

1:59 cobol_expert: also, when docs say 'set *warn-on-reflection* to true...' how do you set it?

1:59 just redefine it, like (def *warn-on-reflection* true) ??

2:00 amalloy: cobol_expert: (set! ...)

2:00 symbols are wrapped in *earmuffs* usually to indicate that they're expected to change and/or be rebound

2:01 Sgeo: wut. they are completely different things. clojure has a state monad too

2:01 cobol_expert: okay, thanks. i remember seeing that before, but I don't see docs for 'set!' anywhere.. i would expect it to be in clojure.core

2:02 what ns is set! in?

2:02 amalloy: &(doc set!)

2:02 sexpbot: java.lang.SecurityException: You tripped the alarm! set! is bad!

2:02 amalloy: blah. cobol_expert, set! is a special form

2:02 (doc set!)

2:02 clojurebot: Pardon?

2:03 cobol_expert: ah, whenever I can't figure something out, it's a 'special form' :)

2:03 Sgeo: Are Clojure monads used as commonly as monads in Haskell (subtracting usage of Haskell's IO monad, of course)

2:03 cobol_expert: i should know by now

2:04 amalloy: you bots all suck: http://clojure.org/vars#Vars%20and%20the%20Global%20Environment--%28set!%20var-symbol%20expr%29

2:05 Sgeo: o.O Clojure can use Monadic I/O

2:05 I'm going to hazard a guess that it's mostly used by Haskellers

2:07 amalloy: as with every clojure tool, it's mostly used by developers who think it's the best widget for the current job

2:14 cobol_expert: okay, so how do I create a new global variable to use set! with? (def *a* 1) ; (set! *a* 2) doesn't work.. that link says it 'must resolve to a global variable'

2:19 amalloy: cobol_expert: don't: clojure doesn't want you to introduce mutable state. vars should created with def and bound with (binding [var value] (var is globally changed until binding form is over))

2:20 once a var has been bound, you can set it with set!, but usually shouldn't anyway

2:21 in fact i've never set! anything but warn-on-reflection and a couple java instance fields :P

2:22 cobol_expert: okay, thanks for clearing that up :)

2:23 i just see that form a lot and wondered if I ought to be using it for my programs' globals.. i guess not

2:23 Sgeo: binding is dynamic though, couldn't it cause weird issues if not used with caution?

2:23 (binding [some-function-name-but-i-dont-realize-it nil] ...)

2:24 Hmm, accidentally binding a function name like that probably wouldn't happen, come to think of it'

2:27 All names are namespaced?

2:29 cobol_expert: binding seems to create its own namespace

2:29 amalloy: neither of the previous two statements is true

2:30 cobol_expert: 'seems to' is not an assertion :)

2:30 amalloy: lol

2:30 lots of names aren't namespaced, for example x in (let [x 10] (inc x))

2:30 *most* vars are namespaced, which may have been what you meant

2:31 cobol_expert: binding pushes the value of a global variable onto a stack, changes it, and sets it back, more or less

2:31 cobol_expert: yeah, i was struggling with how to say it

2:31 more or less

2:32 amalloy: it piggybacks on top of the existing namespaces in the vars; it definitely doesn't create its own

2:34 Sgeo: Why are there no lisps that have special forms be first-class values? Or are there?

2:35 amalloy: that's what makes them special

2:38 Sgeo: I thought what made them special was that inner arguments aren't fully evaluated before being sent

2:38 Or something along those lines

2:40 amalloy: Sgeo: the same is true of user-defined macros, and those definitely aren't special

2:46 Sgeo: I meant to include user-defined macros

2:46 But why aren't they first-class?

2:47 amalloy: they don't have values. it doesn't make sense to be able to pass a macro as a value at runtime, because it can only perform actions at compile time

2:47 Sgeo: Ah

2:48 Sorry if I seem like an idiot.

2:51 amalloy: Sgeo: http://rantsand.blogspot.com/2006/09/intelligence-wisdom-ignorance-and.html is an entertaining discussion of the difference between stupidity and ignorance

4:03 semperos: I have a structure like {:foo #{"bar" "baz"}}

4:03 starting with an empty map

4:03 I know if I do

4:03 ,(assoc {} :foo #{})

4:03 clojurebot: {:foo #{}}

4:04 semperos: I get a structure with which I can use update-in to conj onto the set

4:04 ,(update-in {:foo #{}} [:foo] conj "bar")

4:04 clojurebot: {:foo #{"bar"}}

4:04 semperos: and so on as I add to that set

4:04 my question is

4:04 Arelius: I'm not sure I understand why when I eval a ns block, I get an error 'replace already refers to ...." in slime when normally that's just a warning.

4:04 amalloy: semperos: fnil

4:05 &(update-in {} [:foo] (fnil conj #{}) "bar")

4:05 sexpbot: ⟹ {:foo #{"bar"}}

4:05 semperos: amalloy: thank you for anticipating my question

4:05 I keep forgetting that fnil exists

4:05 amalloy: semperos: you were building up to it quite thoroughly :)

4:05 semperos: :)

4:05 I knew there was a way

4:06 and I keep missing the opportunities to use it

4:06 amalloy: thanks, really appreciate it

4:06 amalloy: semperos: i went out of my way to use fnil the other day. up till now i basically just use it for update-in

4:06 semperos: very natural fit for this kind of thing

4:07 Toomasu: I hadn't seen fnil yet, tangible benefit from following the channel for a couple of minutes :)

4:07 amalloy: and in fact even in https://gist.github.com/ac577998a404164266aa i'm really just using it for a more-specialized version of update-in, i guess. so no extra credit for finding new places to use fnil

4:08 * semperos looks

4:09 semperos: gotcha

4:10 Toomasu: imho, you won't find many channels better than this one

4:10 for any language/project

4:11 amalloy: semperos: i have a tidier version of that code somewhere but i might have thrown it away. i surprised myself by writing (let [[< inc] (map #(fnil % 0) [< inc])] ...)

4:11 so that the nil-handling code didn't have to be next to the math-handling code

4:12 semperos: absolutely, your use in that gist makes sense

4:12 with a more complex data structure elsewhere in my code, I think I already committed an oversight and "prepped" map entries

4:12 amalloy: ah

4:12 semperos: so I'll have to go back and fnilify that

4:13 amalloy: fnilify. that's a tricky one to pronounce

4:13 semperos: :)

4:14 eff-nil-ify

4:14 how I hear it, anyway

4:25 fliebel: morning.

4:25 amalloy: allo fliebel

4:27 fliebel: In this post by dnolen, why is he creating these multimethods with a single method? http://dosync.posterous.com/beyond-javascript-prototype-chains The type inheritance is nice and all, but I don't see why he does not use regular functions, or a single multimethod.

6:07 amalloy: semperos, if you're still around and are interested, i've written two more versions of keep-only at https://gist.github.com/ac577998a404164266aa

6:11 i'm not sure whether the second or third version is more readable, and the fourth certainly isn't, but it's been fun playing with refining an idea, and figuring out how to lazify it was a real headache

6:13 kencausey: I've just created #las3r for anyone interested in the AVM2 'port' of Clojure - https://github.com/aemoncannon/las3r

6:14 semperos: amalloy: unfortunately I am still around, can't sleep

6:14 thanks, I'll take a look

6:14 amalloy: semperos: same here, though i was about to clock out. what time is it where you are?

6:14 semperos: 6

6:14 you?

6:14 clojurebot: You will not become skynet

6:15 amalloy: 3

6:15 semperos: more sane :)

6:15 I slept for a few hours

6:15 but woke around 2:30 my time and can't sleep

6:15 go get some rest, thanks for all your help

6:16 amalloy: semperos: you're welcome. i'm not doing it for you, though :) - i think i'll write a blog post about how a simple idea evolves into various different versions

6:17 kencausey: hey neat. one of my friends thinks clojure is really cool but will never spend the time to do anything with it - maybe i can get him halfway there in his native flash environment

6:18 kencausey: It's not my implementation of course, I'm just an interested user. And note it is as much influenced by clojure as a port, but yes, it is sort of halfway

6:18 I would say it is less polished at this point and certainly has nothing like the community of clojure, I'm hoping to improve that somewhat

6:18 amalloy: well, i'll remember not to claim i know the guy who wrote it all

6:19 kencausey: :)

6:21 amalloy: night folks

6:44 semperos: I've removed clojure.contrib from my project.clj, but leiningen keeps pulling in the lib when I run 'lein deps' and 'lein uberjar'

6:44 am I missing something?

6:45 nm

6:45 * semperos needs sleep

8:04 gfrlog: Good morning clojure

8:07 tscheibl: may I introduce queuejure

8:08 gfrlog: please

8:10 tscheibl: it's a http long polling library based on a compojure ring aleph lamina combination

8:11 gfrlog: now I have to find out what lamina is

8:11 tscheibl: it's very lightweight.. not as bloated as CometD is...

8:11 lamina is a channel framework

8:11 gfrlog: was it extracted from aleph?

8:12 tscheibl: ..just enough functionality to implement a reliable server messagequeue

8:12 gfrlog: lamina?

8:12 gfrlog: yes

8:12 tscheibl: probably

8:13 it's quite usefull for implementing messagequeues

8:13 .. I mean.. you don't have much mor to implement

8:14 gfrlog: cool

8:15 tscheibl: queuejour primarily focuses on hiding http request concurrency issues and request timeouts

8:16 well.. I think I will call it queuejour ... despite the fact that technomancy won't like it ;)

8:16 gfrlog: I was thinking of that naming controversy

8:16 tscheibl: got a better name? ;)

8:16 I'm open for proposals

8:17 fliebel: tscheibl: Are you making a message queue?

8:17 gfrlog: queue-ball

8:17 tscheibl: Yesterday it started to do everything I expected in my testbed... currently I try to create a decent library from the prototype code

8:18 fliebel: clueue :)

8:18 tscheibl: lol

8:18 gfrlog: can't beat that

8:19 tscheibl: msjqueue

8:19 ..nah

8:19 gfrlog: ueueueue

8:19 tscheibl: jeujeujeujeu

8:19 gfrlog: pronounced "oooh!"

8:19 tscheibl: jeujour

8:19 excuse my french ;)

8:20 fliebel: ceuj

8:20 tscheibl: cjeu ?

8:20 cjeur ?

8:20 raek: monsieur clojeur

8:20 tscheibl: clojard

8:21 raek: (the community seems to have settled on "clojurian", but always felt that "clojeur" was an interesting option)

8:21 fliebel: raek: I agree :)

8:22 tscheibl: org.myveryownorangisationname.http.toolkits.qeuejour

8:22 arghh

8:22 raek: fliebel: that even fits the dutch spelling system, doesn't it?

8:23 fliebel: yea… but that is probably because dutch borrows heavily from french

8:23 tscheibl: they borrow from everyone ;)

8:23 raek: Klåschör

8:24 tscheibl: you are scandinavian, aint you?

8:24 raek: swedish does that too to some extent, but the spelling makes it less obvious

8:24 tscheibl: yess Sweden

8:24 * fliebel is confused, who is from sweden? raek or tscheibl?

8:25 tscheibl: raek

8:25 I'm from Austria

8:25 ... no... no Kangaroos

8:25 fliebel: you did not say australia did you?

8:26 tscheibl: Claustralia

8:26 .but there is no j in it

8:26 gfrlog: my great grandparents are from sweden

8:26 fliebel: I've been to sweden last month (to contribute some other random fact)

8:27 tscheibl: I've been in Norway some years ago.. that's at least close ;)

8:27 gfrlog: I think that roughly equals great-grandparentage as far as being-swedish goes

8:27 tscheibl: would be like great-grandparents

8:29 gfrlog: Sweden is in the news lately

8:30 fliebel: gfrlog: Because of that leaking guy? O rjust because Sweden is taking over3 the world?

8:31 tscheibl: I think you confuse it with Libya

8:31 gfrlog: it's always those two

8:31 I'm like "which is which?" and I can never remember

8:32 fliebel: gfrlog: sweden hos no sand, so if you seen sand in the news, it's not sweden

8:32 gfrlog: well I hope al-Gaddafi is nice to Mister Assange...

8:33 fliebel: So, is Anonymous behind these protest after all?

8:33 tscheibl: both of them will need political asylum in the near future

8:33 .. if they make it before beeing executed

8:34 ..ahhh don't say 'anony....' they will close down irc

8:35 * fliebel wonders how we got so offtopic

8:36 gfrlog: maybe we could use queuejure to send Mister Assange a helpful message

8:36 or a sequence thereof

8:36 tscheibl: or.. queueball

8:36 I'm not so jour anymore

8:36 fliebel: or clueue

8:36 tscheibl: or jeujeujeu

8:37 fliebel: Anyway, does anyone know if Clojure runs on Mono yet?

8:37 tscheibl: who needs that?

8:37 I mean... why the hell?

8:38 I can understand if you are ms fanboy you prefer to run it on the .NET CLR on an MS Platform... but Mono?

8:39 Cozey: :-) btw. sweden had and has some good music bands: http://www.youtube.com/watch?v=Aq4apgYriXE

8:39 fliebel: Well, why not? I heard they have some nice stuff on the CLR, plus MonoTouch would be cool :)

8:39 tscheibl: do they have Clojure in Sweden?

8:40 I've got a grey import here in Austria

8:40 ;)

8:40 MonoTouch?

8:40 I knoe.. goolge is ya...

8:40 w

8:41 fliebel: $google monotouch

8:41 sexpbot: First out of 43200 results is: Main Page - MonoTouch from Novell

8:41 http://monotouch.net/

8:41 gfrlog: oh I know why everybody is European...I'm on IRC way too early

8:41 now it all makes sense

8:42 the western hemisphere is still hungover

8:42 $google gfrlog

8:42 sexpbot: First out of 91 results is: gfrlog:

8:42 http://gfredericks.com/

8:43 gfrlog: I wonder how it is googling...the result count seems low

8:51 kencausey: Not everyone is European ;) but point taken and agreed to

8:51 gfrlog: kencausey: are you also an exception to the hungover-westerner rule?

8:55 kencausey: Yes

8:55 hmm, actually I'm not certain what yes and no means to that question...

8:56 I consumed no alcohol yesterday, I'm a loner geek/nerd of the first order

8:56 clojurebot: No entiendo

9:31 TimMc: gfrlog: Me too.

9:43 gfrlog: kencausey & TimMc: well good.

9:43 no wonder this party is so happening

9:43 TimMc: Boston, USA here.

9:43 gfrlog: That is my time zone but not my climate

9:44 I would love to be there though

9:51 isn't there a method somewhere that could go by the name 'eval-in-ns?

9:51 I feel like I heard of it the other day

9:52 $findfn 'difference clojure.set/difference

9:52 sexpbot: []

9:55 gfrlog: and is (deref (future (expr...))) equivalent to (expr...)?

9:55 wondering why I used the former...

9:55 oh it probably has to do with agents waiting on things...

10:06 raek: gfrlog: modulo costs for thread allocation and that exceptions get wrapped in a ExecutionException, yes

10:11 eckroth: Is there some idiomatic improvement of the following: (first (filter pred coll)) ?

10:13 raek: eckroth: (some #(when (pred %) %) coll) is an alternative. when pred is =, it can be written as (some #{x} coll)

10:13 kencausey: I prefer the original myself

10:14 raek: yeah, me too in this case. but #'some can be useful sometimes.

10:14 eckroth: raek: thanks; seems like this is common enough to have something like (pick-out pred coll)

10:16 kencausey: eckroth: so add it, Lisp is all about customization

10:16 eckroth: well yeah but then I have my own special function floating around in some duplicated file for all my projects :)

10:16 oh well

10:16 kencausey: not an unusual situation

10:16 eckroth: I suppose so

10:17 kencausey: have you check the contrib libs?

10:17 eckroth: no; will do now

10:17 kencausey: if it's not there maybe you can get it added

10:19 msappler: Hello I have a question regarding require and loading: http://pastebin.com/NRnLmzaq

10:20 raek: msappler: (:require (a.test2)) should be (:require a.test2)

10:20 eckroth: kencausey: thanks for the push to look in contrib; I found it:

10:20 (clojure.contrib.seq/find-first pred coll)

10:20 raek: (:require foo.x foo.y foo.z) is the same as (:require (foo x y z))

10:21 kencausey: eckroth: excellent

10:21 eckroth: kencausey: its definition: (first (filter pred coll))

10:21 haha

10:21 raek: so (:require (a.test2)) means "require no namspaces starting with a.test"

10:22 kencausey: :)

10:22 msappler: oh

10:23 why is this not in the require docs?

10:25 eckroth: does anybody already know of an optimization of (second (first coll))?

10:26 fliebel: eckroth: What is there to optimize?

10:26 raek: eckroth: (let [[[_ x]] coll] ...)

10:26 not an optimization, but another way of writing it

10:26 eckroth: yeah, ok... I thought maybe something like CL's cadr, caadr, etc.

10:27 fliebel: there are a couple of ones named like fnext and such

10:27 eckroth: yeah

10:27 raek: I think clojure has fnext and nnext, but destructuring is used more often my gut feeling tells me

10:29 gfrlog: raek: regarding my (deref (future (expr...))) question, you would agree that it has different behavior within an agent, right?

10:30 raek: gfrlog: how?

10:30 fliebel: $findfn [[1 2] 3 4] 2

10:30 sexpbot: []

10:30 gfrlog: raek: I believe you cannot call (await) within an agent

10:31 but you can within a future that the agent derefs

10:31 so you can get the same behavior, but with the advantage of harder-to-understand code

10:31 raek: ah, now I see what you mean

10:32 I get the feeling you are using agents for something they weren't designed for (I may be wrong, though)

10:32 gfrlog: I thought of that, and it make be the case. But what I'm doing is using clojure.contrib.http.agent for synchronous http calls

10:32 so it wasn't my idea to make it an agent

10:33 but maybe doing the synchronous http is inappropriate; that would require more thinking

10:33 raek: yeah, agents are meant to be primarily asynchronous

10:33 gfrlog: well naively I would say that I want a synchronous http library and there just aren't any

10:34 so I have to use clojure.contrib.agent and just wait for them

10:34 but there's probably a cleaner way to do what I'm doing

10:35 raek: there are a lot of other http client libs

10:37 I would recommend checking them out to see if their api fits better for your usage

10:39 bobo_: async http client? https://github.com/neotyk/http.async.client

10:54 gfrlog: ,(do (dorun (repeatedly 500 (partial agent 4))) "all those poor unused agents")

10:54 clojurebot: "all those poor unused agents"

10:56 gfrlog: I feel like the documentation for the (ns) macro might be wrong...

10:56 I thought this is not valid: (:require (clojure.contrib sql sql.tests))

10:57 either that or the documentation for 'require is wrong: After removing the

10:57 prefix, the names that remain must not contain any periods.

10:57 or alternatively, I'm confused

11:05 is 'for always nicer than using 'map with an anonymous function?

11:05 pdk: the intent is clear enough with map and it's more concise

11:05 gfrlog: it is?

11:05 (the concise part I mean)

11:06 pdk: cf. (map anon-fn list) and (for [i list] (anon-fn i))

11:06 gfrlog: more like (map #(do-this %) list) and (for [i list] (do-this i))

11:06 I feel like the second one looks nicer

11:07 pdk: if do-this takes one argument you only need to write (map do-this list)

11:07 Sgeo: (map (partial do-this) list)

11:07 Oh

11:07 * Sgeo facepalms

11:07 gfrlog: pdk: I know, but when I say "anonymous function" I'm specifically ruling that out

11:07 I agree map is nicer when you can just pass a function

11:08 assuming that that map alternative involves typing #(...) or (fn [_] ...)

11:08 both of which seem clunkier

11:08 pdk: in that case i guess for would be fine

11:10 gfrlog: ,(map for list)

11:10 clojurebot: java.lang.Exception: Can't take value of a macro: #'clojure.core/for

12:12 sritchie_: hey all -- is there a way to bind a vector of all arguments to defn to a variable?

12:12 like -- (defn read-test [datasets resolutions tiles :as args] ... )

12:12 I'm not destructuring, I just want to apply a function to all of these arguments

12:17 spewn: sritchie_: As in (defn foo [& bar] (apply str bar)) ?

12:17 sritchie_: spewn: yeah, that's true... I just wanted to make it clear what the arguments should be

12:18 TimMc: You want individual names and also a name for the whole list?

12:18 sritchie_: TimMc: yeah, exactly. I think I need to think more about these functions, but I was just curious about that possibility

12:19 Sgeo: (defn foo [a b c] (let [args [a b c] (apply str args))) ;Note: Don't trust anything I write, I'm somewhat new

12:20 sritchie_: Sgeo: no, that works, that's good

12:21 TimMc: sritchie_: OK, here we go

12:21 ,((fn [& [a b :as e]] [a b e]) 1 2 3)

12:21 clojurebot: [1 2 (1 2 3)]

12:21 Sgeo: Maybe I'll try Clojure Box

12:21 TimMc: Note that there is nothing forcing the correct number of arguments.

12:22 Sgeo: Your example would be better done as (defn foo [a b c] (str a b c))

12:22 sritchie_: TimMc: noted -- that makes sense, though, since the :as clause I was thinking about is found in destructuring

12:22 so we just destructure the variadic arguments

12:22 TimMc: sritchie_: It still may not be what you want.

12:23 sritchie_: Sgeo: I'm currently using TimMc's method, of just feeding them through into the next function

12:23 Sgeo: I was curious about shorthand

12:23 TimMc: ,((fn [& [a b :as e]] [a b e]) 1)

12:23 clojurebot: [1 nil (1)]

12:28 _2x2l: http://pastie.org/1610288 does anyone know why lein is throwing that error? seems like the syntax should be right according to the github docs.

12:29 Sgeo: Yay Clojure Box1

12:36 Emacs seems to have some weirdities with []

12:36 I mean I guess that's to be expected

12:36 But still

12:39 TimMc: Sgeo: I haven't experienced any weirdness with that.

12:39 Sgeo: Typing ] doesn't show the other [

12:39 And it indents weirdly

12:39 TimMc: You're probably not in the right modes.

12:40 Sgeo: http://ideone.com/M96Yh

12:40 I'd expect that println to be further to the left

12:41 TimMc: Right. You're probably not in the right modes.

12:41 I get the expected behavior in Clojure + Paredit + hl-p

12:43 Sgeo: This thing came with paredit but it's not enabled by default

12:43 What's hl-p?

12:44 bennylut: what am i doing wrong? ^(with-meta '(1) {:x 5}) => #<IllegalArgumentException java.lang.IllegalArgumentException: Metadata must be Symbol,Keyword,String or Map>

12:44 TimMc: Sgeo: highlight-parentheses-mode

12:45 ,(with-meta '(1) {:x 5})

12:45 clojurebot: (1)

12:45 TimMc: bennylut: Drop the initial caret.

12:46 bennylut: TimMC: i want to receive the metadata

12:46 when i wrote ^(with-meta '(1) {:x 5}) i wanted to get (meta (with-meta '(1) {:x 5}))

12:46 TimMc: ,(meta (with-meta '(1) {:x 5}))

12:47 clojurebot: {:x 5}

12:47 TimMc: I don't think ^ does that.

12:47 bennylut: i see, i have read that writing ^x means (meta x) am i wrong?

12:47 ok, thanks!

12:48 TimMc: bennylut: ^String foo means (with-meta foo {:tag String})

12:49 and ^{:a :b} foo gives you (with-meta foo {:a :b})

12:49 bennylut: hmm.. i see, thanks

12:52 TimMc: but see that- (def my ^String y) (meta my) => {:line 9} why?

12:54 where y is : (def y '(1))

12:54 TimMc: Hmmm. This is where vars start to complicate things and I am out of my depth.

12:55 ,(meta ^String (list 3))

12:55 clojurebot: nil

12:55 TimMc: OK, ignore the bit I said about :tag, then.

12:56 bennylut: see that: (meta #'my) => {:tag String}

12:56 TimMc: All I'm sure of is that ^ is for associating metadata, not for reading it.

12:57 bennylut: ok i think that i will use the full methods for metadata cause the reader macros seem to be little awkword

12:59 TimMc: What we're dealing with here is the difference between metadata on a var and metadata on a value.

13:01 bennylut: so ^String x will put metadata on the var and (with-meta {:tag String} x) will put metadata on the value? if so in order to give the compiler a type hint what should i use ?

13:05 TimMc: ,(do (set! *warn-on-reflection* true)

13:05 clojurebot: EOF while reading

13:05 TimMc: bah

13:05 ,(do (set! *warn-on-reflection* true) (let [x "foo"] (.length ^String x)))

13:05 clojurebot: java.lang.IllegalStateException: Can't change/establish root binding of: *warn-on-reflection* with set

13:05 TimMc: OK, let me play with my own REPL for a sec.

13:08 bennylut: Anyway, (set! *warn-on-reflection* true) in your REPL and then try (.length (identity "foo")).

13:08 This will give you a baseline for determining that hinting might be useful.

13:09 identity here serves to strip any knowledge that the argument to .length is a String.

13:09 Then try different approaches: (.length ^String (identity "foo"))

13:15 bennylut: TimMc: thanks i will check it and post here

13:15 TimMc: bennylut: It's the ^String approach, btw.

13:16 ,(with-meta (identity "foo"))

13:16 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (1) passed to: core$with-meta

13:16 TimMc: ,(with-meta (identity "foo") {:tag String})

13:16 clojurebot: java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IObj

13:17 TimMc: You can't put Clojure metadata on most Java objects, including strings.

13:17 That is, (with-meta ...) won't work with most Java values.

13:18 bennylut: i see, so this is why you must put the metadata on the var - so that the compiler will be able to search metadata on static location :)

13:19 TimMc: Something like that. I don't understand it myself yet.

14:11 DespiteItAll: Hmmm, (Boolean. false) is true

14:15 TimMc: ,(Boolean. false)

14:15 clojurebot: false

14:15 DespiteItAll: ,(if (Boolean. false) "true" "false")

14:15 clojurebot: "true"

14:15 TimMc: Oh, I see.

14:15 Yeah.

14:15 DespiteItAll: I thought clojure false was the same as java's false

14:16 TimMc: ,(if false "true" "false")

14:16 clojurebot: "false"

14:16 Lulu58e2: Isn't anything not nil or false is true? (or something)

14:16 TimMc: It is.

14:16 DespiteItAll: ,(class false)

14:16 clojurebot: java.lang.Boolean

14:16 DespiteItAll: Hmmmm

14:16 TimMc: DespiteItAll: (Boolean. ...) is an object, which is always true.

14:16 danlarkin: clojure's false is Boolean/FALSE

14:17 Lulu58e2: Not same instance though?

14:17 DespiteItAll: Ahh, got it

14:17 I know no java so the distinction is lost on me, but I see that there is one

14:17 Lulu58e2: I'm not 100% sure, I'm just guessing

14:18 TimMc: (class) might auto-box the input

14:18 So, false -> (Boolean. false)

14:18 Lulu58e2: ,(hash (Boolean. false))

14:18 clojurebot: 1237

14:19 Lulu58e2: ,(hash false)

14:19 clojurebot: 1237

14:19 Lulu58e2: Hmmm

14:19 DespiteItAll: So, (Boolean. false) is the same as (Boolean. Boolean/FALSE)

14:19 whatever that means

14:19 TimMc: ,(identical? false (Boolean/FALSE))

14:19 clojurebot: true

14:19 TimMc: ,(identical? false (Boolean. false))

14:19 clojurebot: false

14:20 TimMc: ,(identical? (Boolean. false) (Boolean. false))

14:20 clojurebot: false

14:20 mrBliss: ,(if (Boolean. false) "true" "false")

14:20 clojurebot: "true"

14:20 TimMc: The hash does not tell you about identity.

14:20 Lulu58e2: lol

14:20 mrBliss: (if (boolean false) "true" "false")

14:20 Lulu58e2: Ah, I thought each instance had a unique hash

14:21 TimMc: Nope.

14:21 mrBliss: (Boolean. false) is evil, use boolean ##(map boolean [false nil 1 () true])

14:21 ,(map boolean [false nil 1 () true])

14:21 clojurebot: (false false true true true)

14:23 TimMc: ,(type false)

14:23 clojurebot: java.lang.Boolean

14:23 TimMc: hrm

14:23 Still auto-boxing. :-)

14:58 amalloy: &(.getComponentClass (class (into-array [false])))

14:58 zippy314: Hi folks, I'm using emacs and lein swank for my REPL. I'd love to have all my files compiled at load time rather than having to C-c C-k each one. Anybody know a shortcut for this?

14:58 sexpbot: java.lang.IllegalArgumentException: No matching field found: getComponentClass for class java.lang.Class

14:59 amalloy: &(.getComponentType (class (into-array [false])))

14:59 sexpbot: ⟹ java.lang.Boolean

15:00 amalloy: zippy314: C-c C-k is transitive. if you compile your "main" file that depends on all the others, they all get compiled

15:00 zippy314: Cool. Thanks.

15:07 jk_: if i remove a namespace with remove-ns, what happens to the vars that were mapped into that namespace? are they garbage collected? if not, how do you access them?

15:10 amalloy: jk_: looks to me like they get GCed

15:12 try this entertaining experiment: (in-ns 'tmp) (def x 1) (in-ns 'user) (def h #'tmp/x) (remove-ns 'tmp) @h

15:13 yields 1 because h is keeping a reference to the defunct var, but if you redef h, there's no longer any way to get at it

15:18 Null-A: lol amalloy

15:24 jk_: amalloy: yes that makes sense because you simply grabbed a reference to it before you trashed the namespace map. i was basically wondering if there is anything internally that keeps a reference or whether it gets garbage collected

15:24 amalloy: i don't think so

15:25 jk_: i was basically wanting to know whether i could blow away stuff in a long-running repl simply by removing namespaces without having a memory leak

15:25 amalloy: should be fine

15:25 jk_: thanks, amalloy

15:35 rikva: Beginners question: Is it possible to use multiple lines of code within a if form? Or is that not the Clojure way?

15:36 no_mind: rikva: if you are looking for executing multiple lines inside braces like non-functional programing languages, then I think it is not possible

15:36 amalloy: whoa slow down

15:36 no_mind: but I am no clojure master :)

15:37 amalloy: rikva: it is possible, and also it is not the clojure way :)

15:37 rikva: then, what is the clojure way? :)

15:37 moving the code to a new function?

15:38 amalloy: rikva: code without side effects when possible. if you think about it, you only want a "multi-line" if statement when the first few expressions have side effects

15:38 if you are aware of that, and side effects are the right solution to your problem, clojure lets you do it: ##(if false 10 (do (println 1) (println 2)))

15:38 sexpbot: ⟹ 1 2 nil

15:40 amalloy: if you only have one branch in your if (ie no else), there's shorthand for the if/do combo: ##(when true (println 1) (println 2))

15:40 sexpbot: ⟹ 1 2 nil

15:40 amalloy: rikva: making any sense yet?

15:41 rikva: yes, you are making perfect sense. I'll try it the Clojure way ;)

15:45 Null-A: rikva: (when true (println) (println) ..)

15:45 er already explained

16:03 amalloy: Null-A: but you included the ... that i was missing :)

16:03 Null-A: heh

16:03 gfrlog: best way to check if I have a list or vector?

16:05 am handling source code

16:08 Guest22761: gfrlog: (list? x) (vector? x) ?

16:10 dsantiago: It seems like clojure.core/name will cause a null pointer exception when it is passed nil. Why wouldn't it just return nil?

16:13 Guest22761: dsantiago: that seems like a reasonable thing to do if you don't pass it an actual clojure.lang.Named

16:13 dsantiago: return nil, i mean.

16:14 dsantiago: Yeah. Most other functions seem to cope very nicely with nil. I am just wondering if it is a bug or if it's deprecated or there's a good reason for that or what.

16:14 Can't imagine why you'd want the NPE, epecially when so many other clojure functions cope with nils as if they are empty objects of the type they are interested in.

16:15 TimMc: I can't say I'm too pleased with nil propagation as an idiom.

16:16 Makes it hard to know where the logic bug actually occurred.

16:17 dsantiago: But it's not really a logic bug if nil means "the empty list" or something like that.

16:18 Guest22761: i like the idea of (name) basically telling you tehre is no name

16:18 without just blowing up :)

16:21 TimMc: Nil as empty seq (and nil propagation) are problematic for fail-fast programming.

16:21 amalloy: gfrlog: don't use list? for source code. seq? is better

16:21 macros expand into seqs, not lists

16:22 dsantiago: amalloy: Is seq? better than sequential? seq? returns true on a map, but sequential? doesn't.

16:22 Guest22761: amalloy: but that's not telling you that it's a list or vector, right?

16:22 amalloy: &((juxt seq? sequential?) {})

16:22 sexpbot: ⟹ [false false]

16:23 amalloy: &(map (juxt list? seq? sequential?) [() [] {} (range 0)])

16:23 sexpbot: ⟹ ([true true true] [false false true] [false false false] [false true true])

16:24 amalloy: note that seq? returns true for the list and the lazy-seq, but not for the vector or the map. sounds like what gfrlog was asking for

16:25 Guest22761: ok, if it's exclusively one or the other than you have then that's fine

16:25 s/than you/that you/

16:25 sexpbot: <Guest22761> ok, if it's exclusively one or the other that you have then that's fine

16:26 dsantiago: Weirdly mixed up about that.

16:26 amalloy: Guest22761: if you need to distinguish scheme-style "atoms" from "listy things", you have coll?

16:26 dsantiago: I ran into that same question like 3 days ago, apparently I alredy forgot everything about the differences.

16:30 Sgeo: Maybe I should translate one of my few Haskell programs to Clojure...

16:32 gfrlog: ,(seq? (read-string "(+ 3 4)"))

16:32 clojurebot: true

16:33 gfrlog: ,(seq? (read-string "[+ 3 4]"))

16:33 clojurebot: false

16:33 gfrlog: amalloy: seq? misses vectors

16:33 guess I gotta go with (or (seq? ..) (vector ..))

16:33 amalloy: gfrlog: it sounded like you wanted to tell seqs and vectors apart, not lump them together

16:34 gfrlog: amalloy: sorryo, no

16:34 amalloy: see my juxty thing earlier. you want sequential?

16:34 gfrlog: wanted to distingush them from other things

16:34 ,(sequential? "hoo ha")

16:34 clojurebot: false

16:34 gfrlog: nice

16:35 ,(map sequential? [[] () (read-string "(+ 3 4)") "okay" :nope 'yeah])

16:35 clojurebot: (true true true false false false)

16:35 gfrlog: that is exactly what I wanted

16:35 thx amalloy

16:35 amalloy: gfrlog: what's with the read-strings, anyway? '(+ 3 4) seems easier

16:36 hm. i wonder. ##(sequential? (sorted-set []))

16:36 sexpbot: ⟹ false

16:37 gfrlog: amalloy: strings aren't available till runtime

16:37 my strings I mean; wasn't saying something bizarre about strings gin general

16:37 amalloy: lol

16:38 gfrlog: I'm doing all kinds of disgusting crap with these strings, like doing gsubs with namespace names...

16:38 rikva: i'm doing a small test with recursion but I can't seem to figure it out. Can someone tell me what's wrong with this? http://pastebin.com/JZM3tSUv

16:38 Sgeo: Once Clojure-in-Clojure is completed, will Clojure be ported to bare metal?

16:38 * amalloy rewrites gfrlog's main function as (constantly 'dude-what-a-mess)

16:39 gfrlog: amalloy: I wrote my own parser for the (ns) sub-language

16:39 amalloy: rikva: the a needs to be inside the if

16:39 gfrlog: just shake your head slowly

16:39 amalloy: gfrlog: is there a reason not to just steal it from clojure.core source?

16:40 gfrlog: amalloy: I seriously doubt it. Do you know how that works? i.e., what it parses to?

16:40 I know it initially goes to (require ...) and (use ...)

16:41 I did look at the source some

16:41 what I ended up with wasn't too long...

16:41 fliebel: gfrlog: I'd try macroexpand-all combined with the lisp reader.

16:42 gfrlog: fliebel: the (ns) macro only transforms to direct calls to require and use

16:43 doesn't manipulate the arguments at all

16:43 I guess there might be more macros underneath...

16:43 fliebel: (do (clojure.core/in-ns (quote test)) ((fn* loading__4410__auto__ ([] (. clojure.lang.Var (clojure.core/pushThreadBindings {clojure.lang.Compiler/LOADER (. (. loading__4410__auto__ getClass) getClassLoader)})) (try (clojure.core/refer (quote clojure.core)) (clojure.core/use (quote clojure.set)) (finally (. clojure.lang.Var (clojure.core/popThreadBindings))))))))

16:44 rikva: amalloy: in what way?

16:44 amalloy: (if (> n 1) (test ...) a)

16:44 gfrlog: fliebel: heck that probably works

16:44 thanks

16:45 fliebel: gfrlog: (macroexpand-all (read-string "(ns test (:use clojure.set))"))

16:45 rikva: amalloy: ah wow. Thanks a lot!

16:46 fliebel: gfrlog: What are you trying to achieve?

16:46 amalloy: also rikva, i realize you have a lot on your plate learning a new way of thinking, so feel free to put this off as long as you like, but as a matter of style you don't want ) on their own line. just stack up a load of them in sequence on one line. doing that will also help you stop thinking of (if) as a control-flow statement/block and more as a conditional expression

16:47 gfrlog: fliebel: I'm trying to have several versions of a library loaded at the same time, by transforming the namespace names

16:47 fliebel: amalloy: Good point, I still tend to think of functions and for loops as blocks, while they work perfecly inline.

16:47 gfrlog: so the prefix syntax for (require) and (use) cause a problem for naive string substitution

16:49 amalloy: fliebel: yeah, the number of times i've changed (if foo (myfn a b c d) (myfn a b waffle d)) to (myfn a b (if foo c waffle) d) is surprising

16:50 gfrlog: mmm, waffles...

16:50 amalloy: gfrlog: all my code needs more waffles

16:50 gfrlog: amalloy: lolwaffle.com

16:51 fliebel: amalloy: Hava you read any of those schemer books? they contain a ot of food code. Much better than foo/bar/baz

16:51 amalloy: fliebel: i haven't. i'd like to, but not badly enough to put them in front of all the other reading i'm not doing :P

16:52 fliebel: hm, I forgot to mention the food in my blogpost about it :(

16:52 * fliebel goes editing

16:54 _2x2l: is there a way to get meta-point to work in emacs with clojure, i.e., to auto-manipulate the jar?

16:55 amalloy: _2x2l: it already does work for moving from your source to the library function you use. if you find a way to make it move from one jarred library to another i'll be delighted

16:56 dsantiago: I can't find any docs on what the {:static true} metadata means...

16:56 amalloy: dsantiago: not rebindable

16:56 in 1.3 it's being replaced by {:dynamic true} as the default changes from rebindable to not rebindable

16:56 dsantiago: amalloy Ah, OK, is this related to the new semantics for varS?

16:56 I see.

16:58 rikva: amalloy: thanks!

17:10 arohner: I've got a question. I'm looking for something vaguely hadoop-like, but I'm not exactly sure Hadoop is the right tool for the job. I've got a clojure function that takes a big, nested map (hundreds of thousands of keys), and iterates over a set of possible outcomes, and scores each one. Is hadoop the right tool for parallelizing that on a cluster?

17:12 amalloy: arohner: it doesn't sound like the *wrong* tool, at least. it might depend on what a "set of possible outcomes" is. are you basically processing all the possible ways to walk from the root to any leaf, or something?

17:13 arohner: amalloy: I'm building a DAG from the input dataset, and then scoring each DAG. Then I want to return the DAG with the highest score

17:14 or rather, building all possible DAGs from the input dataset, and scoring them

17:17 amalloy: hm. in that case it's not really clear to me how to partition the task into independent maps and reduces. every DAG will need to work with the whole dataset, you'll just be passing a different parameter like "build DAGs 1024-2047 out of this"

17:18 which sounds like you'll need to subvert a lot of hadoop's intended use-cases. sadly i don't really know a better tool for the job, myself

17:21 arohner: amalloy: right, that was my concern. I think I can make it work, just wanted to make sure I wasn't forgetting about something

17:21 amalloy: arohner: undoubtedly you are forgetting about something, but i don't know what it is either :)

17:52 Null-A: arohner: cascalog

18:09 _2x2l: is there a way to print locals via attaching to a running instance of swank?

18:13 amalloy: _2x2l: check out george jahad's clojure debugging toolkit

18:45 DespiteItAll: hahaha, i wrote a maze generator that kicks out an svg file. Kept making bigger and bigger mazes to see how firefox would take it. It completely froze up on a 250x250 grid

18:46 and the file is 5.5MB

18:54 joshua__: Would it be accurate to say that most functions we work with are multivariate functions?

18:54 arohner: man, lein uberjar is *slow*

18:55 joshua__: as in most functions take more than one variable?

18:55 joshua__: arohner, basically yea

19:07 amalloy: joshua__: probably, but bug brehaut and he'll tell you about currying to turn everything into one-argument functions

19:50 in (reduce (fn [a b] (...do stuff...)) coll), is there a "name" for the anonymous function? i'm calling it the "reductor" to avoid having to write "anonymous reduction function" over and over, but if there's a standard name i'd like to use it

20:45 TimMc: amalloy: "f" :-P

20:49 amalloy: Anyway, are you writing documentation, or an instruction manual, or a blog post or what?

20:49 amalloy: TimMc: blog

20:50 TimMc: In that case, you'll be able to change it easily if you find a better name.

20:51 amalloy: TimMc: sure

20:51 TimMc: Why does it matter that the function is anonymous?

20:51 Or is it just part of that example?

20:51 amalloy: TimMc: it doesn't, i suppose. you're suggesting i could write (reduce (fn some-name [a b] ...))?

20:52 TimMc: Most of the reduce expressions I've written have used a def'd function from elsewhere.

20:52 amalloy: the function can't be a top-level def, because i need it closing around some stuff

20:52 TimMc: That probably means I'm not using reduce enough. >_<

20:52 ah

20:55 amalloy: anyway TimMc i'm done with the text now, just need to do some linking and tidying

21:45 sritchie_: hey all, quick question about a function I'm writing to generate timeseries

21:45 I've got something that I think is pretty clean, but I'm worried that it's inefficient -- I map across the data three times

21:45 https://gist.github.com/845855

21:47 would it be better to sacrifice the second transpose call, and bring it up to the map-indexed step level?

21:52 amalloy: whew, TimMc, writing is so time-consuming. my blog post with an over-the-shoulder view of what I'm thinking as I refine a #clojure function: http://hubpages.com/t/21754f

21:52 * amalloy reminds himself to drop the # next time he pastes from twitter :P

22:25 TimMc: hah, cool

22:25 Interesting point about application logic vs. bookkeeping code.

22:25 amalloy: TimMc: not my original idea, though. i found it in a 1969ish paper about why functional programming is the hot new thing

22:26 TimMc: :-)

22:28 amalloy: TimMc: found it! http://www.stanford.edu/class/cs242/readings/backus.pdf

22:28 clojurebot: #<RuntimeException java.lang.RuntimeException: java.lang.Exception: 503>

22:30 TimMc: Thanks!

22:30 amalloy: 5.1 was the section i was thinking of when i wrote that section

22:31 hiredman: clojurebot has been doing a lot of barfing when some (but not all) URLs are pasted into the channel. any idea why?

22:33 TimMc: http://www.stanford.edu/class/cs242/readings/

22:33 Didn't barf there.

22:34 http://www.stanford.edu/class/cs242/readings/backus.pdf

22:34 Sgeo: TimMc: found it! http://www.stanford.edu/class/cs242/readings/backus.pdf

22:35 TimMc: It sure looks like a 503 Service Unavailable, which would be a transient error if that's what's really going on.

22:35 Sgeo: No barfing?

22:35 TimMc: We need to find a page that always returns a 503 error. :-)

22:36 Sgeo: I know of one!

22:36 TimMc: Could certainly just write one.

22:36 Sgeo: Or, actually, I don't know if it really does it or just displays the custom page for the error that the person put up

22:36 http://zzo38computer.cjb.net/errors/error.php?code=503

22:37 amalloy: Sgeo: it's an actual 503

22:37 TimMc: It really does give a 503, but clojurebot didn't...

22:37 Yeah.

22:37 amalloy: wow Sgeo that's an old page. php 4.4.0

22:38 Sgeo: The person behind that site is a bit.. strange

22:38 amalloy: and apache on windows, i see

22:38 which seems like a weird combo, but who am i to judge

22:38 TimMc: Man, that's great! I can get an HTTP 493 error on command!

22:38 No wait, it's a 500. Drat.

22:38 Sgeo: He wrote a custom IRC client where he types in the PRIVMSG command, iirc

22:38 erm, MSG?

22:39 I forget the IRC protocol now

22:40 sritchie_: more specific question, for anyone interested, about the timeseries question -- https://gist.github.com/845855 -- why is my second version of timeseries lazy?

22:43 amalloy: sritchie_: could you clarify? the simple answer is because map-indexed is lazy and it's your final result, but i don't think that's what you're looking for

22:44 sritchie_: amalloy: sure, sorry about that. I was testing these with (partial nth (timeseries test)), and found that the second version could return an answer immediately, while the first version had to process everything before returning first

22:44 s/first/

22:44 sexpbot: <sritchie_> amalloy: sure, sorry about that. I was testing these with (partial nth (timeseries test)), and found that the second version could return an answer immediately, while the version had to process everything before returning

22:45 sritchie_: amalloy: oh, I see. my transpose method had a wrapping call to vec.

22:45 amalloy: right

22:46 sritchie_: amalloy: I'm finding that the second version is about 20% faster

22:46 amalloy: interesting. i wonder why

22:47 memory usage, maybe? having to alloc a huge block of memory and not free any of it until you've processed all of it may be slowing things down somewhere

22:48 sritchie_: amalloy: even when I take that wrapping call to vec out, it retains the advantage

22:48 Here's how I'm doing my micro-benchmark -- (time (dotimes [n 10] (count (timeseries tester))))

22:48 test-chunks, rather, as defined in the gist

22:49 amalloy: $source cons

22:49 sexpbot: cons is http://is.gd/nKzkPw

22:49 sritchie_: I get about 24 seconds for the first version, 20 for the second

22:49 over multiple runs

22:49 amalloy: i'm thinking your map-indexed call may be lazily consing onto a list without computing the whole list?

22:49 but i dunno

22:51 sritchie_: this is for a hadoop job, so the faster one wins, but the first one describes more clearly what's going on

22:51 interesting stuff

22:53 amalloy: i think it's because the #(vector ...) form has to make a four-element vector, while the second one is consing a single number to the front of a two-element vector

22:54 so the first version requires reconstituting a whole new structure out of four elements, while the first just adds one element to a structure that reuses existing data

22:56 but take that with a grain of salt because i barely understand what you're doing and generally don't deal with the nitty-gritty of performance

22:57 sritchie_: ^, and afk for a bit

22:57 sritchie_: amalloy: no problem, thanks for looking at this! I'm going to goof around with changing the arguments to vector, and see if I can figure it out

22:57 amalloy: that seems like a good approach to thinking about it, though

23:15 jcromartie: is there any solution to printing/reading defrecords?

23:16 amalloy: jcromartie: i think defrecord2 does it for you, and i've seen a couple other solutions on the mailing list. that said, the easiest solution is often to use maps instead of records

23:16 jcromartie: amalloy: you mean to convert to/from maps?

23:17 maybe have a :_recordname key or something

23:17 amalloy: jcromartie: that's a possibility

23:17 talios: You could just seralize to yaml/json etc.

23:18 amalloy: talios: why? serializing to a map will be at least as easy and we're in a lisp

23:19 talios: for the "print" side of things.

23:19 amalloy: talios: (print (into {} my-record-object))

23:19 jcromartie: yeah that's easy enough... now go the other way :P

23:19 amalloy: jcromartie: but serializing to json won't make the other direction any easier

23:20 jcromartie: I wouldn't go to JSON

23:20 the constructor is the problem

23:20 there's no empty constructor

23:20 is there any function that returns the arity of a constructor?

23:20 amalloy: jcromartie: i assume the set of record types is limited?

23:20 jcromartie: yeah I mean it could just be handled in logic

23:22 amalloy: (defmulti build-a-record :_type) (defmethod build-a-record ::person [{:keys [name age]}] (Person. name age))?

23:23 jcromartie: not bad

23:23 amalloy: then (build-a-record {:type ::person :name "dave" :age 30}) should work

23:23 jcromartie: better than what I just came up with :P

23:23 (defn read-car [s] (let [c (Car. nil nil nil) m (read-string s)] (merge c m)))

23:23 (defrecord Car [year make model])

23:24 sattvik: sritchie_: The reason is simple: Vector only creates vectors of up to 4 elements. With more than 4 elements, it uses a lazy vector to provide the rest.

23:24 jcromartie: but what I was thinking was, if you know the arity of the constructor for the record type you can just call that and merge the map

23:24 amalloy: somewhere i have a def-record-with-constructor macro that creates a make-myobj function

23:25 but defrecord2 surely does a better job of it than i did

23:25 sritchie_: sattvik: but my first function doesn't use more than 4

23:25 sattvik: it uses four

23:25 jcromartie: yeah defrecord2 looks good

23:25 it should become defrecord at some point

23:25 amalloy: sattvik: also what you said is false in every way i can think of. vectors are not at all lazy

23:26 sattvik: $source vector

23:26 sexpbot: vector is http://is.gd/rHjtsJ

23:27 sattvik: For more than four args: ([a b c d & args] (. clojure.lang.LazilyPersistentVector (create (cons a (cons b (cons c (cons d args))))))))

23:28 amalloy: sattvik: and have you looked at the source of LazilyPersistentVector()? it's just passing a lazy sequence of arguments to the actual java function that eagerly creates a vector

23:30 jcromartie: well I can get the arity of a record constructor

23:31 (count (.getParameterTypes (first (.getDeclaredConstructors klass))))

23:31 easy enough

23:31 and apply the constructor with the right number of nil args

23:31 sattvik: amalloy: Now that I look at it in detail, you are right.

23:31 jcromartie: so it's slow

23:31 sattvik: My mistake.

23:31 jcromartie: but it works for generic printing and reading of records

23:31 yay

23:32 amalloy: jcromartie: record classes have two constructors. are you *sure* the right one will always be first? i guess it doesn't matter though

23:32 since you're just giving nil args

23:32 jcromartie: yeah

23:33 amalloy: why are you using records to begin with?

23:35 sritchie_: amalloy, sattvik: the only difference between the two is the place where I apply the vector operation

23:36 I think it's slower when map-indexed does the job, than when I put it inside map

23:36 jcromartie: amalloy: why? I dunno, I am just getting into protocols and records

23:36 and this is something interesting

23:36 sritchie_: but that's handwaving, I don't know the source well enough to back that up with any real reason

23:37 amalloy: i mean, this is causing you great pain, so if you're not desperate for performance you can just use hashmaps

23:38 (even if you are desperate for performance, verify that this is the bottleneck)

23:39 jcromartie: yeah I'm not there yet :)

23:40 hash-maps and multimethods would probably be fine

23:40 it's just a data access layer

23:40 basically an interface to a nasty ol' database

23:40 10 years old

23:40 no design

23:40 built mostly in MS Access

23:40 and most of our apps are bolted directly to the database (or at the most through stored procedures)

23:41 amalloy: oh, the irony: clojure 1.2, powered by ms access

23:41 jcromartie: so the goal is to design a "nice" library to access it, and protocols are a good fit because we have lots of methods on various types, and we eventually want to switch the implementation when the interface is solid and there are no apps using the DB directly

23:42 and a RESTful API on top of that for web apps and such

23:42 anyway that's my plan

23:42 amalloy: jcromartie: because calling protocol functions looks just like calling regular functions (or indeed multimethods), you can start simple and bolt on protocols later if it becomes necessary

23:43 no need to change the client api

23:43 jcromartie: good point

23:44 amalloy: i succumbed to records in my first clojure program because i was so used to thinking of things as objects and classes. didn't even have protocols for them

23:44 jcromartie: man I hate OOP for building stuff like this... it's like Clojure makes it so simple that it's not obvious after doing things the OOP way

23:44 :P

23:44 yup

23:44 great minds think (or fail to think) alike

23:44 amalloy: remember what OOP practiced backwards is

23:46 jcromartie: heh

23:46 the thing is, I love Smalltalk to

23:46 too

23:46 OK so here's a generic record print/read

23:46 https://gist.github.com/845906

23:48 (now with docstrings!)

23:48 amalloy: jcromartie: you can make this substantially faster by memoizing the class-name=>base-record function

23:48 jcromartie: true

23:49 amalloy: and (to-array (repeat arity nil)) is fine i guess, but i like (make-array Object arity)

23:50 jcromartie: ah yes that's better

23:51 amalloy: not sure why you're using into in one case, and merge in the other

23:51 they're basically the same

23:51 jcromartie: not sure either

23:52 well merge is for maps, into is generic

23:52 might as well use merge for both

23:52 amalloy: *shrug* i usually use into but it doesn't matter

23:53 jcromartie: I've used merge and merge-with for specific situations before

23:53 can't recall though

23:53 amalloy: sure

23:53 jcromartie: anyway thanks for all the feedback

23:53 amalloy: welcome. i'ma go kill some zombies now, but ping me whenever

Logging service provided by n01se.net