#clojure log - Aug 13 2009

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

0:40 mebaran151: probably better than transcripts would be an introduction to modern Clojure for Schemers

0:42 Chouser: a transcript is more editable than a video presentation -- might be a decent place to start.

1:18 unlink2: Is #(Integer/valueOf %) the standard way to parse integers in clojure?

1:27 andyfingerhut: I don't know of any other way off hand, but I certainly don't know much of what is in all the Clojure libraries yet. It works. Go for it! :-)

1:31 hiredman: ~everyone

1:31 clojurebot: Huh?

2:32 wavister: i'm trying to figure out how to create a collection A that contains a collection B that contains A. any advice? i can do it easily with mutable collections, but that's not ideal

2:33 something like (let [x [y] y [x]] x)

2:38 frodef: completely unrelated, but (let [x [y]] ..) shows an unfortunate aspect of the [] syntax, imho.. the square brackets are (too) overloaded.

2:38 andyfingerhut: I don't think that cycles are possible with immutable data structures like that.

2:39 wavister: not possible? ack... seems not very declarative of clojure

2:39 andyfingerhut: What leads you to want such a cycle?

2:39 Not saying you shouldn't. Just curious.

2:39 wavister: networks that connect both forward and backward

2:40 andyfingerhut: So like x and y are nodes in a graph, with lists of adjacent nodes for each one?

2:40 wavister: yeah

2:41 andyfingerhut: Seems like it should be possible to do that. Thinking...

2:41 Are the nodes just symbols, or some arbitrary data structures?

2:41 wavister: the goal is to avoid creating a top-down map. nodes shouldn't be able to access more than what's next to them

2:42 a node could have other properties, but mostly it's just a collection of it's adjacent nodes. potentially empty

2:42 andyfingerhut: I mean, I've done simple graphs in C/C++ where they could be represented as a vector of nodes, and each node had a vector of nodes adjacent to it, where each nodes was simply an integer

2:44 So a graph with 3 nodes 1, 2, 3, with edges between 1<->2 and 1<->3 would be represented by a vector [nil [2 3] [1] [1]]

2:44 (nil for the non-existent node 0)

2:44 That would represent the edges.

2:44 Other info about nodes or edges would need to be represented elsewhere.

2:44 wavister: yeah, it's the vector of nodes i'm trying to avoid. it's weird, i know. and there might be another way to do what i'm trying to do

2:45 the algorithm should have a node object, and have no access to the rest of the graph except through its neighbors

2:45 andyfingerhut: You're trying to avoid the vector in order to make it easy to arbitrarily add new nodes, without having to assign them a numerical index, or something like that?

2:46 wavister: yeah other nodes could be on other computers possibly

2:47 andyfingerhut: It seems to me like you need some kind of "indirection" to represent this, not via pointers, since you can't have them, but via something like some kind of identifiers for node names.

2:47 Then lists of edges are lists of node names.

2:47 You'd still need to look up those identifiers in some way, in order to traverse the graph.

2:47 i.e. get the edges for the next node in some walk

2:48 That doesn't have to be a vector. It could be a hash, if the node is stored on the local computer. But what would you do if it was stored on another computer? Send it some request over a network and ask for info about that node? Then you definitely need some kind of identifier, I think.

2:49 wavister: yeah, there could be a map that takes nodes as keys and has as values collections of other keys

2:49 andyfingerhut: And a way to know who to ask for info about that node in the graph.

2:50 wavister: yeah there would be a function for getting that other node from wherever it was instead of a reference, so they'd all have to be functions i suppose even if they just always return the same reference

2:50 okay i guess that's how i'll do it

2:52 thanks :)

2:52 andyfingerhut: np

2:53 wavister: oh crap, but the node still has to reference the map of nodes to nodes, which references said node. looks like it has to be mutable

2:54 andyfingerhut: The map of nodes to information about the nodes can be "well known", i.e. like a global thing.

2:54 Is there some kind of security or information hiding you're trying to enforce inside of your program?

2:56 Or you need multiple threads to make updated versions of this graph, and you want it to be possible to parallelize such updates?

2:56 wavister: well not really, to be truthful i'm mostly just playing around with concepts at this point. but i'm hoping it will evolve into something more serious

2:56 yeah it's the latter

2:57 andyfingerhut: I don't know if this will work, but you could try representing nodes as Clojure Refs pointing to information about the nodes.

2:57 Then part of that information could be a vector of other Refs for nodes that are adjacent.

2:58 wavister: i think that might be the way to go

3:01 andyfingerhut: I'd hack up a quick little toy program first to see if that basic idea works at all, or if there is something broken about the idea.

3:03 wavister: doing so :)

3:07 '(let [x (ref []) y (ref [])] (dosync (commute x conj y) (commute y conj x)) x)

3:08 ,(let [x (ref []) y (ref [])] (dosync (commute x conj y) (commute y conj x)) x)

3:08 clojurebot: #<Ref@917cb0: [#<Ref@1913751: [#<Ref@917cb0: [#<Ref@1913751: [#<Ref@917cb0: [#<Ref@1913751: [#<Ref@917cb0: [#<Ref@1913751: [#<Ref@917cb0: [#<Ref@1913751: [#<Ref@917cb0: [#<Ref@1913751: [#<Ref@917cb0: [#<Ref@1913751: [#<Ref@917cb0: [#]>]>]>]>]>]>]>]>]>]>]>]>]>]>]>

3:08 wavister: looks good

3:08 andyfingerhut: We have different esthetics, then :)

3:09 wavister: heh. it should look like you're in one of those bathrooms with big mirrors on both walls...

3:09 andyfingerhut: I know what you mean. It ought to work.

3:10 You'll just want to make your own custom printing functions for debugging :)P

3:10 wavister: lol definitely

3:38 lloy0076: I'm trying to find an idiot's guide to installing the clojure-contrib and seem to see that there's a repository at sourceforge under SVN, one at github and then another group on google code...

3:39 It's possible I'm not looking in the right place for it - I've been staring at the wiki and www.clojure.org and various links and seem to have gotten a .jar from sourceforge...and that has download a heap of stuff in a trunk directory...

3:39 oops, it's not a .jar sorry (forgot to delete)

3:39 hiredman: lloy0076: sourceforge is old

3:39 clojurebot: clojure contrib?

3:39 clojurebot: clojure is the brand

3:39 hiredman: clojurebot: contrib?

3:39 clojurebot: contrib is http://github.com/richhickey/clojure-contrib/tree/master

3:39 lloy0076: Whatever I got, seems to have built.

3:40 Ok, so I should figure out how to download it from github and build it from there?

3:40 hiredman: you don't want it from sourceforge

3:40 sourceforge will be maybe six months out of date

3:40 andyfingerhut: Two most recommended ways would be: get latest clojure and clojure-contrib, both from github, or (2) get 1.0.0 version of Clojure from wherever, and 1.0-compatible version of clojure-contrib from github.

3:41 The latest stuff seems to work fine, and is probably easier to figure out how to get.

3:41 lloy0076: Ok, thanks. I believe I can figure that out - I got a tad confused between the s'forge and github one :)

3:46 @andyfingerhut and @hiredman (and @clojurebot) - thanks - problem fixed!

3:53 angerman_: how is the anatomy of those (with-xxx construct?

3:53 hiredman: eh?

3:54 like with-open?

3:54 angerman_: (def *xxx*) (defn with-xxx [val & body] (binding *xxx* val body)) ?

3:54 andyfingerhut: you mean, how are they implemented?

3:54 angerman_: yes, like that

3:55 andyfingerhut: You can do (use 'clojure.contrib.repl-utils), then (source with-open)

3:55 at the REPL

3:55 Great learning tool.

3:55 hiredman: with-open is basically a let wrapping a try/finally

3:55 angerman_: I have a session object and I'm getting kinda confused with (let [session (get-session)] (to-session session key val) (from-session session key)))

3:56 hiredman: ,(macroexpand '(with-open [a foo] stuf))

3:56 clojurebot: (let* [a foo] (try (clojure.core/with-open [] stuf) (finally (. a clojure.core/close))))

3:57 angerman_: so I'm wondering if I could simplyfy it by having a globaly bound one.

5:13 mikem`_: hi, newbie here. I have a string which I split with clojure.contrib.str-utils2/split, and I would like to assign the results to a map. starting with (split "First Last" #" ") I'd like to end up with {:first "First", :last "Last}.

5:15 clojure: using (source) with vimclojure repl, syntax hi-lighting, is fun ;p

5:17 andyfingerhut: You mean you want the keywords to always match the words split out of the string? That wasn't clear from your example.

5:17 mikem`_: andyfingerhut: yeah, ambiguous. let's try "Bob Smith" -> {:first "Bob", :last "Smith"}

5:18 the keys are predetermined and constant, I'm just filling in the map from a string

5:19 andyfingerhut: Getting there. Just having trouble with my home REPL to test out the return value of split

5:19 Don't recall it off top of my head.

5:19 mikem`_: andyfingerhut: apparently the return value of split is clojure.lang.ArraySeq which cannot be cast to clojure.lang.IPersistentStack (ie: pop won't work on it)

5:20 talios: you could (seq (split ...)) thou?

5:20 I think

5:20 andyfingerhut: Try something like (let [[first last] (split ...)] {:first first :last last})

5:21 Not sure if you've seen destructuring before, but the extra [] around first last mean to treat the (split ...) return value as a sequence, and take the first element and bind it to first, and the second and bind it to last.

5:22 arbscht: ,(doc zipmap)

5:22 clojurebot: "([keys vals]); Returns a map with the keys mapped to the corresponding vals."

5:22 andyfingerhut: Using the names first, last might lead to confusion in larger examples, given that those are also the names of commonly used functions (at least first is)

5:22 arbscht: ,(zipmap [:first :last] ["Bob" "Smith"])

5:22 clojurebot: {:last "Smith", :first "Bob"}

5:23 mikem`_: andyfingerhut: ok, cool, that works :)

5:24 arbscht: thanks for that :)

5:25 ok, this works. but let's say I wanted to process each of "Bob" and "Smith" by passing it to some arbitrary function. how do I get it out of an ArraySeq?

5:26 andyfingerhut: The let form I showed is one way.

5:26 talios: ,(doc seq)

5:26 clojurebot: "([coll]); Returns a seq on the collection. If the collection is empty, returns nil. (seq nil) returns nil. seq also works on Strings, native Java arrays (of reference types) and any objects that implement Iterable."

5:26 mikem`_: hm, I guess functions first will get me the first

5:26 andyfingerhut: Another is to do something like (let [a (split ...)] expression using (a 0) to get first element of a, and (a 1) to get second )

5:27 Hmm. Actually that is only if the return value of (split ...) is a vector, I think.

5:27 talios: ,(seq (split "hello world"))

5:27 clojurebot: java.lang.Exception: Unable to resolve symbol: split in this context

5:27 talios: doh

5:28 andyfingerhut: (nth 0 a) will work for more kinds of things.

5:33 mikem`_: talios: can clojurebot pull in methods from clojure.contrib?

5:33 ,(seq (clojure.contrib.str-utils2/split "hello world"))

5:33 clojurebot: java.lang.ClassNotFoundException: clojure.contrib.str-utils2

5:33 talios: I guess not :(

5:33 mikem`_: ,(seq ('clojure.contrib.str-utils2/split "hello world"))

5:33 clojurebot: nil

5:34 andyfingerhut: ,(use 'clojure.contrib.str-utils2)

5:34 clojurebot: java.io.FileNotFoundException: Could not locate clojure/contrib/str_utils2__init.class or clojure/contrib/str_utils2.clj on classpath:

5:34 talios: I can't remember who runs clojurebot either

5:34 mikem`_: ,('clojure.contrib.str-utils2/split "hello world")

5:34 clojurebot: nil

5:34 mikem`_: ,('clojure.contrib.str-utils2/split "hello world" #" ")

5:34 clojurebot: #" "

5:35 tomoj: what do symbols do as functions?

5:36 mikem`_: ,(clojure.contrib.str-utils2/split "hello world" #" ")

5:36 clojurebot: java.lang.ClassNotFoundException: clojure.contrib.str-utils2

5:36 talios: ,(use 'clojure.contrib.str-utils)

5:36 clojurebot: nil

5:36 talios: ,(re-split #" " "Hello World")

5:36 clojurebot: ("Hello" "World")

5:36 talios: regex win :)

5:37 tomoj: oh, just like keywords

5:38 talios: a symbol is a function that takes a map as an arg

5:38 and a map is a function that takes a symbol

5:38 kinda weird, but neat :)

5:38 tomoj: yeah, I knew keywords did that

5:38 didn't know symbols did too

5:38 also didn't know they took two args

5:39 ,('foo {} 3)

5:39 clojurebot: 3

5:40 andyfingerhut: I wonder what kinds of resource limits are on clojurebot, if any? Not that I want to crash it or make this channel unusable, mind you, just curious :)

5:41 talios: forkbomb!

5:41 tomoj: (require '[clojure.contrib.str-utils2 :as s2])

5:41 ,(require '[clojure.contrib.str-utils2 :as s2])

5:41 clojurebot: java.io.FileNotFoundException: Could not locate clojure/contrib/str_utils2__init.class or clojure/contrib/str_utils2.clj on classpath:

5:41 andyfingerhut: I did that once, on a shared server at my college. The sysadmin kicked me off that system for months.

5:41 tomoj: it's in a sandbox

5:41 dunno what all it does

5:43 arbscht: clojurebot is hiredman's creature

5:43 clojurebot: clojurebot

5:43 clojurebot: clojurebot is like life: you make trade-offs

5:43 tomoj: 10 second timeout looks like

5:44 'Thread. is in a commented-out blacklist, but not the uncommented blacklist on github

5:47 "Naked Singularity" wtf?

5:47 clojurebot works with black holes?

5:49 andyfingerhut: Are you looking at clojurebot's list of patterns and canned replies?

5:49 tomoj: nope

5:50 hiredman.horizon

5:50 git b75cdb8b61e0fd4e83934e29d5ddaf78296ba7a7

5:51 tomoj: git b75cdb8b61e0fd4e83934e29d5ddaf78296ba7a7

5:51 :(

6:11 ole3: hi, how do i cast an Intger to an int?

6:11 cark: ,(int 3)

6:11 clojurebot: 3

6:11 opqdonut: :t fromIntegral

6:11 woops, thought i was in #haskell

6:11 sorry

6:11 i'll get my coat

6:11 tomoj: hmm

6:12 isn't an Integer already an int?

6:12 ,(class 3)

6:12 clojurebot: java.lang.Integer

6:12 cark: Integer is the boxed int

6:12 opqdonut: ,(class (int 1))

6:12 clojurebot: java.lang.Integer

6:12 tomoj: it gets boxed when you ask for its class?

6:12 opqdonut: yeah, probably

6:12 cark: yes

6:12 andyfingerhut: It gets boxed on every fn call.

6:12 so I've heard, anyway.

6:13 opqdonut: yeah, we need primitive type annotations

6:13 tomoj: well, anyway, there's no reason to cast, right?

6:13 opqdonut: well performance

6:13 (loop [i (int 0)] ...)

6:13 andyfingerhut: The primitive type annotations work fine within a loop/recur, inside of one function, but yeah, it would be nice if they could work across function boundaries, too.

6:14 cark: tht would be a gret performance boost

6:14 +a +a

6:16 ole3: thank you

6:20 tomoj: opqdonut: I don't get it

6:20 oh, yes I do

6:20 opqdonut: :D

6:21 andyfingerhut: Is it still funny if you have to explain it to someone?

6:27 Chousuke: I think Rich is planning on allowing longs and doubles as function parameters (and probably as return values too)

7:12 ChrisPS: Whenever I do something in the repl and get an error message (inside emacs), I am always returned something like: java.lang.ClassCastException: java.lang.Integer (NO_SOURCE_FILE:0)

7:13 this NO_SOURCE_FILE, I would love to have that work

7:13 can someone point a flashlight in front of my face?

7:14 * ChrisPS is lurking

7:15 cark: of you program in files and then load them, you should get a line number

7:16 of/if

7:16 tomoj: ChrisPS: C-c C-k

7:16 ChrisPS: tomoj: what?

7:16 compile?

7:18 tomoj: yep

7:18 unfortunately it can only compile the entire file

7:18 so.. everything has to work

7:19 ChrisPS: cark: that is the odd thing

7:22 my compile is working just fine

7:25 tomoj: after C-c C-k you still get NO_SOURCE_FILE ?

7:29 ChrisPS: tomoj: right!

7:30 mind you, I am a java noob

7:32 so I might have some problems wrt source-file ref. etc.

7:32 but everything else is working just fine (except for word-completion, but I think this is related...)?

7:33 that's my analysis anyway

7:45 tomoj: oh hmm

7:45 I just got NO_SOURCE_FILE too

7:45 ChrisPS: hehe, see

7:46 * ChrisPS approximately 899483 hours left (until spotlight has indexed my disk)

7:47 tomoj: oh wait

7:47 nvm

7:47 I don't get NO_SOURCE_FILE

7:47 it depends on where the error is

7:48 if the error is in the line you type into emacs, then you'll get NO_SOURCE_FILE

7:48 if the error occurs inside a compiled function, you should see the filename and line number

7:48 ChrisPS: I have yet to see this, but ok for now

7:49 tomoj: do like (defn foo [] (map 1))

7:49 ChrisPS: usually when things blowup because of an exception or something, it responds with a NO_SOURCE_FILE:0

7:49 tomoj: when you C-c C-k, you should get a big stacktrace

7:49 well, compile, then call (foo)

7:50 somewhere down on the stacktrace you should see your filename

7:50 ChrisPS: user=> (foo)

7:50 java.lang.IllegalArgumentException: Wrong number of args passed to: core$map (NO_SOURCE_FILE:0)

7:50 user=>

7:50 :-)

7:50 tomoj: uhh

7:50 something's wrong with your slime setup

7:51 ChrisPS: I guess :-/

7:51 tomoj: you should get restarts with a full backtrace

7:51 ChrisPS: I always thought something was missing, since I did not see the Smalltalk effect

7:51 tomoj: what is "the smalltalk effect" ?

7:52 opqdonut: ChrisPS: use stacktrace

7:52 clojure.contrib.stacktrace

7:52 ChrisPS: the: instaneosly everything now, effect

7:52 opqdonut: see the docs

7:52 ChrisPS: opqdonut: ok

7:52 tomoj: but... it should do that by default

7:52 ChrisPS: you did clojure-install?

7:53 ChrisPS: tomoj: not recently

7:53 tomoj: maybe you need to update clojure-mode?

7:53 ChrisPS: what is the easiest path

7:54 tomoj: I did emacs-starter-kit, install clojure-mode from elpa, then M-x clojure-install

7:54 (well.. but then I deleted elpa clojure-mode since the clojure-test-mode from elpa still uses clojure.contrib.test-is)

7:54 ChrisPS: I've spent so much time reconfiguring emacs, that yeah, perhaps something got lost on the way

7:55 regarding the stacktrace thing, when I (use it), I get a ClassNotFoundException etc...

7:55 java.lang.ClassNotFoundException: clojure.contrib.stacktrace (NO_SOURCE_FILE:78)

7:55 but what is this? a NUMBER??

7:55 tomoj: you have to require it

7:55 ChrisPS: ok

7:56 (require 'clojure.contrib.stacktrace)

7:57 * ChrisPS will look at the stacktrace docs

7:57 tomoj: that's funny, I don't see a clojure.contrib.stacktrace

8:01 ChrisPS: neither do I

8:02 tomoj: I'd just try starting with a fresh clojure-mode

8:02 ChrisPS: I think so too

8:02 Chousuke: hm

8:02 I don't see .stacktrace either.

8:03 ... I'm sure it was there. :P

8:03 ChrisPS: mkaay

8:04 Chousuke: heh.

8:05 I see a clojure.stacktrace

8:05 :P

8:06 apparently it was moved over when .test was, too

8:10 cark: I'm trying to use memcached with clojure, it's a problem that the data structures are not serializable

8:11 so in the meantime i'm printing these to a string and reading these from the string returned by memcached

8:11 but it's slower

8:11 so that defeats the purpose =/

8:12 i understand the problem about serialization, how to serialize an infinite sequence ...

8:12 but still that does not help =(

8:13 Fossi: i thought the persistent datascructures implement serializable

8:13 cark: i could not serialize (range 1 100)

8:14 Fossi: tried (vec (range 1 100))?

8:14 cark: but i'm a total noob when it's about java serialization

8:14 yes that works

8:14 Fossi: i think you have to realize lazy things (naturally)

8:14 tomoj: (range 1 100) is a lazy seq

8:14 which has the problem you just mentions

8:14 cark: right, but then i don't have a "universal" memcached serialization

8:15 Fossi: well, maybe only convert to string (or other token) if it's lazy

8:15 then again, almost everything tends to be lazy :D

8:15 cark: if i need to walk the data structures i'll be as slow as the printer

8:16 tomoj: I don't get it, what's the problem with realizing before serializing?

8:16 Fossi: i'm having a similar inherent problem with exception handling

8:16 cark: you mean with lazy sequences ?

8:18 Fossi: cark: seen http://groups.google.com/group/clojure/browse_thread/thread/e704414cf36ef2aa?pli=1 ?

8:19 rich suggests print/read too

8:19 cark: mhhh let me read that =)

8:19 tomoj: I don't think it's gonna help much

8:19 most of the solutions involve serializing to some string form

8:19 Fossi: and and there is rarely anything else you can do

8:20 tomoj: what's missing serialization that needs it?

8:20 ohh.. PersistentHashMap is, but Keyword isn't

8:21 Fossi: tomoj: well imho it's just the tradeoff of realizing your whole deep datastructure, against serializing to string

8:21 a combination would be nifty (but impossible?)

8:21 tomoj: you have to realize the whole structure to serialize to string anyway, right?

8:21 cark: looks like i'm stuck with printing/reding

8:22 Fossi: well, you could try to keep lazy seqs and delay realizing them to read time

8:22 cark: there is still the problem with keywords ...

8:22 tomoj: huh?

8:23 cark: keywords are not serializable either

8:23 tomoj: how can you write a lazy seq to a string without realizing the whole thing?

8:23 Fossi: with exceptions a similar problem is to check for exceptions during realization, but also being able to stream the datastructure from jetty or such

8:24 tomoj: don't know, just a thought. kinda keeping the function call around

8:24 so serializing "(range 1 100)" instead of "1 2 3 4 ..."

8:25 anyway, it has lot's of weird implications and prolly won't make sense in 99.9% of all cases

8:25 tomoj: yeah, guess that would work if it was pure

8:26 Fossi: would make one hell of a serializing framework thought if it would work

8:26 i don't have a good solution for the exception problem yet

8:27 it would be so nice if the exception handling would be "carried over"

8:27 cark: Fossi : you couldn't do it without language support

8:27 Fossi: but it's also *really* weird

8:27 tomoj: what exactly are you trying to do?

8:28 cark: yeah some kind of super-dynamic vars, these would be carried by the environement of the lazy closures

8:28 Fossi: tomoj: the use-case i had was in composure: i want to wrap every function i call in try/catch to not throw an exception at the user

8:28 but i also might want to lazily stream things

8:29 tomoj: guess I don't know enough to understand why that's a problem

8:29 oh, yeah, I see

8:29 cark: that wouldn't work as you might send the first part of your page, then get the error while realizing the sequence deep in your tree

8:29 Fossi: cdomposure doesn't let me set an exception handler for realization time

8:30 so it realizes a function and one of my inner functions bails

8:30 tomoj: you _could_ do it in each part of the lazy seq, right?

8:30 but I imagine that would be slow

8:30 Fossi: tomoj: yes, that would make quite some places to add try catch as well

8:31 cark: exactly

8:32 anywaz, it's more off an enhancement to composure really in this case

8:32 but it felt weird when i discovered it

8:33 and it's not really obvious that try catch doesn't work for lazy seqs

8:33 especially since you (unknowingly) create/use them all the time

8:33 tomoj: so maybe compojure can try/catch while it's consuming?

8:33 Fossi: tomoj: yes, that's what i meant above

8:33 and let me provide a handler

8:34 tomoj: I've been thinking about compojure lately

8:34 it's very unopinionated

8:34 cark: i wouldn't say that

8:35 it tries very hard to avoid state

8:35 bit too much in my opinion

8:35 tomoj: well, that's part of the clojure territory I think

8:35 I mean compared to, say, rails

8:35 there are no opinions about how to structure your app really

8:35 cark: true

8:35 tomoj: which gives me the problem of designing such a structure :/

8:35 Fossi: yeah

8:36 there are several aproaches as well

8:36 tomoj: I think my experience with rails is probably limiting my imagination

8:36 Chousuke: on the other hand, if you come up with a good design, you can make a framework on top of compojure that supports that design

8:36 Fossi: but actually i like compojure for not imposing a structure on me

8:36 tomoj: yeah, it's nice

8:37 Fossi: and i think the state handling is kinda ok as well

8:37 tomoj: guess compojure is sort of the equivalent of rack

8:37 Fossi: the request usage is a like awkward, but then again, that's more or less the only place one of our whole projects has a state

8:38 can't do much else for the user session

8:38 eevar2: tomoj: neh. compojure is built on top of ring, which afaik is the equivalent to rack

8:38 Fossi: compojure is very cl-who'ish

8:38 tomoj: ok, so maybe compojure is half-way between rack and rails :)

8:38 Fossi: and it kinda just works ;)

8:39 tomoj: but I think in terms of like defcontroller, defaction, render, bindings over render for view variables, helper functions etc

8:39 I think these concepts from rails are probably limiting me

8:39 Fossi: i dislike defserver etc for making me restart jetty :(

8:39 tomoj: wonder if I can find some apps written in compojure on github...

8:40 eevar2: i've rewritten all my compojure apps a gazillion times w/o coming up with a design i'm happy with

8:40 Fossi: especially because i have to restart slime then because my layout is too dumb

8:40 eevar2: s/all/both ;)

8:42 tomoj: Fossi: hum?

8:42 you mean layout like html layout?

8:42 I found I could just recompile my handlers without even restarting jetty and changes would happen

8:42 but I just did a trivial hello world

8:43 Fossi: no, my clojure file

8:43 if you defserver, the old server variable is gone

8:43 but you need it to stop the jetty

8:43 cark: use multiple file, one that initialize your server, and another one for routes/implementation

8:43 tomoj: ah, I see

8:43 Fossi: but using def*, you need to recompile to get the changes

8:44 tomoj: what do you think about autoloading files like rails does?

8:44 Fossi: so if you forget to stop the jetty before compiling, you have to restart slime. at least that's the easiest way to get rid of the process i've found so far

8:44 cark: i just handed out a fairly large compojure application to a customer, and only seldom had to restart the whole thing during developement

8:44 Fossi: tomoj: well, you can recompile almost everything

8:44 just not the defs

8:45 tomoj: def..whats?

8:45 Fossi: route being the most common case

8:45 defserver, defaction, defroutes etc

8:45 tomoj: ah

8:45 do they generate anonymous functions or what?

8:46 Fossi: no, they call def, creating a var

8:47 well, they also create a heap of anonymous functions, but that's not the problem

8:47 tomoj: but if the var has the same name, wouldn't the def just overwrite the old value?

8:47 just like recompiling defn does?

8:49 Fossi: for defserver, you loose the reference to the server then, but it still runs

8:49 tomoj: yeah that one makes sense to me

8:49 Fossi: for defroutes there was similar problem. let me look

8:49 tomoj: actually...

8:49 I did it with defroutes and had no problem

8:50 at least I thought I did

8:50 Fossi: yeah, ok, that problem is more on our side of the code

8:50 we have two defroutes, one using the other

8:50 tomoj: ah I see

8:50 Fossi: and the secondary doesn't get reread

8:51 and the primary is in the same file as the defserver call ;)

8:51 so it prolly would work, if i didn't use C-c C-k

8:51 and compiled everything needed seperately

9:58 it's really funny: i just realized that most of the code i've recently written in javascript is functional

9:58 and i document or mark the few occasions of global state explicitly

9:59 makes me wonder how much of that habit will carry over to java

10:27 ole3: hello, is it possible to do bitwise or in clojure?

10:28 cark: ,(doc bit-or)

10:28 clojurebot: "([x y]); Bitwise or"

10:28 ole3: thank you

10:30 hm, bitwise or of n arguments where n is greater 2?

10:31 ah... (reduce bit-or args)

10:31 cark: ,(reduce bit-or 0 [1 3 7]) ?

10:31 clojurebot: 7

10:32 ole3: :)

10:32 cark: i was too slow i guess =)

11:02 Chousuke: heh, I forgot Clojure pattern literals don't need to escape \

11:03 Got a bit confusing when the pattern that I copied verbatim from LispReader source wasn't matching my floats :P

12:21 cemerick: ~max

12:21 clojurebot: max people is 164

13:08 m3lling: Anyone here a fan of StackOverFlow.com?

13:08 I'm trying to get people to gather small Clojure examples into a question that I asked.

13:08 http://stackoverflow.com/questions/1261557/whats-the-most-useful-thing-youve-done-in-less-than-50-lines-of-clojure

13:09 Put a 250 point bounty on it.

13:13 technomancy: m3llingl: personally I'm still trying to get over the idea of using a web application built in ASP.NET. apart from that it seems decent. =)

13:18 cark: technomancy : there might be more of these than you might think

13:18 lots of intranets i guess

13:19 technomancy: cark: well specifically for a web app targeted towards programmers. I'm sure there's plenty of news sites etc. that use it.

13:19 cark: well .net programmers are programmers too

13:20 and i woud say they have much merit =)

13:20 technomancy: cark: Stack Overflow is the first community I've seen that has much overlap between Windows devs and the rest of the world.

13:22 cark: true

13:22 same goes for java

13:22 it really on it's own planet

13:22 cemerick: it's a huge improvement for people that generally don't have a high-quality community (e.g. asking Java questions in Java-focussed forums is *really* painful)

13:25 cark: but is really stackoverflow ASP.net ? or just .net somehow connected to the web ?

13:27 ok yes it is

13:36 jweiss_: how come when i call load-file, a java class i refer to in that file (inside a defn) is being instantiated, its static initializer fails because it's being called too early, i want it to wait until i actually call the function

13:38 cark: maybe you have some code calling that function in your file ?

13:38 try adding a print statement and see how it goes

13:38 jweiss_: cark: no, i don't call the function anywhere

13:39 cark: would you care showing the code of this function ?

13:39 jweiss_: cark ok

13:40 cark, what paste website do you guys use

13:41 cark: clojurebot: paster?

13:41 clojurebot: Gabh mo leithscéal?

13:41 cark: clojurebot: paste?

13:41 clojurebot: lisppaste8, url

13:41 lisppaste8: To use the lisppaste bot, visit http://paste.lisp.org/new/clojure and enter your paste.

13:41 technomancy: you know what I could really use? an introduction to the quirks of the JVM that isn't written for a Java programmer.

13:42 lisppaste8: jweiss_ pasted "untitled" at http://paste.lisp.org/display/85329

13:42 technomancy: I have no idea how properties files are used, and I keep running into problems from multiple classloaders that confuse me.

13:42 anyone know of an article like that?

13:42 jweiss_: cark ^^

13:43 oh um i think i get it, it's because i used def

13:43 i thought if i used it inside a function it wouldn't get called until runtime?

13:43 how do i create a reference to this java object that i can refer to throughout this file?

13:44 (at runtime)

13:45 cark: right

13:45 you don't use def inside a function

13:45 jweiss_: cark: what is the right way

13:45 cark: use let

13:45 jweiss_: cark, but i want to be able to refer to this instance in other functions

13:45 cark: (let [test-script TestScript.)] ..use it here)

13:46 jweiss_: let is local

13:46 cark: allright

13:46 put a (def test-script (atom (TestScript.))) outside the function then

13:46 but you said you don't want it to be instanciated early

13:46 jweiss_: cark, but i don't want it to run at load time

13:47 right

13:47 cark: so you (def test-script (atom nil))

13:47 then when you want to instanciate it (reset! test-script TestScript.)

13:47 but

13:47 that's the wrong way to go about doing this kind of stuff

13:48 not very idomatic

13:48 not very functional

13:48 jweiss_: cark: yeah, i am looking for the idiomatic way

13:48 i know its not functional, but i'm stuck with this java class

13:48 that has methods i need to call

13:48 cark: i don't quite know about selenium

13:48 but usually you want to have a clojure function that will return a result

13:49 so you can create your java objects in a let

13:49 and pass these along

13:49 jweiss_: i don't want to create a new instance in every function call

13:50 cark: well at some point you have a top-level state object, with all the state of your program

13:50 jweiss_: yeah, that's this testscript object

13:50 cark: you can pass the script object already created to all your functions

13:50 jweiss_: using the atom, reset! stuff you mean?

13:50 oh i see

13:50 Chousuke: use refs for state

13:51 cark: well if it's a top level object, it's ok to use the atom stuff

13:51 Chousuke: refs are designed so that the value they reference varies over time, with well-defined semantics for how the reference changes.

13:52 atoms can change at any time, without any coordination

13:52 jweiss_: Chousuke: i'm just looking to set this once, and never change it

13:52 but i don't want to set it at load time, rather at run time

13:52 cark: Chousuke : you don't want to manipulate a java object in a dosync

13:53 Chouser: jweiss_: sounds like a good job for an atom

13:53 Chousuke: an atom might be okay. or a function that returns a singleton.

13:53 ie. inits on first call, returns the object on subsequent calls.

13:53 jweiss_: Chouser: ok, i'll give that a shot. Chousuke: how do you return a singleton in clojure

13:53 Chousuke: oh i see

13:54 Chousuke: I think you would usually use a local atom for that though :P

13:54 cark: global state is evil !

13:54 Chousuke: but at least it would be local, so no evil user could go and change it.

13:54 Chouser: yeah, that's even better. close over an atom with a singleton-access fn

13:55 Chousuke: cark: global coordinated references to immutable values are not :)

13:55 oh, the language has become sentient!

13:55 Chouser: (let [thing (atom nil)] (defn get-thing [] ...))

13:55 * Chousuke runs

13:55 clojure: (fear)

13:56 Chouser: maybe it's just recursion. clojure has joined #clojure has joined ##clojure...

13:57 cark: Chousuke : agreed, though it's best to have as little of that as possible

13:57 jweiss_: ok so i changed it to an atom that i reset! in my function. still get java.lang.ExceptionInInitializerError (console.clj:0)

13:57 when i load it in the repl

13:58 cark: show us the new code =P

13:58 probably a little oversight

13:58 lisppaste8: jweiss_ pasted "untitled" at http://paste.lisp.org/display/85330

13:59 jweiss: how do i get it to colorize properly

13:59 cark: well i'm positive that this is not run on load =/

14:00 jweiss: cark: remember, it's the static initializer that's being run

14:00 so maybe it runs on import?

14:00 stuartsierra: The compiler might run the static class initializer when the class is first referenced.

14:00 jweiss: i thought that only ran when you create an instance of the class... but maybe it's even earlier, when the class is loaded?

14:01 i guess i should look this up

14:01 cark: maybe some magic hapenning in the imported name spaces

14:01 jweiss: yep, "you can also write static initializer blocks to initialize static variables when the class is loaded."

14:02 well, i am gonna have to do some work to move that code out of the java class's initializer block

14:02 and into somewhere where it runs later

14:17 technomancy: OK, I'm pretty stumped about this. I'm trying to set some properties for the jets3t library. Dropping a jets3t.properties file in the classpath seems to have no effect according to System/getProperty.

14:17 first of all, is that a good way to check for properties?

14:18 I mean, are library-specific properties going to be present as system properties, or will they be loaded elsewhere?

14:19 lrenn: technomancy: just dropping the properties files won't add them to the System properties.

14:19 brool: I think you need to load them explicitly, don't you?

14:20 lrenn: http://java.sun.com/j2se/1.4.2/docs/api/java/util/Properties.html

14:20 brool: http://www.factorypattern.com/how-to-readwrite-java-properties-files/

14:22 technomancy: lrenn: right, but the jets3t library should be loading them

14:22 sorry, should have mentioned that

14:22 http://jets3t.s3.amazonaws.com/toolkit/configuration.html doesn't say where the file goes, but in the root of a dir on the classpath is pretty standard

14:22 right?

14:25 lrenn: technomancy: right. But I don't think checking System/getProperty is a test to see if they got loaded.

14:25 technomancy: OK, I'm just not sure what the conventions are here. I guess jets3t should expose its own Properties object somehow?

14:26 stuartsierra: technomancy: yes

14:26 jweiss: can we use the .. macro to call java like this: testscript.getTasks.createUser("blah") - where the last call has args?

14:27 stuartsierra: jweiss: yes: (.. testscript getTasks (createUser "blah"))

14:28 jweiss: stuartsierra: thanks

14:30 Chouser: or (-> testscript .getTasks (.createUser "blah"))

14:31 lrenn: technomancy: https://jets3t.dev.java.net/source/browse/jets3t/src/org/jets3t/service/Jets3tProperties.java?rev=1.18&view=markup

14:32 technomancy: lrenn: right; I can construct my own jets3t properties object by passing in a filename

14:33 but if I don't know what filename it's going to use by default, that's not going to help

14:33 I need a way to grab the properties object that's currently in use.

14:33 lrenn: technomancy: http://jets3t.s3.amazonaws.com/api/org/jets3t/service/Jets3tProperties.html

14:34 technomancy: You already know the filename it's going to use by default.

14:36 technomancy: lrenn: ah... I see. it wasn't working with "/jets3t.properties", but removing the initial slash fixed it.

14:36 go figure

14:39 Anniepoo: has anybody written a little swing GUI repl you can embed in a clojure app for debugging?

14:39 technomancy: now to throw hadoop into the mix and watch it all explode. =\

14:46 stuartsierra: technomancy: but it will explode in parallel!

14:46 Chouser: Anniepoo: I have one in my "textjure" project.

14:46 jweiss: anyone know an existing fn to convert camel case to lisp case?

14:46 Chouser: In fact, that's about all it is so far. Though not designed to be embedded in another app, I wouldn't expect it to be too difficult.

14:46 technomancy: stuartsierra: I can now have twenty cores all ignoring my properties file at once! can't say that's not progress.

14:47 stuartsierra: oh yeah

14:47 technomancy: stuartsierra: do you use s3 with hadoop at all?

14:48 stuartsierra: A little, mostly just copying stuff between S3 and HDFS.

14:48 technomancy: yeah, I'm distcping stuff over to S3 and getting lots of BS "Response '/packed' - Unexpected response code 404, expected 200" warnings without any actual errors.

14:48 crazy stuff. =\

14:49 stuartsierra: Yeah, it'll do that, but distcp retries on error.

14:49 technomancy: it's causing the mappers to fail for me.

14:49 so I'm trying to increase the retry limit

14:50 oh! I think I got it. I need to export HADOOP_CLASSPATH to a dir that has the jets3t.properties file in it

14:50 b4taylor: I think I've asked a few times but a better solution was always found so I never needed it, but can I give a type hint saying that something is an arry of doubles or something?

14:50 I just get back a 2d array of Objects.

14:50 technomancy: putting it in conf/ alone doesn't cut it

14:50 stuartsierra: technomancy: yes

14:50 b4taylor: Which may not be a problem, but I'd rather see Double[][] from my (into-array-2d foo)

14:51 stuartsierra: Also, the Hadoop JARs include a copy of JetS3t, which may have its own properties file.

14:52 lrenn: technomancy: are you doing this from the repl/slime with your clojure-project?

14:52 technomancy: lrenn: no, hadoop must be run from the shell

14:52 it's very tedious

14:53 stuartsierra: You can run it via the API, but it's not well-documented. I've never figured it out.

14:54 technomancy: stuartsierra: we've got that working, but it's so different from distributed mode that it's nearly useless for debugging real issues

14:54 I mean, if you've already got your code factored out sanely

14:55 write as much as you can in regular clojure interactive slime style, and then go to slow batch processing for figuring out all the crazy hadoop quirks

14:56 stuartsierra: Right, that's what I tried to implement in my clojure-hadoop library.

14:56 technomancy: the problem with Clojure/FP is that the interesting problems get solved so easily that you end up spending all your time on the boring infrastructure BS like this.

14:56 Chousuke: heheh

14:56 stuartsierra: I think that's true of programming in general.

14:56 clojurebot: that is not what I wanted

14:57 technomancy: stuartsierra: it's just more noticeable when your language is more streamlined

14:58 stuartsierra: yes

14:58 jweiss: what is the significance of # in task#, in this line: (let [task# (apply instantiate-task ant-project ~(name ant-name) props#)]

14:58 is it just part of the name?

14:58 stuartsierra: I'm suffering through WSDL right now.

14:59 technomancy: stuartsierra: my condolances

14:59 Chousuke: I wonder if it'll be a problem for my reader that it might consume more from a stream that it needs to read a single object :/

15:00 technomancy: Chousuke: that's why you need a PushbackReader IIRC

15:00 in the current implementation

15:00 Chousuke: technomancy: yeah, but my current reader design doesn't work with anything stateful.

15:00 it just wants a seq of lines.

15:00 technomancy: gotcha

15:02 Chousuke: it shouldn't be too difficult to "push back" any leftover stuff after a read has been completed though.

15:03 but then it would complicate the line numbering ;/

15:05 Anniepoo: What's not to like about a language you already like, when you're stuck in a long debug cycle, and you realize instead of wishing for a debugger you could HAVE one.

15:06 Chousuke: I suppose the reader could claim ownership of the stream and then any operations on the reader input the user might want to do should be on the (immutable) reader data structure.

15:06 Anniepoo: 11:35 I start writing one - 11:40 I realize undoubtedly one exists and ask, 11:47 Chouser suggests where to get one, 11:53I notice his message, but mine's done already

15:16 b4taylor: Do you know a sane way to get a 2d array of doubles?

15:16 argh

15:16 Chousuke: Do you know a sane way to get a 2d array of doubles.

15:19 Chousuke: I avoid arrays in Clojure code to the best of my ability :P

15:19 b4taylor: Unfortunately I'm interfacing to a matrix library :p

15:19 I suppose I could just write a pure clojure library.

15:20 I doubt it would be slower, and I just need the basic operations. I don't need solving or anything.

15:20 stuartsierra: ,(make-array Double/TYPE 3 5)

15:20 clojurebot: #<double[][] [[D@1d433c1>

15:20 b4taylor: Ahha.

15:21 Then I just have to copy the data over.

15:21 stuartsierra: I'll play with this. Thanks.

15:21 stuartsierra: np

15:23 b4taylor: Also, I suppose I should ask for a good lisp macro how-to before I ask for a clojure one.

15:25 lrenn: jweiss: it generates a unique symbol.

15:25 jweiss: lrenn: thanks

15:28 lrenn: http://clojure.org/macros is pretty sparse.

15:36 jweiss: can someone tell me whats wrong w this macro (trying to defn a function that is just a wrapper for a java method, using memfn):

15:36 (defmacro define-task [task-name]

15:36 `(def ~task-name (memfn (.. @testscript getTasks ~task-name))))

15:36 i get java.lang.IllegalArgumentException: Malformed member expression (repl-1:15)

15:38 stuartsierra: memfn only works on isolated symbols

15:38 andyfingerhut: If you want lots of examples and discussion of macros, book length, then Paul Graham's On Lisp is a Common Lisp specific book on them, but a lot of them translate well to Clojure. http://www.paulgraham.com/onlisp.html Probably more than you want right now, though :)

15:39 cemerick: isn't memfn long deprecated at this point (by #()?)

15:39 jweiss: cemerick: it's still in the Programming Clojure book

15:39 cemerick: ah

15:39 stuartsierra: ,(defmacro define-task [name] `(defn ~name [script#] (.. script# getTasks ~name)))

15:39 clojurebot: DENIED

15:40 jweiss: stuartsierra: thanks

15:40 Chousuke: it's not deprecated I guess but I don't think anyone uses it :P

16:20 jweiss: if i have a vector of args i want to pass to a java method, how do i unpack the vector to call the method

16:22 hiredman: jweiss: easiest way is to wrap the java method call in a function and use apply

16:23 ,(let [f (fn [s p r] (.replaceAll s p r))] (apply f "foo" ["o" "a"]))

16:23 clojurebot: "faa"

16:23 jweiss: hiredman, maybe i should go up one level. i'm trying to write a macro that just creates function wrappers for all the member methods on a class

16:24 hiredman: :(

16:24 jweiss: I would just write function wrappers as needed

16:24 jweiss: i'm having trouble dealing with methods with args tho

16:24 hiredman, i can't it has to be dynamic :)

16:24 hiredman: why?

16:25 jweiss: because my prog won't know beforehand what all the methods on this class are, it will just know at runtime

16:25 hiredman: what does that have to do with any thing?

16:26 jweiss: how can i write a wrapper for a method before i even know what class i'm going to be using

16:27 oh, i think what you're asking is why wouldn't i just use the java method directly

16:27 i just want a cleaner syntax

16:27 because i want other people to be able to use this

16:30 cemerick: jweiss: about the only difference you'll see is the lack of a period before method names

16:30 ,(.size [])

16:30 clojurebot: 0

16:30 cemerick: -> (size [])?

16:31 it's too bad proxy doesn't allow one to put docstrings in their usual spot

16:32 jweiss: cemerick: yeah sorta, i was actually using (.. @myobjatom (method args)) -> (method args)

16:32 or actually

16:33 cemerick: (.method @youratom args) is more idiomatic

16:33 jweiss: (.. @myobjatom getTasks (method args))

16:33 hiredman: and -> is kind of prefered over ..

16:33 (-> myobjatom deref getTasks (.method args))

16:34 cemerick: well, I'd keep the @, but sure :-P

16:34 jweiss: k

16:34 cemerick: jweiss: the java interop syntax is virtually transparent -- enjoy it :-)

16:35 hiredman: I can tell which functions I created though messing around at the repl and which I just sort of typed out by the use of →

16:35 jweiss: cemerick: hopefully my other team members won't be thoroughly confused. clojure is completely foreign to them

16:35 hiredman: the repl functions always have a bit long → call

16:35 jweiss: then again, so is most programming, so what is the diff right

16:36 eventually i'm going to make a UI, but was hoping for a repl to be usable enough

16:36 cemerick: indeed -- shock them with concision

16:42 jweiss: there isn't any way to really build javadoc into classes so it's available at runtime, is there.

16:42 that sucks

16:52 cemerick: That will change eventually. We'll need that capability before we can release the next version of our main product.

16:54 Chouser: Java's going to compile javadoc right into the classfiles?

16:59 jweiss: i can't believe they didn't allow for annotations to hold javadoc

16:59 cemerick: Chouser: wha?

17:00 oh, hah, I didn't read jweiss' comment properly

17:00 I thought he was talking about generating javadoc from clojure code (e.g. gen-class, newnew)

17:01 not sure how I misunderstood that :-/

17:01 misread*

17:01 Chouser: ah

17:02 does that mean generating a sort of stubbed out .java?

17:03 cemerick: Yeah, almost certainly. We dove into that a little bit some months ago, if you'll recall.

17:03 Chouser: hm, I don't. I maybe be blocking the memories.

17:03 cemerick: I did some spelunking into javadoc, and it's a super-gnarly javac sidecar that is entirely unextensible.

17:04 I thought that's where gen-interface originally came from, but maybe I'm inventing whole cloth over here.

17:08 hrm, what is #_ used for? It's defined in LispReader, but unused in core.

17:10 Chouser: It comments out an expression.

17:10 hiredman: ,(do 1 #_2)

17:10 clojurebot: 1

17:10 Chouser: ,[1 2 #_ (oh no goin crazy here) 3]

17:10 clojurebot: [1 2 3]

17:12 cemerick: yeah, I figured that from the LR impl. I just can't think of any reason to use it...

17:12 just inline comments, where (comment ...) is too much?

17:13 oh, I see, it doesn't evaluate to nil

17:19 Chouser: exactly.

17:23 cemerick: annotations will be the death of us all

17:24 Chouser: I don't even know what they are.

17:24 As far as I'm concerned, if Clojure doesn't support it, it doesn't exist. :-D

17:25 cemerick: it's only a matter of time before clojure supports them. The whole Java multiverse is tilting in their direction.

17:25 Chouser: yes, this does present logical paradoxes when I try to write new features for clojure.

17:35 mebaran151: I never really got their point, but probably clojure could quarantine annotations with the rest of its Java compromise

17:36 I also was wondering whether or not, based on Clojure's compilation model, anonymous fn's were ever garbage collected

17:36 if each fn gets it's own class, it would seem that using lots of clojures would rapidly fill up the permgen

17:37 Chousuke: lots of clojures? :P

17:37 technomancy: mebaran151: iirc that was a problem a while ago, but it's been addressed

17:37 cemerick: as code transformation mechanisms, they're simply nutty; for controlling code generation and runtime configuration in one spot, they're better than the alternative (e.g. like wedging stuff into a superclass or put into an XML file or whatever)

17:38 mebaran151: an anonymous fn still has just one class.

17:38 cark: mebaran151 : closures are really like a class

17:38 so the environement is an instance of that class

17:38 and instances can be garbage collected

17:40 cemerick: ,(doseq [x (range 2)] (println (class #(list))))

17:40 clojurebot: sandbox$eval__2445$fn__2447 sandbox$eval__2445$fn__2447

17:41 mebaran151: no I see

17:42 cemerick, but if you just had a large application with lots of anonymous functions, it seems like wedging them into the superclass would be preferable, though I guess at any given time you might want to run that code path

17:43 cemerick: mebaran151: are you referring back to annotations?

17:46 mebaran151: nah, I'm being unclear

17:47 in a really large app, it seems like clojure might force you to suffer from class bloat

17:47 'though I guess each class is small enough individually

17:47 cark: well we don't see these classes

17:47 mebaran151: that it's not like in some Java servlet apps I've seen

17:47 cark: you mean for the user ?

17:47 cemerick: well, I think class GC is off by default in most VMs, though there's an option

17:48 Unless you're actually defining new fns regularly, I don't think there'd be enough class definition to cause a problem.

17:50 hiredman: the class gc can also be an issue for java, I've seen reports of redeployments on tomcat eventually filling the permgen space

17:50 cark: but the fix technmancy refered to should shield us from that , isn't it so ?

17:51 my understanding was that everything was in it's own class loader

17:51 mebaran151: hiredman, that's what I was referencing: I've had to redeploy on Jetty

17:51 and if you have many many classes, I've noticed weird GC behavior on this one app I put up

17:52 hiredman: cark: I dunno if it is complete fix

17:52 it might fix some clojure specific issue

17:52 cark: well every eval (and so the compiled code) should be garbage collected

17:53 but i don't know how that applies to loaded code

17:53 is there a class loader per defn ?

17:53 or per anonymous function even

17:57 cemerick: I wonder if it'd be worthwhile to define a binary serialization mechanism, so that arbitrary Serializable object could be dropped in in-line

17:58 hiredman: it would be pretty easy with #=

18:00 cemerick: ugh, doesn't seem like a good move -- one would have to encode the binary serializations. I was thinking of going the other way, emitting binary for clojure data structures, with java-serialized graphs in-line.

18:01 readable clojure is nice, but *big* (esp. strings and such)

18:01 hiredman: cemerick: you could do that

18:01 just wrap the binary in #=(read-binary-chunk ...)

18:01 Chousuke: you need to base64-encode it too :/

18:02 cemerick: yeah, that's what makes any use of #= sorta pointless

18:02 hiredman: I guess

18:03 cemerick: It'd be pretty easy to emit the core data structures via DataOutputStream, etc.

18:05 Chousuke: hmm

18:05 how do you serialise infinite seqs though? :P

18:06 cark: serialize the underlying lambda !

18:06 Chousuke: hm, I guess it's not so difficult. you'd just have to serialise whatever produces the next value.

18:06 (in addition to the values so far, of course)

18:07 cemerick: not even that, I think. Just some marker to start a map, read pairs until you hit a terminating marker, etc. Recurse, and done.

18:13 hiredman: I thought the marker to start a map was {

18:14 cemerick: ah, I had thought that DataOutputStream packed bits. So yeah, standard delimiters would work fine.

18:41 heh, java regex Patterns are serializable, but not interned. I didn't expect that...

18:42 actually, I didn't expect that they wouldn't override equals and hashcode based on the pattern string. That's more like it. :-)

19:55 arrayman: I've looked all over, but can't seem to find the right syntax for an array argument in gen-class

19:58 _mst: I've done something like this before: (defn -read-char<>-int-int [this cbuf off len] 456)

19:58 but I haven't tried it recently :)

20:01 arrayman: @_mst Thanks; does that automatically get added to the .class as an instance method because of its name, or do I have to mark it as such?

20:03 _mst: I think it's just based of the name, yep. In that case I was overriding this method of StringReader: "int read(char[] cbuf, int off, int len)"

20:03 the full example's here if you want to try it: http://dishevelled.net/Tricky-uses-of-Clojure-gen-class-and-AOT-compilation.html

20:05 arrayman: I remember reading that article, but was under the impression that I had to give the method that special name _and_ tag it inside the gen-class invocation. Thanks for setting me straight.

20:07 @_mst I notice that -read-char<>-int-int matches the argument signature (char array and two ints), but how does the return type get specified?

20:10 _mst: it doesn't in that example, but I'm not sure you'd need to

20:10 clojurebot: that is not what I wanted

20:10 _mst: does java actually let you dispatch on return type too?

20:14 arrayman: @_mst I don't believe it does, so maybe I'm fretting about nothing.

20:15 @_mst Does the same naming apply to static methods?

20:16 _mst: I've never done much with static methods and gen-class, sorry. But can you really override static methods anyway?

20:16 arrayman: @_mst I'm creating a brand new class, not overriding

20:17 _mst: ah I see

20:17 arrayman: @_mst ...and I've been able to define other static methods on it -- but haven't been able to specify an array type at all.

20:50 mrsolo: http://4.bp.blogspot.com/_syI_yyzTPG8/SnDhboxfNZI/AAAAAAAAATk/4cyx7jJ4XLc/s1600-h/chart1_jruby.5.png

20:50 ack!

20:50 and i though jruby is slowest of them all...

20:56 cemerick: mrsolo: that's why libraries are so important. e.g. who cares that the sort fn uses java.util.Arrays/sort?

20:57 mrsolo: where'd that graphic come from?

20:57 mrsolo: http://berlinbrowndev.blogspot.com/2009/07/jvm-notebook-basic-clojure-java-and-jvm.html

20:57 i haven't went through the details

20:58 but this is the first benchmark that shows jruby is faster than clojure

20:58 usually it is another way around..

20:58 cark: he's filtering twice

20:59 cemerick: *shrug* both JRuby and clojure should (and do, at least in clojure's case) use Java's sorting routines

21:01 mrsolo: should but this is intentional

21:01 guess he is trying to determine the overhead of various jvm langauges.

21:01 cemerick: yeah, I suppose it's an interesting exercise.

21:02 quicksort certainly benefits from the use of a mutable data structure. :-P

21:03 cark: the java example doesn't really mutate stuff

21:09 cemerick: cark: LinkedLists are most certainly mutable.

21:10 cark: right, but they are only used like our own mutables

21:14 cemerick: hardly -- the clojure code is doing two filters on each pass, vs just accumulating results.

21:15 cark: yes yes

21:15 i mean the linked lists while being mutable are used in a way that won't interfere with the outside of the function

21:16 in the same way we're supposed to use the new mutable data structures in clojure

21:17 but yes i wouldn't do the quicksort in clojure that way, not for speed ... though the ruby version is not any better

21:19 mrsolo: ya jruby version is pretty crappy

21:19 still faster

23:08 avital: hi. is there an equivalent to filter for hashmaps?

23:08 Raynes: Filter works for maps.

23:09 avital: i'm looking at the source code and it seems that pred only gets one argument. i want to filter based on the keys, not the values.

23:12 hiredman: avital: the seq of a map is a seq of [key value] pairs

23:12 avital: ah nice ok cool

23:12 hiredman: ,(seq {:a 1 :b 2})

23:12 clojurebot: ([:a 1] [:b 2])

23:13 hiredman: ,(filter #(= 1 (val %)) {:a 1 :b 1 :c 3})

23:13 clojurebot: ([:a 1] [:b 1])

23:13 hiredman: ,(into {} (filter #(= 1 (val %)) {:a 1 :b 1 :c 3}))

23:13 clojurebot: {:b 1, :a 1}

23:13 avital: wow what wow wow

23:13 what is #(

23:13 and what is val

23:13 and %

23:13 WOW

23:14 is #( a really quick way to define a fn

23:14 where % is its arg?!

23:14 hiredman: yes

23:14 avital: INCREDIBLE

23:14 hiredman: but it is not equiv to (fn [] )

23:14 with #() there is no implicit do

23:14 well

23:14 avital: hmmm not sure what that entails

23:14 hiredman: more that that

23:14 #(foo 1) => (fn [] (foo 1))

23:15 #(1) => (fn [] (1)) => an Exception

23:15 avital: ah i see

23:15 so wait what is val?

23:15 hiredman: ,(doc val)

23:15 clojurebot: "([e]); Returns the value in the map entry."

23:15 hiredman: ,(class [1 2])

23:15 clojurebot: clojure.lang.LazilyPersistentVector

23:15 hiredman: grrr

23:16 ,(val [1 2])

23:16 clojurebot: java.lang.ClassCastException

23:16 hiredman: bah

23:16 ,(class (first {:a 1}))

23:16 clojurebot: clojure.lang.MapEntry

23:17 avital: thanks this is great

23:56 Chouser: any suggestions on an easy way to un-chunk a seq?

23:56 , (chunked-seq? (seq [1 2 3]))

23:56 clojurebot: true

23:57 Chouser: ,(chunked-seq? (seq (map first (take-while identity (iterate next [1 2 3])))))

23:57 clojurebot: false

23:57 Chouser: surely there's something better than that.

Logging service provided by n01se.net