#clojure log - Sep 29 2009

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

0:02 qbg: Is there a better way to make a big vector than to do (vec (repeat 1000000 0))?

0:03 duck1123: why do you want a whole lot of 0's

0:04 that works, but there's probably a better way depending on what you really need

0:04 qbg: Trying to see just how expensive vectors are

0:04 and have some fun

0:05 duck1123: Clojure's vectors are pretty cheap. They're not the cheapest out there, but if you consider what they can do...

0:06 qbg: True, though making an int array is MUCH faster

0:07 And I run out of memory when trying to create a 10,000,000 element vector

0:07 duck1123: that's why you want to avoid holding the head

0:07 hiredman: well, that doesn't matter for vectors

0:08 duck1123: good point

0:08 qbg: I suppose all of the separate consing is probably the source of the time required

0:15 duck1123: is there a better way to say (if (not (nil? ...)) ...)

0:15 I find myself doing that a lot lately

0:16 qbg: (if ...)?

0:16 duck1123: but I want false to be true

0:17 and I'm a total Discordian for saying that

0:17 qbg: Then (if (not ...))?

0:18 duck1123: true also has to be true

0:18 so, anything except nil is true

0:19 * qbg gives up by saying write a macro

0:19 * qbg notes his inexperience though

0:20 duck1123: no, if not nil? is as clear as it's going to get

0:21 hiredman: (def not-nil? (comp not nil?))

0:22 duck1123: that would still be (if (not-nil? which isn't much better

0:22 I'll stick with what I have

0:22 hiredman: !nil?

0:22 ,'!nil?

0:22 clojurebot: !nil?

0:23 duck1123: has anyone made a -> that shortcuts on nils?

0:23 hiredman: -?>

0:23 it's in contrib.core

0:23 duck1123: cool thanks.

0:24 is contrib.core new?

0:24 hiredman: no idea

0:25 duck1123: I don't seem to have it in my jar

0:25 I can't be more than a month old

0:25 hiredman: ~def -?>

0:27 the history says at it's been in contrib over three months

0:27 more like six

0:28 duck1123: I wonder if I've been bitten by that bug that hlship reported

0:28 I AOT my contrib

0:30 hiredman: and?

0:31 duck1123: he reported that some namespaces weren't being compiled. I'm just guessing why my jar didn't have it

0:32 hiredman: I also AOT the contrib jar clojurebot uses

0:32 ,(-?> nil .toUpperCase)

0:32 clojurebot: nil

0:33 duck1123: I don't know. I'm replacing it

0:46 qbg: Why would pmap be only about 2.2 times faster than map on a quad core machine when the mapped function is essentially as ideal as you can get?

0:47 duck1123: there's quite a bit of overhead on setting up pmap, so unless your fn is long enough, it might even be slower

0:48 qbg: Each function call takes around a quater of a second

0:49 duck1123: I'm sure you'd find that as the time your fn takes increases, so will your performance increase

0:50 qbg: Would the same thing be true with agents?

0:50 hiredman: pmap uses futures which use the same threadpool as agents

1:03 qbg: Even when the function takes 30 seconds to compute, I don't see much more than a 2.4x speed up

1:04 hiredman: how are you consuming the result?

1:04 qbg: nth

1:04 (of the last element)

1:07 Entering all of the code in the repl wouldn't be a problem, right?

2:03 j3ff: Is there a sort of "do nothing" command in clojure?

2:04 salainen: for what?

2:05 j3ff: i have an if statement in a recur, and when the recur is over i want it to do nothing. right now i just have it as "nil" but i dont want it to return anything

2:05 i mean the if statement is the base case

2:06 Makoryu: j3ff: You can't not return anything.

2:06 j3ff: ah ok

2:06 salainen: j3ff: so just ignore the return value. nil means "nothing"

2:06 Makoryu: j3ff: There's no difference between expressions and statements in Clojure, unlike whatever language you're probably used to

2:07 _mst: you might prefer (when test foo) to (if test foo nil)

2:07 salainen: (ok.. nil probably does not mean nothing, but rather unknown ... but what the heck)

2:29 konr: What should I use to make GET/POST requests and parse HTML?

2:30 hiredman: are you looking for something like a web browser interface?

2:30 htmlunit is pretty nice for filling out forms and website scraping, etc

2:31 there are several http client libs, on in contrib

2:31 tagsoup does a great job parsing html

2:32 konr: Hmm, interesting... I'll take a look at this tagsoup, thanks!

3:07 Fossi: hi

4:11 j3ff: hey fossi

4:59 whats up clojure people

5:16 konr: how can I find out what java libraries are available to me? I'm struggling to import tagsoup :S

5:19 fullets: Is there a more idiomatic way to write (some (fn [x] (when (= (foo x) bar) x)) a-list-or-something)?

5:29 Fossi: Chouser: the error-kit handle map destructure isn't really intuitive

5:29 took me about half an our to figure out that you have to use the names in the vector that you used on defining the error

5:29 sunwukong: fullets: (filter #(= (foo %) bar) a-list-or-something)

5:30 jdz: sunwukong: that's not the same

5:30 Fossi: especially with the 'defnish' vector, it lead me to believe it was just a 'normal' bind

5:30 sunwukong: jdz: ah, ok

5:31 jdz: fullets: what exactly do you want to do? because the when in your function is unnecessary

5:32 fullets: jdz: If I just have (= (foo x) bar) the form evaluates to true rather than the matching item in the sequence; what I'm looking for is an equivalent of the CL (find bar sequence :key #'foo)

5:32 jdz: ,(doc some)

5:32 clojurebot: "([pred coll]); Returns the first logical true value of (pred x) for any x in coll, else nil. One common idiom is to use a set as pred, for example this will return true if :fred is in the sequence, otherwise nil: (some #{:fred} coll)"

5:33 jdz: oh, i seem to remember "some" working differently

5:33 fullets: ,(some (fn [x] (= 1 x)) [1 2 3])

5:33 clojurebot: true

5:33 fullets: I want that to eval to 1

5:34 ,(some (fn [x] (when (= 1 x) x)) [1 2 3])

5:34 clojurebot: 1

5:34 sunwukong: ,(first (filter (fn [x] (= 1 x)) [1 2 3]))

5:34 clojurebot: 1

5:34 Chousuke: ,(first (filter #{2} [1 2 3]))

5:34 clojurebot: 2

5:35 jdz: missing the :key here

5:36 Chousuke: hm

5:36 konr: Guys, I have tagsoup-1.2.jar in my classpath. I've opened it, and it contains "org/ccil/cowan/tagsoup/Parser.class". Yet when I try to import it via (import '(org.ccil.tagsoup Parser)), I get a ClassNotFoundException. Where am I getting it wrong?

5:37 jdz: konr: missed cowan?

5:37 konr: jdz: nope, just a typo in my previous message ;)

5:37 (import '(org.ccil.cowan.tagsoup Parser))

5:38 jdz: konr: check your classpath, it works for me.

6:03 cschreiner: konr: seems similar to my experience

6:04 konr: cschreiner: it turned it to be a problem on the classpath

6:04 cschreiner: I'm running emacs on 10.6.1

6:05 (never could get that classpath-thing right)

6:09 konr: Hmm, I don't know how it works on emacs, but using vi/ng-server, we run a JVM as a server and connect to it using a client, so changing the classpath was just a matter of changing the parameters used to run the server

7:15 anyone knows where I can find zip-query.clj? It's referenced in (doc xml->), but it's not in $CLOJURE_CONTRIB

7:34 ngoc: Does coordination in ref mean the same thing as in "cooperative multitasking"?

8:01 Fossi: ngoc: afaik it means changes to more than one variable

8:02 vy: I'm reading the documentation of ensure: "Protects the ref from modification by other transactions. Returns the in-transaction-value of ref. Allows for more concurrency than (ref-set ref @ref)". I still couldn't figure out what ensure does. Could anybody help please?

8:08 Fossi: it ensure's that a ref you don't write to, but only read has a certain value

8:08 otherwise it wouldn't be protected from manipulation

8:09 normally a transaction would be retried only if your writes clash with somebody elses

8:09 vy: Is there any example code using "ensure"?

8:14 Fossi: i don't have any and couldn't find one in a short google trip

8:15 i guess it's not needed very often. just to detect the write-skew

8:41 vy: Why does (#(1)) try to cast 1 to IFn and hence complains that "java.lang.Integer cannot be cast to clojure.lang.IFn".

8:43 Chouser: ,(macroexpand '(#(1)))

8:43 vy: that expands to: ((fn* [] (1)))

8:43 vy: Oops! I see. My bad.

8:43 Chouser: np. It's a common mistake.

8:48 vy: What's wrong with (send a #(fn [v & _] (Thread/sleep 1000) (conj v 1))), after executing this and trying @a, Clojure complains that "Agent has errors".

8:49 Chouser: what was a?

8:49 vy: Chouser: [1]

8:50 (agent [1]) ofcourse I mean.

8:50 Chouser: drop the #

8:51 vy: Brrr!

8:52 Chouser: got it now? :-)

8:52 vy: Yes, I already smacked my head.

9:07 ambient: anyone have a tutorial or something how to install penumbra to ubuntu, because it seems to be beyond me?

9:07 i can do a very difficult install, where i add a million paths to different places but there must be a simpler way to do it all

9:12 seems i have to build my own packaging system

9:14 Dominik_S: hello, i want to integrate a repl in a existing java project

9:15 ambient: do i have to create a single environment into which i copy&paste all the needed dependencies (clj source code) in order to be able to use them later and put the directory into classpath?

9:17 Chouser: ambient: no, commands like 'use' and 'require' search the whole classpath, so you can add as many different directories as you want to.

9:18 ambient: Chouser: just create a single directory like ~/libs/clojure, add it into classpath, and copy&paste all dependency clojure code there?

9:19 Chouser: ambient: I wouldn't recommend copy&pasting code

9:19 ambient: copying the files and the directory structures

9:19 src/*

9:20 Chouser: I know some people recommend that. I personally use -Djava.ext.dirs to point to a directory where I have symlinks to all the .jar's I might need.

9:21 Fossi: Chouser: seen my comments on error-kit?

9:21 ambient: i'd rather make a system that's highly dynamic so that I don't have to manually do anything except copy some files

9:22 Chouser: Fossi: I have now, thanks.

9:22 Fossi: i'm still a bit confused on how it should actually be used

9:23 Chouser: Fossi: I'm thinking about ripping out deferror and the error constructor and inheretance stuff.

9:23 Dominik_S: hello everyone, is there a tutorial for integrating a clj repl in a existing java project?

9:23 Fossi: deferror has that args-destruct-map parameter that i can't really wrap my head around

9:24 Chouser: Fossi: so one way to use it would be to specify all details of the error when you raise it -- if you want to craete your own fn to create similar types of errors you'd do that on your own.

9:24 Fossi: since it doesn't really seem to work with nested maps as in the binding

9:24 Chouser: sounds valid

9:26 Chouser: I think that my cut out a lot of unnecessary complexity in an already necessarily complex lib.

9:26 Dominik_S: I don't know of a tutorial -- did you search the google group? I know it's been asked about and done a few times.

9:29 Dominik_S: i search the google grp, but i did't found. are there some special key words for that?

9:41 Fossi: we'd love to have serializable keywords and apparently that's fixed in master, does the next release have any fixed date yet?

9:42 ambient: this is strange "Could not locate clojure/contrib/def__init.class of clojure/contrib/def.clj on classpath" even if both clojure and clojure-contrib jars are in classpath

9:47 chouser: Fossi: no fixed date.

9:48 Fossi: but you can grab a current snapshot of the repo and just use that.

9:52 Kjellski: Hi there =)

9:53 Someone has got a minute or two for a small piece of code I´m trying to translate?

9:56 I´ve got a solution, but it looks so extremely ugly, that I think there would be a better way...

9:56 chouser: lisppaste8: url

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

9:56 chouser: Kjellski^^

9:57 Kjellski: Oh thanks, I´ve already prepared some pastebin urls:

9:58 http://pastebin.org/29410

9:58 I´ve translated into:

9:58 http://pastebin.org/29413

9:58 It´s about the simple rot13 "cypher" ^^

10:00 And btw, the result looks ugly too.

10:04 chouser: I'd try writing it as a seq processor.

10:05 Kjellski: Okay, where can I read through how that goes?

10:06 Fossi: chouser: thanks, we rather patched stable ;)

10:08 Kjellski: Or can you tell me where I could find a version to compare with?

10:19 ambient: (require) seems to search for root resource <classpath>/x/y/z/z.clj from (require x.y.z), how do i make it <classpath>/x/y/z.clj?

10:22 lisppaste8: Chouser pasted "rot13 for Kjellski" at http://paste.lisp.org/display/87892

10:22 raek: ambient: how does your (require) line look like?

10:23 Kjellski: Ufff... thanks a lot Chouser! ... *reading*

10:25 What does the -> thing?

10:25 chouser: Kjellski: note there's no IO -- doseq and print are side-effecty things and will tend to make your code uglier, especially when you don't need it.

10:26 -> is a macro that takes each expression and inserts it as the first arg of the next expression

10:26 so (-> i (- base)) is the same as (- i base)

10:26 Kjellski: Damned, that sounds extremely useful... and now I can read the code much better =)

10:27 ambient: raek: (require 'examples.gears)

10:29 Kjellski: Thanks a lot... I think the best thing is that I can see how clojure was used in the right way =)

10:32 LauJensen: ambient: You guys still haven't gotten penumbra working?

10:34 raek: ambient: and your sourcefile is in <classpath>/examples/gears.clj ?

10:35 ambient: raek: yes

10:35 LauJensen: no

10:36 raek: i'm really a java noob so this is just a guess, but i've heard that you should have at least two levels of directories

10:36 and java might be enforcing this

10:36 chouser: only need one dir. examples.gears for examples/gears.clj should be fine

10:37 LauJensen: What I did was, copy the native files into ~/deps and the source into /libs/penumbra/, then EXPORT LD_LIBRARY_PATH=$LD_LIBRARY_PATH:~/deps/ and then java -cp clojure.jar:/libs/penumbra/src/ clojure.lang.repl, and then (use 'examples.gears) . What are you doing idfferently ?

10:37 "~" is shorthand, I always use fully qualified names

10:37 ambient: clojure.main

10:37 LauJensen: sure :)

10:37 Same thing

10:38 ambient: well i did (println (seq (.getURLs (java.lang.ClassLoader/getSystemClassLoader))))

10:38 and it shows that the correct path exists

10:38 penumbra/src

10:40 java.io.FileNotFoundException: Could not locate examples/gears__init.class or examples/gears.clj on classpath: (NO_SOURCE_FILE:0)

10:40 im boggled

10:46 lisppaste8: cgrand annotated #87892 "another rot13 for Kjellski" at http://paste.lisp.org/display/87892#1

10:58 Kjellski: Hey cool, that´s another nice idea =) thanks cgrand!

11:09 So thanks again folks, I´m leaving! cya

11:28 johnmn3: hello all

11:28 I followed the tutorial here: http://freegeek.in/blog/2009/08/setting-up-emacs-clojure-with-emacs-starter-kit/

11:29 and I want to get paredit working

11:29 anyone have familiarity with this setup?

11:31 prospero_: hey, I'm a bit late to this, but I saw a conversation in the logs about not getting Penumbra to run

11:31 johnmn3: doing a M-x paredit-mode RET gets it going just fine. However, I'd like to enable "Electric RET" so that I can manipulate which lines expressions can go on

11:32 prospero_: did I just give bad advice here: http://wiki.github.com/ztellman/penumbra/getting-started

11:33 it's worked for me on os x and windows

11:33 but maybe I'm just eliding a step or something

11:34 danlarkin: prospero_: that's okay advice for java6, but not for java5

11:34 you don't want to go messing around with your java.library.path on java5...at least in my experience

11:35 prospero_: danlarkin: so for java5 you need to place the files in the right place?

11:37 danlarkin: I don't know where jnilib and so files have to go

11:37 prospero_: ok

11:37 but for java 6, the script seems solid?

11:38 danlarkin: seems so, worked for you anyway

11:38 prospero_: yeah, fair enough

11:38 ok, thanks

11:38 rsynnott: does clojure build on java 6 these days, actually?

11:41 Makoryu: I'd be amazed if it did not

11:46 tmountain: rsynott: it definitely does

12:18 Fossi: PersistentHashMap$BitmapIndexedNode not being serializable. rings a bell for someone?

12:46 Drakeson: is swank-clojure broken these days?

12:47 technomancy: Drakeson: if it is please let me know!

12:49 Drakeson: well, it might be some change in clojure itself or maybe my own local configurations. When I try to compile it (or `use') it, it produces this error message: [java] java.lang.ClassFormatError: Duplicate method name&signature in class file swank/util/io/proxy$java/io/StringWriter$0 (io.clj:23)

12:50 tomoj: I have the latest swank-clojure and didn't have any problem

12:51 Drakeson: tomoj: do you have the latest clojure, too?

12:51 tomoj: ah, no, I had last week's

12:52 Drakeson: last week it was fine

12:52 technomancy: Drakeson: I've been sloppy about keeping in sync with jochu's repo. are you using his or mine?

12:52 Drakeson: I am using his tree.

12:52 technomancy: I haven't gotten a chance to look at that yet. try mine?

12:53 Drakeson: technomancy: most likely the same. I'll try yours too. do you have the latest clojure now?

12:54 technomancy: Drakeson: I'll update just to be sure

12:54 tomoj: ah I'm using technomancy's as well

12:56 technomancy: Drakeson: works with today's clojure.

12:56 at least, M-x swank-clojure-project does

12:56 Drakeson: technomancy: thanks. I'll try yours in a moment ...

13:00 oh, he is now producing swank-clojure.jar

13:00 johnmn3: broke my emacs some how: M-x slime [no match]

13:01 was working after I followed the instructions and installed everything, but after restarting emacs, no joy

13:01 technomancy: johnmn3: do you have (clojure-slime-config) in your .emacs file?

13:02 johnmn3: never mind; I see the problem

13:02 johnmn3: I actually don't have an .emacs file.. how do you see the problem?

13:03 technomancy: johnmn3: some of the autoloads are in the wrong order

13:03 johnmn3: I have an .emacs.d folder

13:03 technomancy: works with swank-clojure-project but not with simple M-x slime.

13:03 johnmn3: that's what I meant

13:03 file, folder; same thing.

13:04 johnmn3: oh. if it gets fixed, will doing an clojure-update fix it?

13:05 technomancy: johnmn3: that's part of clojure-mode unfortunately, so you'll need to update that

13:07 Drakeson: technomancy: I still have the issue (even using your tree). Something might be broken locally (maybe debian guys broke something). Please don't consider this as a bug report, yet :)

13:07 johnmn3: I did it once and it started compiling stuff.. but still no worky

13:08 clojure-mode is there

13:09 technomancy: Drakeson: I'm seeing that problem here with M-x slime

13:09 I don't use slime on its own usually, I use it in the context of a project, so I must have missed it

13:09 I think it just needs to be upgraded to work with the latest clojure

13:10 Drakeson: technomancy: thanks

13:10 technomancy: I forgot that in the project context it will just use whatever version of clojure the project depends on, not necessarily the latest.

13:11 tomoj: so swank-clojure is broken with latest clojure?

13:12 technomancy: tomoj: not for long, hopefully. =)

13:16 johnmn3: so how do I get into clojure-mode

13:17 technomancy: johnmn3: if you use it on a project basis, you can use elpa (http://tromey.com/elpa) but if you want standalone slime you'll have to give me a minute

13:17 Drakeson: technomancy: it is broken with clojure origin/master~3 but not with origin/master~4

13:17 technomancy: Drakeson: good to know; thanks

13:20 johnmn3: technomancy: oh, no, no worries bro

13:22 somnium: what does a single ^ mean prefixed to a symbol (seeing it in zip.clj)

13:22 technomancy: somnium: it's a shortcut for meta

13:22 rhickey: ^ == (meta x)

13:23 somnium: thanks

13:36 chouser: rhickey: ^ not deprecated yet?

13:37 rhickey: Chouser: there was a conversation here about how best to deprecate, given that it is a reader thing, I don't know that we concluded anything

13:37 but I'd like to deprecate, yes

13:39 manic12: so someday you could have a regular symbol like m^2 ?

13:40 somnium: would it be possible to get the reader to parse % as part of a symbol outside of a #() fn ?

13:40 rhickey: manic12: not necessarily, the point of deprecating ^ was so that it could replace #^

13:41 both ^ and % are currently terminating, making them not is also an independent decision

13:42 somnium: or as part of a kewyword? always terminating on %, makes implementing dsl for say, css, awkward

13:44 rhickey: somnium: understood

13:45 chouser: somnium: you know % is available for DSLs and used in some already?

13:46 somnium: how?

13:46 rhickey: Chouser: not as a constituent character

13:46 ,'foo%bar

13:46 chouser: just as a plain symbol char

13:47 ,(let [% 5] %)

13:47 somnium: ah

13:47 chouser: clojurebot is letting us down

13:47 somnium: so something like (mydsl 100 %)?

13:47 chouser: oh, but I was thinking of ~ and ~@

13:47 somnium: still have to parse it specially

14:52 hircus: hi folks

14:53 would a Linux distribution be better advised to ship Clojure 1.0, or a later snapshot?

14:54 Raynes: Clojure 1.0, I suppose.

14:56 chouser: depends on your users, I suppose. Are you a Debian Stable type distro, or a Gentoo ~x86 type distro?

15:08 technomancy: java.lang.ClassFormatError: Duplicate method name&signature in class file <= would you get that error when trying to write a proxy that defines a method twice?

15:09 hah; I'm looking at this code thinking "why's he using a ref there; he should use an atom."

15:09 C-x v g tells me the code was written before atoms were implemented.

15:09 (this is in swank-clojure)

15:11 ,(proxy [java.io.StringWriter] [] (close [] ))

15:11 clojurebot: java.lang.IllegalStateException: Var null/null is unbound.

15:11 technomancy: ^ in current clojure master, this raises an exception

15:11 I can't see how it should

15:13 crios: hello. Could anyone explain a bit what does "holding the head" mean? It seems related to Var declaration, and I gathered it affects the overall runtime performance. Till now I understood that as a "keeping a reference which is not Garbage colleted"

15:13 [collected]

15:13 technomancy: crios: that's about right

15:14 kotarak: crios: "holding the head" means the you store the head of sequence somewhere, in a local, a Var, a Ref, etc. which prevents GC of the sequence.

15:14 so eg. (iterate inc 0) will eventually eat all your memory when traversing it and holding the head somewhere.

15:14 technomancy: if you loop over a lazy sequence, it should normally allow the elements you've already used to be GC'd... otherwise if there's a reference to the head it's a memory leak

15:14 crios: Is it an issue on functional languages in general? Or just Clojure's Java implementation?

15:14 technomancy: crios: it's a laziness issue

15:16 commit a780e1d096f6a99cb974568a0a6d76d4e996e585 seems to have broken proxying to StringWriter

15:16 crios: So in order to be "holded", the sequence must be holded in a "named reference"

15:17 Chousuke: crios: any reference to it will do

15:17 so if you put a lazy seq in a map, that counts

15:17 kotarak: crios: local, in a map, in a vector, ...

15:17 technomancy: Drakeson: I don't think this is a swank-clojure bug

15:17 stick with master~4 for now

15:20 kotarak: Can c.l.Compile set *warn-on-reflection*?

15:20 chouser: technomancy: confirmed that patch broke your proxy example.

15:20 technomancy: chouser: it doesn't look like it's directly related to proxy

15:21 chouser: no indeed

15:21 technomancy: must be just the way proxy relies on TransientHashSet

15:21 somehow

15:21 chouser: :-)

15:21 crios: kotarak: when running "(iterate inc 0)" on the REPL I'm holding the head?

15:22 kotarak: crios: I would think so, because the repl stores the last expression in *1.

15:22 The value of the last expression, that is....

15:23 Since the Repl prints the sequence. It realises it.

15:23 Should give some memory trouble....

15:24 crios: I'm running it ...

15:24 mmm stopped after a while

15:25 ambient: are the jvm summit 2009 talks coming on the web sometime in the future?

15:25 crios: no crash, tough

15:25 kotarak: crios: what did it say, when it stopped?

15:25 crios: nothing, returned to the REPL's prompt

15:26 the last showed number: 1020140

15:26 chouser: technomancy: I gotta run, but that patch is clearly braking sets somehow.

15:26 breaking

15:26 technomancy: chouser: I'll look into it later today

15:27 crios: ah no wait kotarak: the output was mixed

15:28 scrolling back, I found: java.lang.OutOfMemoryError: Java heap space

15:28 now it makes sense :)

15:28 kotarak: crios: bingo :)

15:28 crios: so, all lazy sequence have an hold-to-the-head?

15:29 kotarak: crios: ?? They all have the same problem, if the sequence is bigger than your memory. If that is, what you are asking.

15:30 slyrus_: hmm... is swank-clojure busted?

15:30 technomancy: slyrus_: clojure is busted. =)

15:30 see chouser above

15:30 kotarak: crios: (take 5 (iterate inc 0)) is also lazy, but it shouldn't be a problem to hold unto its head. ;)

15:30 slyrus_: oic... thanks technomancy

15:31 Chousuke: crios: a lazy sequence itself doesn't cause OOM situations, it's the consumer's carelessness that ultimately causes trouble :)

15:33 crios: it is holding *my* head :) - The consumer should care to not execute an infinite loop, and this is obvious. So that's all about this "holding the head"?

15:35 I mean, no declaration / scope issue there?

15:35 kotarak: crios: bad => (let [x (iterate inc 0)] (realise-a-huge-part-but-dont-hold-head x)), good => (let [x (fn [] (iterate inc 0))] (realise-a-huge-part-but-dont-hold-head (x)))

15:38 Chousuke: crios: well, sometimes you end up having references to things where you wouldn't expect them

15:39 crios: but you just need to double-check your code if you get OOM exceptions :)

15:41 crios: kotarak, in your "good" code, your are creating a function so that the reader does not evaluates that iteration as soon as it read it (causing an infinite loop). Correct?

15:42 kotarak: crios: no. The reader does not evaluate anything. (At least not in general). The bad code stores the head in a local. The good just passes the return value of the function (the sequence) on to the next function. So the sequence head is not stored in a local.

15:43 Chousuke: of course, the example is a bit silly :P

15:44 usually you'd just do (realise-a-huge-part... (iterate inc 0)) :)

15:44 kotarak: Chousuke: examples tend to be silly or too huge

15:44 crios: I have to study this chat session carefully, for a while

15:44 thank you both

15:45 kotarak: crios: np

16:08 crios: to stay in topic ... in the mailing list, a new question: "RFC: laziness-safe, semi-dynamic environment Var(Lite)"

16:09 a Request for Comments

16:09 I read it and my head is hold (down)

16:09 'night

16:09 :)

16:15 ngoc: How to call namespace/func dynamically?

16:15 Something like this pseudo code:

16:16 (def my-ns 'foo)

16:16 (def my-func 'bar)

16:16 (my-ns/my-func args)

16:17 chouser: ,(resolve (symbol "clojure.core" "map"))

16:17 clojurebot: #'clojure.core/map

16:17 chouser: ,((resolve (symbol "clojure.core" "+")) 5 10)

16:17 clojurebot: 15

16:17 somnium: ,(ns-resolve 'clojure.core 'map)

16:17 clojurebot: #'clojure.core/map

16:22 ngoc: It works, thank you very much

16:23 somnium: ,(type "foo")

16:23 clojurebot: java.lang.String

16:23 somnium: ,(type 'bar)

16:23 clojurebot: clojure.lang.Symbol

16:23 somnium: ,(type (symbol "foo"))

16:23 clojurebot: clojure.lang.Symbol

16:23 somnium: (ns-resolve "foo" "bar")

16:24 ,(ns-resolve "foo" "bar")

16:25 where'd he go? I get a java.lang.String cannot be cast to clojure.lang.Symbol

16:25 which seems incongruous given the above cast

16:26 chouser: 'symbol' is not a cast. It's a fn.

16:26 somnium: ah

16:26 chouser: ,(name 'foo)

16:26 clojurebot: "foo"

16:26 chouser: ,(name "foo

16:26 clojurebot: EOF while reading string

16:26 chouser: ,(name "foo")

16:26 clojurebot: java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.Named

17:00 somnium: question about the reader, at macro expand time: (vector :foo :bar) is a persistent list containing three unevaluated expressions, but [:foo :bar] is a persistent vector containing two unevaluated expressions?

17:03 Chousuke: somnium: the data structures produced by the reader are such, yes.

17:04 ngoc: How to add a key -> value pair to an existing hash? I do (cons {:k1 1} {:k2 2}) but it seems the result is incorrect.

17:04 Chousuke: use conj

17:05 ,(conj {:foo 'bar} [1 2])

17:05 clojurebot: {1 2, :foo bar}

17:05 kotarak: somnium: they contain keywords (and in one case a symbol)

17:05 ngoc: Ah, conj works, thank you

17:05 kotarak: ,(assoc {:foo 1} :bar 2)

17:05 clojurebot: {:bar 2, :foo 1}

17:06 somnium: is there an equivalent to conj that always appends to the end of seqable?

17:07 ,(conj [1 2] 3)

17:07 clojurebot: [1 2 3]

17:07 hiredman: no

17:07 somnium: ,(conj '(1 2) 3)

17:07 clojurebot: (3 1 2)

17:07 Chousuke: somnium: sequences only grow at the head

17:07 though there is concat

17:07 kotarak: ,(concat (list 1 2) [3])

17:07 clojurebot: (1 2 3)

17:10 raek: conj isn't defined to append to the front, it adds something to a container in a container-specific way

17:11 prospero_: ambient: are you still having issues with Penumbra?

17:11 technomancy: chouser: I'm afraid that TransientHashSet/proxy problem is beyond me

17:11 prospero_: if so, send me a message on Github telling me exactly what your setup is, and I'll try and see how to get it working for you

17:12 technomancy: it looks like that patch is totally additive; I can't trace it to how it affects proxy

17:12 ambient: prospero_ nah, i got it to work on windows. ubuntu might've had some binary incompatibilities or such

17:12 prospero_: hmm

17:12 I think Lau got it working on Linux

17:12 but maybe not Ubuntu

17:13 I've been leaning heavily on JOGL being cross-platform, I haven't had the time to test it across a wide variety of configurations

17:13 ambient: yeah, had to install 32 bit JVM because couldn't find 64 bit binaries

17:13 prospero_: hmm

17:14 oh, right, because I only put 32-bit binaries in the lib folder

17:14 ok, I'll fix that tonight

17:14 LauJensen: prospero_: Works fine on Ubuntu

17:14 prospero_: LauJensen: 32-bit?

17:15 LauJensen: Yep

17:15 ambient: i'm just very apt at f*n things up. mine was 32-bit also

17:16 prospero_: I assumed a 64-bit OS would be backwards compatible w/ 32-bit binaries

17:16 is that not true?

17:16 ambient: it is but 64 bit JVM isn't

17:16 apparently

17:16 prospero_: hmm

17:16 well, glad you got it running somewhere

17:16 ambient: heh thanks

17:16 prospero_: don't be shy about letting me know about these issues

17:17 I'm trying to get a feel for common issues

17:17 LauJensen: prospero_: You're the Tellerman ?

17:17 prospero_: LauJensen: yes

17:17 probably should just come on here as ztellman

17:18 LauJensen: Great to have you in here :) I noticed your doc-strings are mangled due to the macro-expansions that are taking place. I think it would be a great help in minimizing the learning curve if you could fix that.

17:18 ngoc: Since program = code + data, we usually need to encapsulate code and data together. What are "good" ways to do the encapsulation in Clojure? I think just like C, we use struct to do this?

17:19 Chousuke: ngoc: this is no problem in clojure, as code = data, so program = data + data ;)

17:19 ambient: lists :p

17:19 prospero_: LauJensen: can you give me an example?

17:20 LauJensen: prospero_: I think it was draw-points that I noticed it with, the doc string in slime will read "_ __BODY@@A_" or something along those lines

17:20 * ambient goes to try and make an infinite seq of generated functions

17:20 Chousuke: ngoc: don't worry about encapsulation too much.

17:20 prospero_: weird

17:20 Chousuke: ngoc: most of your functions should be processing immutable data structures, and you really don't need to protect those much :/

17:21 prospero_: I'm doing a few macros-within-macros, maybe that's it?

17:21 Chousuke: ngoc: as long as the input to your function is valid and it is immutable, no-one is going to be able to cause havoc from "outside" :)

17:22 somnium: ,(let [a '(fn [x] (println x))] ((eval a) a))

17:22 clojurebot: DENIED

17:22 Chousuke: ngoc: and if someone calls your functions with improper input, that's their problem :P

17:22 LauJensen: prospero_: Yea I think so

17:23 ngoc: Chousuke: In Java most of the time we define a class, then create objects from the class. In Clojure do we usually need to do this way?

17:23 somnium: ngoc: what does a class actually do?

17:23 chouser: technomancy: ok, don't worry about it.

17:24 albino: It bundles the methods into a container?

17:24 Chousuke: ngoc: just use plain vectors, sets, maps and sequences as much as you can. of course, you can document that a function returns something and the user should not care that it's actually just a vector

17:24 ngoc: A class wraps code and data (state)

17:24 somnium: its more or less a hashmap of fields and functions right?

17:24 chouser: technomancy: it appears to be building the set of bridge methods incorrectly -- still trying to figure out what exactly and why.

17:24 Chousuke: ngoc: yeah. and state is bad :)

17:24 (uncontrolled)

17:25 technomancy: chouser: so does proxy actually use transient sets?

17:26 Chousuke: ngoc: with clojure, there's usually no need to bundle functions with the precise data type they work with.

17:26 ngoc: I think state is not bad, uncontrolled mutation is bad. In Erlang we store state in a function loop.

17:26 chouser: technomancy: yep, via into

17:27 Chousuke: ngoc: right. I was mostly referring to the OOP way of wrapping a bunch of state in an object and then thinking that somehow solves the problem :P

17:27 hiredman: state is bad

17:28 it makes processes non-functional

17:28 somnium: - (defn cat [name, color] {:name name :color color :purr (fn [] "meow")})

17:28 hiredman: state gets in the away of repeatability and adds complexity

17:28 Chousuke: ngoc: just look at the core functions. many of them work with sequences. they don't care what the actual input is, as long as you can make a sequence out of it.

17:28 hiredman: state makes reasoning about code harder

17:29 ngoc: I come from Java and Erlang. I tend to use agent and struct all the time. I feel these are not the "Clojure way", but don't know how to do.

17:29 Chousuke: ngoc: well, first realise that structmaps are just regular maps optimised to share a set of keys.

17:30 and agents are fine, but you might want to look at refs and atoms too, for concurrency.

17:33 ngoc: (defn cat [name, color] {:name name :color color :purr (fn [] "meow")}) <-- this constructor is what I mean "struct", is there problem of structuring Clojure programs this way?

17:34 Chousuke: nah.

17:35 cemerick: ngoc: that's all we do, aside from a little special sauce on the side to allow us to treat the struct as an instance of a given Java interface from that side of things.

17:36 hiredman: ngoc: why put the function in there?

17:37 somnium: ... it would have made more since if the output closed over name and color, my fault

17:37 hiredman: nah

17:37 Chousuke: as a silly example, consider a "birthday" function in a life simulator or something; it takes a creature and increments its age by one. in OOP you'd have Creature class with a creature.birthday() or something. in Clojure, I'd just do (defn birthday [thing] (update-in thing [:age] inc)) and represent my things as simple maps with the :age key. the fun thing is, that the birthday

17:37 function works for updating any associative thing with an :age key; not just subclasses of Creature

17:37 that's the kind of polymorphism I like /:

17:37 hiredman: closures and objects are the same thing, replacing one with the other does nothing

17:38 you are better off using multimethods

17:38 ambient: there is only lambda :o

17:39 ngoc: hiredman: another way is (defn cat [name, color] {:state {:name name :color color}, :klass 'cat}), and in cat.clj: (defn purr [] "meow")

17:40 hiredman: ngoc: sure, but what if you have other animals

17:40 (defmulti happy (comp type first list))

17:40 technomancy: why does into create fns and call them immediately instead of just calling loop?

17:41 ngoc: hiredman: Which means "cat.clj" is a Java class but it contains only code, data is stored outside

17:41 hiredman: no

17:41 chouser: technomancy: I think rhickey said that was an artifact on an earlier implementation that just hasn't been cleaned up yet. or something.

17:42 technomancy: chouser: gotcha

17:42 chouser: technomancy: the problem is invoked at line 218: bridge? (reduce into #{} (map second mb))

17:42 hiredman: ngoc: data is not "stored" outside

17:42 there is no outside

17:42 chouser: change that to bridge? (reduce (partial reduce conj) #{} (map second mb)) and it works fine

17:44 technomancy: chouser: but does it indicate a problem with into?

17:44 chouser: not into itself

17:45 technomancy: right, but with the persistent hash set

17:45 which bubbles up via into

17:45 chouser: yes

17:45 (count (into {} (map #(vector % %) badseq))) ==> 6

17:45 (count (into #{} badseq)) ==> 2

17:45 oh, wait...

17:47 ngoc: hiredman: I mean we must pass data to all functions in cat.clj when we call them, thus data is stored "outside"

17:47 hiredman: outside of what?

17:48 somnium: felix.purr vs. (purr felix) ?

17:48 kunley: Hi.

17:48 ngoc: hiredman: outside cat.clj

17:48 hiredman: ,(-> felix purr)

17:48 clojurebot: java.lang.Exception: Unable to resolve symbol: purr in this context

17:49 kunley: Is there a way to interrupt a current call without killing REPL?

17:49 hiredman: ngoc: cat.clj is a source file, are you saying you store data in you source files?

17:49 your

17:51 if I create a new Object what source file does it live in?

17:52 ngoc: hiredman: I mean "define". OK if I write cat.clj this way, it's just like using C to write program in OOP style. Is there another way?

17:52 hiredman: ngoc: but you did define the it in side cat.clj

17:53 (defn cat [name color] {:name name :color color})

17:53 there, it is defined

17:53 technomancy: chouser: I can't trigger incorrect behaviour calling into with a set myself

17:53 though I guess the stuff that proxy is doing is a lot more complicated than what I'm trying

17:54 chouser: technomancy: well, it's a set of Methods which may be part of the problem.

17:54 technomancy: wow; that function is two lines short of 200

17:55 ngoc: (defn cat [name color] {:name name :color color}) <- this is a constructor to create a cat state. Anyway what's your point? What do you want to say?

17:57 somnium: ngoc: it doesn't create state, it creates an immutable map

17:57 serp_: I think a cat has more properties than name and color

17:57 hiredman: ngoc: what state?

17:57 that constructs an immutable cat value

17:58 like the number 1

17:58 somnium: ngoc: to manage state you could (def felix (atom (cat "felix" "purple")))

17:59 ngoc: hiredman: felix now has a state

18:00 somnium: assuming felix may need to change his name to "fluffy" or his color to blue or something in the forseeable future

18:00 hiredman: ngoc: you mean with the atom?

18:00 please be aware that I did not use an atom

18:01 ngoc: yeah, an id has a state has a value

18:01 hiredman: what id?

18:01 ngoc: felix

18:02 hiredman: an atom has state and its state is a function of its past state

18:02 but I am not talking about atoms

18:03 (defn cat [name color] {:name name :color color})

18:03 no state

18:03 {:name "bob" :color :white) is immutable

18:03 er, |

18:03 }

18:04 chouser: technomancy: the problem is not new, I think.

18:05 (count (into [] (into #{} badseq))) ==> 6

18:05 (count (into #{} badseq)) ==> 2

18:05 ngoc: I know all about immutable because I come from Erlang. I just want to ask if I write cat.clj this way, it's just like using C to write program in OOP style. Is there a better way? A "Clojure way"

18:05 chouser: That's before the

18:05 technomancy: chouser: badseq is made up of method objects?

18:05 hiredman: ngoc: what style?

18:06 chouser: That's before the TransientSet stuff. That shouldn't be possible, right?

18:06 technomancy: sure doesn't seem like it

18:06 hiredman: I can assure you {:name "bob" :color :white} has very different properties from a struct in C

18:06 chouser: (count (seq (into #{} badseq))) ==> 6

18:07 technomancy: chouser: where did you get badseq?

18:08 chouser: technomancy: (def badseq (reduce into [] (map second MB)))

18:08 where MB is the value of mb from line 215 of proxy_core.clj

18:08 ...when you run (proxy [java.io.StringWriter] [])

18:08 technomancy: gotcha

18:09 chouser: I've gotta go. If we can't figure this out this evening, I'll just roll back cgrand's patch until someone can fix it.

18:09 ngoc: hiredman: OOP style in C. You pass the immutable struct to functions to get another struct.

18:09 technomancy: OK, thanks for looking at it

18:10 hiredman: ngoc: that is functional style in C, OOP style is generally to mash all over the struct and return null

18:10 pardon, NULL

18:10 somnium: I like that description of OOP

18:12 hiredman: actually, I guess it wouldn't have the return type void and just not returning anything, I dunno if that is semantically equivilant to returning NULL

18:13 somnium: usually you can at least get back a pointer to the struct you're abusing

18:13 hiredman: to really be safe you would need to do a deep copy of the struct

18:15 I mean, any function can just traipse in and hose a string, since the string is just an exposed null terminated character array

18:15 it's barbaric

18:15 funkenblatt: don't knock barbarians

18:15 they conquered most of europe

18:16 still wouldn't want to program with them though

18:16 ankou: hi, what exactly does the private key in the metadata of functions? Does it only affect javacode, or does it also prohibits access from other namespaces or what does it?

18:17 technomancy: funkenblatt: so no visigoth-driven-development for you?

18:18 funkenblatt: not unless it happens to be politically expedient at the time

18:18 hiredman: funkenblatt: yes, but the upper class of the barbarians were heavely influenced by rome and spent most of their time trying to legitimize their authority by expressing it in roman modes

18:19 * hiredman just finished "The Inheritence of Rome"

18:19 technomancy: "upper class barbarians" is a funny concept.

18:20 hiredman: well, the ruling elites

18:20 funkenblatt: so i guess the lesson learned here is that C programmers will eventually adopt our ways after they've crushed us

18:20 hiredman: C programs already did crush us

18:21 we are somewhere around 1300

18:22 funkenblatt: hmm... after they've crushed a few new uprisings

18:24 technomancy: (= (.hashCode (first badseq)) (.hashCode (second badseq))) ;; true

18:24 (.contains (hash-set (take 1 badseq)) (second badseq)) ;; false

18:24 that's a bug all right

18:41 rhickey: technomancy: inequal things can have the same hash code

18:41 chouser: all methods have the same hash code apparently. :-)

18:42 technomancy: chouser: well that would do it.

18:43 chouser: but (count theset) != (count (seq theset)) is clearly a bug, and apparently predates cgrand's patch

18:44 rhickey: Chouser: I'm dropping in late, where's the example?

18:44 chouser: it's hard to construct data that shows the problem. our only current example is proxy

18:45 in master (proxy [java.io.StringWriter] []) throws an exception

18:46 reverting cgrand's TransientHashSet patch "fixes" proxy, but I'm getting this weird set behavior even before his patch

18:47 rhickey: Chouser: I get: #<StringWriter$0 >

18:47 chouser: in latest master!?

18:47 technomancy and I are both seeing this.

18:48 * technomancy may not be much help in fixing this, but at least he's learning a lot! =)

18:48 * churib has also trouble with actual clojure-mode

18:48 chouser: churib: I think that's because of the proxy thing. Just back out the last few revs of clojure for now

18:49 rhickey: ok, I had 868f865bfc5445bea6d6092bc780f05ab0d23c21

18:49 technomancy: churib: using master and swank-clojure?

18:49 rhickey: must have been introduced since

18:49 technomancy: churib: or just clojure-mode by itself?

18:49 churib: chouser: yeah, will try that

18:49 technomancy: nope, master and swank-clojure

18:50 technomancy: churib: master~4 is far enough back

18:50 churib: k, will give it a try - thanks!

18:50 chouser: ,(let [badseq2 (concat (.getMethods java.io.StringWriter) (.getDeclaredMethods java.io.StringWriter)) badset2 (into #{} badseq2)] [(count badset2) (count (seq badset2))])

18:50 clojurebot: [26 26]

18:50 chouser: hmph. I'm getting [16 26] for that

18:51 rhickey: ok, I can reproduce it here

18:51 I imagine it's the TransientSet patch?

18:51 technomancy: rhickey: that's what made proxy break, but this odd set behaviour predates it.

18:52 chouser: not sure how often clojurebot updates

18:52 I get [16 26] here

18:52 chouser: that's with 64323d8c6ad4962ac780d4d904b69a891ab312f8

18:53 technomancy: you don't need getDeclaredMethods

18:54 hiredman: not too often

18:57 technomancy: interesting that toString shows 26 elements

18:57 (count (re-seq #"Method" (str badset2))) ;; <= 26

18:58 while (count badset2) is 16

18:59 rhickey: this is a map bug, must be some other count maintenance issues with the new map code

19:00 technomancy: right, since APersistentSet passes off a lot of things to its impl

19:00 chouser: oh, indeed. I thought I had tests showing hash maps were ok

19:01 ,(let [badseq2 (.getMethods java.io.StringWriter) badset2 (into {} (map vector badseq2 badseq2))] [(count badset2) (count (seq badset2))])

19:01 clojurebot: [26 26]

19:01 chouser: that's [16 24] here

19:14 technomancy: so transient maps have been around for a while; I guess this suggests that the count is broken there?

20:02 rhickey: fixed

20:02 http://github.com/richhickey/clojure/commit/b4095306ddc59c1a992c39369f06f1315b97d377

20:03 technomancy: rhickey: awesome; thanks!

20:03 rhickey: np

20:04 It would be good if cgrand gave it an audit as well

20:04 technomancy: those darn hash collisions...

20:09 rhickey: yeah, looks like reflect Methods have crappy hashes

20:09 same name, same hash

20:11 HashCollisionNode obviously wasn't getting much exercise otherwise

20:12 technomancy: pretty edge-casey, yeah

21:04 chouser: That would make for a very interesting screencast. 1 hour of rhickey hunting a bug

21:08 hiredman: I think it might have a limited audience

21:23 chouser: hm, perhaps

21:42 Makoryu: , (3 "pizza")

21:42 clojurebot: java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn

21:43 Makoryu: ^ What's the idiomatic way to do this?

21:43 hiredman: do what?

21:44 you are trying to call an Integer as a function

21:45 Integers are not functions, incase that was not clea

21:45 r

21:45 Makoryu: (:a {:a \a})

21:45 , (:a {:a \a})

21:45 clojurebot: \a

21:45 Makoryu: I was trying to do this :p

21:45 hiredman: ,(ifn? :a)

21:45 clojurebot: true

21:45 hiredman: ,(ifn? 3)

21:45 clojurebot: false

21:46 Makoryu: Let me be clear: What's the idiomatic way to get the nth item of an arbitrary sequence?

21:46 hiredman: ,(doc nth)

21:46 clojurebot: "([coll index] [coll index not-found]); Returns the value at the index. get returns nil if index out of bounds, nth throws an exception unless not-found is supplied. nth also works for strings, Java arrays, regex Matchers and Lists, and, in O(n) time, for sequences."

21:46 Makoryu: ..... oh. _>_

21:48 s/_>_/>_>/

22:10 churib: swank works also again

23:55 is there a function that inserts elements at any position in vectors, with shifting next elements?

23:56 clojurebot: function is <Chouser> there is one class per fn, one instance of it per closure

23:59 churib: or are zippers the right way?

Logging service provided by n01se.net