#clojure log - Nov 30 2008

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

6:37 AWizzArd: Hi Lau_of_DK

6:38 Lau_of_DK: Good afternoon Andr� :)

6:38 kotarak: Hi you two.

6:38 AWizzArd: did you look at the contrib's sql?

6:38 Moin Kota

6:38 Lau_of_DK: Hey Kota

6:39 Yes I had a look. Im ashamed to say that my complaints came from a lack of knowledge, of the lib which was wrapped

6:39 AWizzArd: Do you still miss some important parts?

6:40 Lau_of_DK: No, select/insert are covered, and that will be enough for quite some time

6:40 AWizzArd: yes, and prepared statements and transactios also I think

6:40 Lau_of_DK: How difficult is it, so move into stored procedures?

6:41 AWizzArd: I think this can be done without problems

6:41 Lau_of_DK: Can you think of a simple example?

6:41 AWizzArd: although you will have to do it with sql, there is no special clojure magic that would help

6:41 Lau_of_DK: ok

6:44 Have any cool website written in compojure popped up yet?

6:44 AWizzArd: i think (do-commands "sql stuff here to create a stored procedure"). And then in your "normal queries" you can call them, as in (with-connection *db-conn* (with-results res "select * from tab1 where name=my_procedure(15)" ...)) or something like that

6:44 no, although I try to come up with something with Stuart Halloway

6:45 Lau_of_DK: Yea AWizzArd, it'll be something like that

6:45 Stuart... thats the guy who made the Clojure book which is prited on pure gold paper right? :)

6:45 s/prited/printed

6:45 AWizzArd: yup :-)

6:45 We would like to make the possibly most powerful webdevelopment framework available for Clojure

6:46 Lau_of_DK: In which scope?

6:47 AWizzArd: Well, we are cheating, because we won't write it ourselves, but instead make Rife available in Clojure, where Rife is a framework for Java. http://rifers.org/

6:47 check out for example this http://rifers.org/blogs/gbevin/2005/3/18/blabla_tada_in_java

6:47 hiredman: clojurebot: clojure is also cheating

6:47 clojurebot: c'est bon!

6:49 AWizzArd: hire :-)

6:49 Lau_of_DK: clojurebot: ?

6:49 clojurebot: It's greek to me.

6:49 Lau_of_DK: clojurebot: *

6:49 clojurebot: * is just for when you are lazy and sloppy

6:49 AWizzArd: clojurebot: Why?

6:49 clojurebot: Pardon?

6:49 AWizzArd: clojurebot: multimethods

6:49 clojurebot: multimethods seperate the 20% from the 80%

6:49 Lau_of_DK: AWizzArd: Rife looks interesting, and like its in its infancy ?

6:50 AWizzArd: clojurebot: multimethods

6:50 clojurebot: multimethods is what separates the boy from the man.

6:50 AWizzArd: :-)

6:50 hiredman: clojurebot: why is <reply> why not?

6:50 clojurebot: c'est bon!

6:50 AWizzArd: Lau_of_DK: I think development of Rife started around 2001, so it has more years than most other frameworks

6:51 Lau_of_DK: k

6:53 I certainly would love to see a webframework, which would wrap html, jQuery and JSon all in one, clojurish elegant looking package

6:54 oh, and Javascript

6:54 AWizzArd: The famous Bruce Tate made comments about it, also the Ruby on Rails inventor: http://rifers.org/testimonials

6:55 Lau_of_DK: hehe, famous or infamous, we'll leave that in the air

6:55 AWizzArd: Over some time the framework can be clojurized, so one does not write Java in Clojure. This should give us Rails+ productivity in Clojure

6:55 Lau_of_DK: I remember in the early days of the Googlegroup, Rich actually presenting quite strong oppinions against continuations

6:57 AWizzArd: yes, but this has nothing to do with webapplications

6:57 it basically means: users can use their back buttons and the website will just work

6:57 Lau_of_DK: k

6:58 AWizzArd: all filled out forms stay filled out.. if you accidently move backwards you can go forward again, and so on, or go back a few pages and take a different road through the website from that point on, etc.

6:58 Lau_of_DK: Its really amazing that those features havent been standarized 5 years ago

6:58 AWizzArd: Clojure itself needs no continuations. It supports threading.

6:59 Lau_of_DK: You think threading = continuations?

6:59 AWizzArd: no

6:59 but all you can do with continuations you can do with threads

7:00 hi blackdog

7:00 blackdog: hi

7:00 Lau_of_DK: he's the blackest dog I know

7:01 AWizzArd: clojurebot: clojure

7:01 clojurebot: clojure > scheme

7:02 AWizzArd: clojurebot: clojure is also the bestest programming language available.

7:02 clojurebot: You don't have to tell me twice.

7:02 Lau_of_DK: clojurebot: blackdog is the start of Black Dawg Down

7:02 clojurebot: Ok.

7:02 Lau_of_DK: clojurebot: blackdog is the star of Black Dawg Down

7:02 clojurebot: In Ordnung

7:03 Lau_of_DK: ah, german efficiency, I like

7:06 AWizzArd: how can you know that this is german?

7:06 Lau_of_DK: You mean besides the fact that he just replied to me in German?

7:06 Kerris7: haha

7:07 jleslie: hey, I'm having trouble with namespaces and :exclude, if I (use 'clojure.zip) I get a java.lang.IllegalStateException: replace already refers to: #=(var clojure/replace)

7:07 hiredman: clojurebot: are you german?

7:07 clojurebot: Excuse me?

7:07 jleslie: but I can't figure out how to get :exclude to work.

7:07 hiredman: clojurebot: well?

7:07 clojurebot: I don't understand.

7:07 hiredman: clojurebot: useless git

7:07 clojurebot: It's greek to me.

7:08 jleslie: also, looking in zip.clj seems like there's already something for excluding replace?

7:08 hiredman: I am unsure, but I think the one in zip.clj is for inside the zip.clj namespace

7:09 jleslie: ok, that seems reasonable

7:12 I've tried a variety of things like: (refer 'clojure.zip (:exclude (replace))) but haven't had any luck.

7:13 Lau_of_DK: tried (use 'clojure.zip) ?

7:13 jleslie: I get a java.lang.IllegalStateException: replace already refers to: #=(var clojure/replace)

7:14 with use, and refer.

7:14 Lau_of_DK: Maybe you should restart your REPL

7:15 Did you try (ns 'j.leslie.ns :import '(clojure.zip)) ?

7:17 jleslie: same error.

7:17 Lau_of_DK: In a fresh Repl ?

7:17 jleslie: Yeah.

7:18 AWizzArd: Hello rhickey. In http://clojure.org/compilation I think there is a closing paren missing in your -main, at the bottom.

7:19 Lau_of_DK: jleslie: then maybe its an error in clojure.zip, that it specifically tries to def clojure/replace, and not /replace in its own namespace

7:19 rhickey: AWizzArd: fixed - thanks

7:20 jleslie: I think I just need to figure out the :exclude filter, but I can't quite get it right

7:21 AWizzArd: rhickey: also I seem to not understand fully how to compile it. I copied the whole example and put it into a file test.clj which is saved in my classpath. I start a fresh clojure and type (load "test"). It begins to load, but then soon it complains.

7:21 Do I have to name the file with a specific name or put it into a specific path to make it loadable?

7:22 lisppaste8: Lau_of_DK pasted "Another Lazy mistake?" at http://paste.lisp.org/display/71257

7:22 Lau_of_DK: Can somebody help me point of the obvious, what is my mistake here?

7:23 AWizzArd: java.lang.ClassNotFoundException: clojure.examples.IBar

7:24 My plan was: (load the-file), (compile the-namespace) and then run it as you showed from the shell

7:26 rhickey: AWizzArd: all AOT compilation is based upon classpath and dir pathing, e.g. a ns called x.y.z must be in x/y/z.clj

7:26 and that path must be under the classpath

7:27 Lau_of_DK: disclaimer: My lisp-paste contains only 100% tested code and has been reviewed to eliminated typos, its quite safe

7:27 oh wait

7:27 I got it

7:27 never mind

7:27 Like I said, obvious :)

7:27 AWizzArd: rhickey: okay, I will give that a try

7:40 rhickey: my file is now in path/clojure/examples/instance.clj and the path/clojure/examples/ folder is in the classpath var. When I type (load "instance") I still get java.lang.ClassNotFoundException: clojure.examples.IBar

7:40 This is for me an indicator that the file was really found in the classpath, because otherwise I would have gotten a class-not-found exception or something like that.

7:42 lisppaste8: Lau_of_DK annotated #71257 with "Disregard above paste" at http://paste.lisp.org/display/71257#1

7:43 kotarak: rhickey: can i import classes from gen-class in the defining namespace? (ns foo.bar) ... (gen-class :name foo.bar.SomeClass) (import '(foo.bar SomeClass)) <- gives exception, that foo.bar cannot be loaded again, while it is loading.

7:44 For interfaces it works.

7:44 rhickey: AWizzArd: things get found in namespace pathed dirs under the classpath. Any component of your ns shouldn't be in the classpath, i.e. classpath = src, files in src/my/namespace/lib.clj

7:47 AWizzArd: or in your example, only path should be in classpath var

7:51 kotarak: right now, the default is that a gen-class class tries to load its implementing ns. You can control that with :load-impl-ns false

7:52 AWizzArd: I will try some more combinations. When I put path into the classpath I get java.io.FileNotFoundException: Could not locate instance__init.class or instance.clj on classpath.

7:52 kotarak: Is this :load-impl-ns a voodoo feature or is it in contained in the new interface?

7:54 rhickey: (doc gen-class)

7:54 clojurebot: Generates compiled bytecode for a class with the given package-qualified cname (which, as all names in these parameters, can be a string or symbol). The gen-class construct contains no implementation, as the implementation will be dynamically sought by the generated class in functions in a corresponding Clojure namespace. Given a generated class org.mydomain.MyClass with a method named mymethod, gen-class will

7:54 rhickey: kotarak: it's documented

7:54 kotarak: rhickey: Ok. Thanks. :)

7:56 rhickey: kotarak: I'm looking into the nesting as well, I think that a nested load might be better as a no-op

8:01 kotarak: If you could, please try 1131 on your original test case, I made nested load of already loading resource a no-op

8:01 kotarak: Ok. Just let me check.

8:03 AWizzArd: So now I have path in the classpath evn variable. The example from the website was saved in a file /path/clojure/examples/instance.clj and in a freshly opened clojure I get (load "instance") ==> java.io.FileNotFoundException: Could not locate instance__init.class or instance.clj on classpath

8:04 (.getProperty System "java.class.path") ==> "/path/"

8:05 (plus other .jar files)

8:05 rhickey: AWizzArd: you don't load it, just compile it

8:06 kotarak: rhickey: 1131 works perfectly. :)

8:06 AWizzArd: I just compiled 1130 and now there is a 1131 ;-)

8:06 Rich, you are sometimes a bit too fast *g*

8:06 kotarak: AWizzArd: Ah, Wizz! You are too slow. ;)

8:07 AWizzArd: I need a script for automatically checking out clojure, ant'ing it and copy the clojure.jar into the right dir

8:07 kotarak: But to honest: I also had to check out a fresh SVN, since I normally use the hg mirror.

8:09 AWizzArd: (compile 'clojure.examples.instance) ==> java.io.IOException: The system can't find the path

8:11 but maybe this comes from the *compile-path*

8:27 compared with CLs compile-file it is really very complicated. The Java interop is in my opinion the ugliest part of Clojure *sigh*

8:33 fran1: Hello, I'm new to Clojure. While playing around under WinXP and Linux (Ubuntu 8.04), I encountered the following behaviour: user=> (doto (new String "Test") (length)) works under WinXP (JDK 6u10) but doesn't under Linux (JDK 6u07). Any Ideas?

8:39 Lau_of_DK: Is there a better way?

8:39 (alter turtle assoc :x x)

8:39 (alter turtle assoc :y y)

8:39 (alter turtle assoc :direction d)


8:41 (this is where I expect Rich or Chouser to go (alter t^a^xyz #[vals]) or something like that)

8:42 blackdog: assoc can take multiple key vals

8:42 Lau_of_DK: (doc assoc)

8:42 clojurebot: assoc[iate]. When applied to a map, returns a new map of the same (hashed/sorted) type, that contains the mapping of key(s) to val(s). When applied to a vector, returns a new vector that contains val at index. Note - index must be <= (count vector).; arglists ([map key val] [map key val & kvs])

8:44 Lau_of_DK: Right you are blackdog, thanks

8:52 Chouser: fran1: there was a recent change to doto that would require '.length' instead of 'length' -- perhaps you have slightly different versions of Clojure?

8:56 Lau_of_DK: 1

8:57 fran1: also notice that 'a recent change' could span about 120 revisions

9:04 Chouser: 20 revisions, in this case, from 11 days ago.

9:12 kotarak: Off-Topic: How can I check in ant, whether some property is set and how to do something according to the result?

9:19 fran1: Chouser: Thank you! I've just tried it and it works.

9:19 Lau_of_DK: :-)

9:25 AWizzArd: rhickey: do you have slime installed, and jochu-swank-clojure and emacs?

9:25 rhickey: AWizzArd: nope, just Aquamacs + clojure-mode

9:26 AWizzArd: I experience some strange problems. When I go into the shell and manually run clojure from there I can compile. I can also do it from within slime via (binding [*compile-path* "/path/classes/] (compile 'clojure.something))

9:26 rhickey: given that I'm changing core clj files and Clojure itself, I need to keep it simple

9:27 AWizzArd: but .getProperty shows me that "/path/classes/" indeed is on my classpath

9:27 kotarak: AWizzArd: *compile-path* only default to "classes" in the Repl. So the SLIME stuff probably doesn't change the value. So you have to do it manually.

9:28 AWizzArd: Hmm, possible

9:29 in the repl I have *compile-path* ==> "classes"

10:18 jtoy: what is the web programming library besides webjure?

10:18 ?

10:18 i remember there is another one but cant remember the name

10:18 kotarak: compojure

10:19 jtoy: ah yes, which is more mature/robust?

10:20 duck1123_: I haven't used webjure, but I think compojure

10:20 that was why I went with that one

10:21 jtoy: duck1123_: i think so too

10:23 duck1123_: they both have a way to go

11:12 rhickey: Chouser: I've been thinking about the dynamic code gen scenarios

11:16 an additional option for runtime code-gen is to automatically gen into *compile-path* rather than in-memory, the great advantage being classes loaded from there have normal visibility

11:20 Chouser: hm... because as long as the root of that classpath element exists at startup, other classes can be created and discovered later.

11:21 rhickey: Chouser: right, that's how compilation works now, classes are gen-ed to disk and immediately available

11:23 stuart: rhickey: what happens if you gen more than once in a single runtime?

11:23 Chouser: stuart: screwed. ;-)

11:24 you could update the .class on disk, but the JVM wouldn't let you reload a new class with the same name.

11:24 If you need a named class, I'm much more sympathetic with an "only-AOT" solution.

11:25 stuart: but worse: Java programmers are used to reloading a new class with the same name by dropping a URLClassLoader and creating another one

11:25 rhickey: if you've changed anything, you'll need to reload to see the changes, otherwise it's a no-op

11:25 stuart: or more accurately having a container do it for them

11:25 rhickey: stuart: not really, if they are truly relying on the names they need to reload

11:26 stuart: I think we are saying the same thing

11:26 rhickey: e.g. container reloads them

11:26 right, so Clojure can't solve that problem, the thing at hand is the use of custom classloaders and the visibility and deploy constraints therein

11:27 Chouser: But there are times when you want to add methods (JNA, Swing, etc.) when the class name isn't important and it'd be nice to get new ones at runtime.

11:28 rhickey: Chouser: JNA was the first case I've seen of that - Swing is straight interface impls satisfied by proxy

11:28 Chouser: generally running those to disk and back wouldn't be hurt enough to matter, esp. if it solves all the visibility problems.

11:28 stuart: if you drop files into a directory serviced by a URLClassLoader, including the standard "classpath" loader, you create possible oddities

11:29 rhickey: gen-class and gen-interface are subject to macro fu, so you could call e.g. gensym to fabricate tear-off names

11:29 Chouser: rhickey: actually it's java.io.Writer proxy that I've got where I'm overriding .close to mean something entirely different. :-P

11:29 stuart: e.g. if a named class already has been loaded by a child loader, then you create an "impossible" situation, where that class retroactively shouldn't have been able to be loaded by the child

11:30 rhickey: stuart: that sound like a broken child classloader that's not delegating

11:30 stuart: it doesn't get a chance to delegate if at time A the file isn't there

11:31 and at later time B the AOT compiler puts it there. :-)

11:32 rhickey: are you talking about a classloader that either reads from disk or load from memory? I'm not advocating that

11:32 stuart: no, I am questioning the gen-to-disk approach

11:33 if I understand correctly, it doesn't compose with the way other people may be (correctly) using classloaders

11:33 because it creates a moment in time when a class does not exist, followed by a later moment time when it does

11:33 rhickey: putting the file on the disk is not a classloader thing

11:34 stuart: are you sure of that?

11:34 if you are putting the file on disk before any classloader points at that location on disk then I agree

11:34 rhickey: sure, the compiler just spits out a file and calls it a day, later some classloader loads it

11:35 it's not a side effect of a load attempt

11:36 stuart: ok as long as people aren't using the compiler at runtime to add classes to a

11:36 "live" path

11:36 rhickey: stuart: well, they might be, e.g. in a repl session

11:37 stuart: that's probably OK, if you make a mess in a REPL that's your business

11:37 rhickey: I agree the deployment of an app that needs to write to disk is a nightmare

11:37 stuart: The notion of tear-off names scares me because when I have seen it used in the past what people often

11:37 needed was tear-off classloaders

11:38 rhickey: stuart: I agree completely, people should code to interfaces, these are scenarios where some 3rd party cares about the name

11:39 stuart: cool, I will stop agitating now :-)

11:39 what's the ETA for sorting this all out to 1.0 readyness?

11:40 I am contemplating making the case study chapter a deep dive on integrating with some Java stack, and am holding writing that chapter to see what happens

11:40 rhickey: stuart: I think gen-clas is in good shape, pending feedback, also gen-interface, AOT proxy probably today

11:40 gen-class

11:40 stuart: sweet. You are writing this language faster than I can write *about* it. Awesome.

11:41 rhickey: stuart: have a look at the current version of: http://clojure.org/compilation

11:41 make sure you refresh, changed a bunch yesterday

11:42 Chouser: rhickey: AOT proxy will involve some kind of early declaration of the interfaces later runtime proxies will use?

11:42 A simple "no" will suffice, and I can learn about it when it's done. ;-)

11:43 rhickey: Chouser: no, fixed names will be generated automatically (based on supers), when compiled proxy class is pre-created, should be no change to existing code

11:44 but compiling will eliminate the need for runtime classloader for proxy, the last scenario requiring it

11:44 Chouser: oh, because proxy is already a macro it can do some "work" at compile time. of course.

11:44 rhickey: then compiled code can target applets, android etc

11:45 Chouser: beautiful.

11:45 stuart: Crikey, this is gonna need a whole chapter.

11:46 rhickey: also moving to named proxy classes (under the hood) will allow proxy constructors to be direct rather than reflective as they are now

11:46 Chouser: oh! nice!

11:46 stuart: rhickey: are you interested in bundling an ant-replacement with Clojure, with some support for building hybrid Clojure+Java apps?

11:47 I have the lancet sample code, plus fyuryu has built something I haven't had time to look at yet

11:47 rhickey: stuart: sounds like a good contrib thing to start with - I've added you to clojure-contrib

11:47 Chouser: and since calls to proxy methods will generally be coming from Java code, those have never needed reflection.

11:48 stuart: rhickey: Thanks. I will be committing stuff there soon.

11:48 rhickey: I intend to start shipping some of contrib, we just need to partition it into experimental, 3rd party dependent, and ready-to-bundle

11:48 stuart: I wish that people would build stuff anew in Clojure

11:48 rhickey: Chouser: right, users of proxy interact through the interfaces.

11:49 proxy construction was its major perf bottleneck

11:49 stuart: but I think that for about 90% of adopters, the greased-path story for dropping Clojure into framework X will be key. Whether in Clojure, or Contrib, or just a tutorial doesn't matter

11:49 ahem, 90% of adopters coming from Java

11:50 rhickey: stuart: gen-class and AOT should greatly facilitate that

11:51 stuart: agreed! and the up-in-5-minutes tutorial closes the deal for newbies. I will work on that for at least a few scenarios

11:51 Chouser: stuart: does an ant replacement really fit into that story? Surely existing projects will have significant investment in ant itself such that replacing it will seem like a non-starter?

11:51 I'm really asking, because I know essentially nothing about Java or Ant. :-)

11:52 man, swing is beating me up.

11:54 stuart: chouser: build assistance is critical. May have to be *in* ant. Worse, may have to be *in* Maven.

11:55 But I think you could automate a conversion from Ant->Lancet, or something like Lancet. And you would immediately pick up some goodness.

11:55 Chouser: hm, ok.

11:55 stuart: I'll give you a better answer in three weeks. :-)

11:56 Chouser: :-)

12:26 fyuryu1: stuart: my stuff is in no way a replacement for ant, at least not if you're doing Java+Clojure development

12:29 but so far it's been useful to me for Clojure development. automating basic tasks and avoiding editing xml

12:46 Lau_of_DK: Yo yooo :)

13:18 * Chouser continues to pour time down the Swing drain.

13:20 rhickey: Chouser: what's the drain, just unfamiliarity?

13:20 Lau_of_DK: hehe, you no like Swing?

13:20 blackdog: Chouser, you seen this one http://pivot-toolkit.org/

13:20 Lau_of_DK: blackdog: youve always got the greatest links :)

13:20 Chouser: rhickey: yes, primarily. Trying to get very specific layout behvior, and am awash in options that don't seem to help.

13:22 blackdog: no, I hadn't. I firmly believe (so far with little evidence) that Swing is sufficient. I just need to learn...

13:22 blackdog: yes it is i'm sure

13:22 but it may not be easiest

13:23 i haven't really used it in anger, but you also may find the miglayout helps too

13:23 Chouser: I'd like to use stock Java if it's at all reasonable. Aiming for tiny download...

13:24 blackdog: Chouser, let's talk in another week :P

13:25 Chouser: blackdog: :-)

13:26 rhickey: Chouser: are you targeting 1.6?

13:27 Chouser: dunno, are you? :-)

13:27 I'd like it to work everywhere clojure works.

13:28 rhickey: Clojure targets 1.5

13:28 But 1.6 has GroupLayout, I think you can get it for 1.5 a la carte

13:28 Chouser: I've got SpringLayout almost behaving.

13:29 joew: Newbie question: Can you initialize a vector with values from a list?

13:29 Chouser: (doc vec)

13:29 clojurebot: Creates a new vector containing the contents of coll.; arglists ([coll])

13:30 joew: thanks

13:34 AWizzArd: also technically possible: (apply vector my-list)

14:43 The google group has now 2^10 members

14:52 pjb3: For anybody in the DC area, there is a Clojure group forming: http://groups.google.com/group/clojure-study-dc/browse_thread/thread/500d6fb42524b182

15:39 lisppaste8: ppierre pasted "macro and ns" at http://paste.lisp.org/display/71272

15:40 ppierre: Can I get some help on macro and ns ?

15:40 I try to get ns of where macro is expended

15:40 But I can't write it with just one macro

15:43 mibu: hey, I gotta question about refs. anyone here can help?

15:44 Chouser: ppierre: I don't quite follow. it's namespace-with-default that's not behaving how you want?

15:44 mibu: go for it.

15:45 ppierre: Yes but it wouldn't work directly in intl macro

15:45 mibu: chouser: I can't figure out when I should use alter. How is it fundamentally different from ref-set?

15:46 Chouser: mibu: I think it just saves you some typing in many cases.

15:47 mibu: chouser: so, it really isn't different from a ref-set, just a fancy apply combined with ref-set?

15:47 Chouser: (ref-set foo (conj @foo 99)) vs. (alter foo conj 99)

15:47 rhickey: Chouser: alter is more clearly a function of the current state, ref-set should be reserved for overwrite

15:47 Lau_of_DK: (doc ref-set)

15:47 clojurebot: Must be called in a transaction. Sets the value of ref. Returns val.; arglists ([ref val])

15:48 Lau_of_DK: (doc alter)

15:48 clojurebot: Must be called in a transaction. Sets the in-transaction-value of ref to: (apply fun in-transaction-value-of-ref args) and returns the in-transaction-value of ref.; arglists ([ref fun & args])

15:48 mibu: rhickey: when would you use alter that is inappropriate to use ref-set?

15:48 Chouser: rhickey: but no less contention or more "complex" return values for alter over ref-set?

15:49 rhickey: ref-set says 'I don't care what was there before'

15:49 Chouser: mibu: well, probably the example I just gave. Since the new value is based on the old value, I should use alter.

15:49 rhickey: no perf or contention differences, alter is read-modify-write

15:50 alter/commute/send all have the same model, and are preferred

15:50 new state function of the old state

15:51 Lau_of_DK: rhickey: have you considered wether or not, using git locally would make you more efficient? It does export to SVN as far as I know

15:51 mibu: rhickey: but inside a transaction a ref-set over values that were deref'd (such as in chouser's example) is just as good as alter, isn't it?

15:51 Chouser: I guess that helps explain why actions are given the current agent state, even though they could get it from @*agent*

15:51 lisppaste8: ppierre annotated #71272 with "macro and ns (with function)" at http://paste.lisp.org/display/71272#1

15:52 rhickey: Chouser: exactly, note how they all let you use e.g. assoc directly, rather than making a ref or agent based function

15:52 Chouser: mibu: it works as well, but is less clear for a programmer trying to read your code.

15:53 rhickey: the idea is you can test your state transformation functions a la carte

15:53 adding refs/agents later

15:54 mibu: chouser: so, they're not fundamentally different. I was busting my head trying to figure out what's so special about alter. I guess having the triplet of ref-set,alter,commute made me think each is special (like vars,refs,agents).

15:58 emacsen: mattrepl, hey

15:58 where in VA are you?

15:58 mattrepl: fairfax

15:59 emacsen: you know about the clojure study group next week?

15:59 LOL, or do you care? :)

16:00 technomancy: how do you modify the classpath once you're in slime?

16:00 mattrepl: heh, no I didn't

16:00 is that a fringedc related thing?

16:00 mibu: a different question on the same subject, why would one call ensure to protect a ref inside a transaction? the in-transaction-value is already the same as in the entry point. is it more like touch and go, i.e. it would have the same effect as reading and re-setting the in-transaction-value on the commit point of the transaction?

16:01 emacsen: yup, FringeDC spinoff

16:02 technomancy: ah, the add-classpath function

16:02 mattrepl: emacsen: where's it at?

16:03 emacsen: mattrepl, hold on I'll get you URL

16:03 http://groups.google.com/group/clojure-study-dc

16:04 mibu: anyone?

16:04 emacsen: it's at some bar next week

16:04 but in the future it may be at HacDC

16:05 Chouser: mibu: I don't have a firm grasp on 'ensure' yet, sorry.

16:05 stuart: mibu: if consistency depends on the relationship between multiple values, then ensure provides a way to state that, without a spurious write

16:06 rhickey: mibu: you might ensure some data that you will only read, but not write, in a transaction, whose value you make a decision upon and want to pin down

16:07 It's there to prevent write-skew, a known liability of MVCC

16:07 mibu: rhickey,stuart: so essentially the semantics of ensure, if you didn't have it, is to re-set the in-transaction-value on commit?

16:08 (without actually re-setting the ref, I mean semantically)

16:08 stuart: ensure would force a tx retry if a value you ensured was written out from under you

16:08 which, in general, would be a GOOD thing for concurrency

16:09 but a bad thing for consistency if that value had to stay in some known relationship with another value that you were writing

16:09 mibu: stuart: ok. that's what I meant. so as rhickey said, it's a value-pin-down function.

16:09 rhickey: did I get this right?

16:10 rhickey: ensure protects the value as if you wrote it

16:10 stuart: this guy is pretty authoritative: http://markmail.org/message/4p4gq2xcxbqhqy6a :-)

16:10 rhickey: see this for write skew: http://en.wikipedia.org/wiki/Snapshot_isolation

16:12 mibu: rhickey: you succinctly said what I was trying to say. thanks everyone for clarifying the subject.

16:14 mattrepl: emacsen: thanks

16:15 emacsen: no problem! Hope you show up next week!

16:16 tell your friends!

16:16 tell your enemies!

16:21 technomancy: so when you send a region to slime (C-c C-r), it looks like that gets eval'd in a different namespace from the slime REPL?

16:27 AWizzArd: rhickey: do you think some should be renamed to some? to better match every? or not-any? ?

16:27 rhickey: AWizzArd: it's not the same, it doesn't return a boolean

16:33 dthomas: technomancy: Is there some kind of ns declaration at the top of the file you're calling slime-eval-region in? If so I think it may parse the NS out of that and eval the code in that name space.

16:34 AWizzArd: rhickey: (some #(= 4 %) (range 20)) ==> true

16:34 at least sometimes it returns a boolean

16:35 but yeah (some identity [nil nil 4 nil 10]) ==> 4

16:37 technomancy: dthomas: oh that makes sense. didn't expect it to be that smart

16:38 dthomas: yeah, that's it

16:44 julian_morrison: Hi all, I have a Q about multimethods: what part of the call does the dispatch function get?

16:44 if I call (my-multi 1 2 3 4) then the dispatch function gets what?

16:44 kotarak: 1 2 3 and 4

16:45 julian_morrison: as a seq? Or as arguments in their places?

16:47 rhickey: julian_morrison: as individual args, but will match to any sig that can take 4 args

16:48 AWizzArd: rhickey: why is (-) ==> Exception while (+) ==> 0 ?

16:48 rhickey: e.g. (fn [x & ignore] ...)

16:48 julian_morrison: ah, thanks

16:49 so (fn [& p] (map class p)) is a good dispatcher

16:50 rhickey: julian_morrison: could be a traditional type-based multimethod then

16:51 julian_morrison: rhickey, BTW, that would be a small useful improvement, make class do the above rather than being forced arity 1

16:51 rhickey: you might want to (vec ..) that, for ease of writing methods

16:52 julian_morrison: interesting

16:56 julian_morrison: hmm, in the above p is not itself a vec, unexpected

16:57 AWizzArd: AWizzArd: In CL (-) also throws an error.

16:57 rhickey: julian_morrison: why should it be a vec?

16:57 AWizzArd: ok, thx

16:57 :-)

16:58 julian_morrison: the param list is a vec, a slice should be a vec?

16:58 I suppose that's a weak reason

16:59 rhickey: the syntax form is a vector, the arguments aren't. & args are seqs

16:59 you can apply fns to infinite seqs

16:59 julian_morrison: lazy seqs? cute

17:04 are you planning to put splice and concat methods into persistent vectors?

17:05 rhickey: julian_morrison: there is constant-time subvec (with sharing), but concat would not be efficient in this implementation

17:07 kotarak: (def vec-cat [v1 v2] (reduce conj v1 v2)), maybe this is sufficient?

17:07 julian_morrison: rhickey: you could implement as something like a sparse vec of subvec, splice, subvec

17:07 rhickey: kotarak: (into v1 v2)

17:08 kotarak: geez. into...

17:08 julian_morrison: concat reduces to a degenerate splice as does delete

17:09 rhickey: julian_morrison: not and maintain complexity guarantees

17:10 julian_morrison: rhickey: that might be a valid trade-off sometimes though. Perhaps a "sparse-vec" datatype?

17:11 rhickey: julian_morrison: there are vector impls with log(n) perf and fast concat, I'd rather just add that than mix metaphors

17:12 julian_morrison: whatever works is good :-)

17:16 thanks, and bye all

17:16 timjr: hm, if I use recur inside a dosync, I get an error about wrong number of arguments in the recur, e.g. (loop [i 0] (if (> i 2) i (dosync (recur (+ i 1)))))

17:17 is the dosync a recur target?

17:29 rosejn: Anyone know how to create a java Enumeration from within Clojure?

17:32 rhickey: rosejn: why do you need an Enumeration?

17:33 rosejn: I'm creating an interface on top of a graph database, Neo4j

17:33 They require that the edge relations are a typed enumeration

17:33 rhickey: timjr: dosync wraps the body in a fn, so yes, but you couldn't loop in and out of a transaction anyway

17:38 rosejn: So for example, to create a relation: (.createRelationshipTo n1 n2 FamilyEdgeTypes/SON)

17:38 Where FamilyEdgeTypes is an enumeration. Not sure if that's how you should reference the SON entry.

17:40 rhickey: rosejn: http://clojure-contrib.svn.sourceforge.net/viewvc/clojure-contrib/trunk/src/clojure/contrib/enum.clj?revision=240&view=markup

17:41 note that that is based on old gen-and-load-class, butyou could do similar with new gen-class

17:43 rosejn: Great, thanks. I should have checked contrib before.

17:58 rhickey: It looks like something has changed to break defenum

17:58 The example in the documentation throws an exception

17:58 user=> (use 'clojure.contrib.enum)

17:58 nil

17:58 user=> (defenum my.package.MyEnum FOO BAR)

17:58 java.lang.ExceptionInInitializerError (NO_SOURCE_FILE:3)

17:58 user=>

18:00 Doing a stack trace, it looks like it's caused by this:

18:00 Caused by: java.lang.ClassNotFoundException: my.package.MyEnum__init

18:22 arohner: is there a fast way to turn the keys of a hashmap into a set?

18:23 or does (set (keys my-map)) do the right thing?

19:06 technomancy: what does this mean? java.lang.reflect.InvocationTargetException / [Thrown class clojure.lang.Compiler$CompilerException]

19:09 rhickey: technomancy: you can get a full stack trace with (.printStackTrace *e)

19:12 technomancy: that just returns nil. should it work even in slime, or does slime wrap the exceptions differently?

19:12 rhickey: technomancy: I don't know about slime

19:13 timjr: hm... any idea how I could list the threads that are running and interrupt one of them?

19:13 I've got an infinite loop going

19:14 technomancy: I think I just need to read up on my Java... slime gives me some kind of backtrace, but it doesn't seem to involve any of my code or the libraries I'm using.

19:20 erg: how does clojure handle the case where a multimethod defines a dispatching function and calls itself recursively in one of the methods?

19:21 technomancy: I'm trying to translate from JRuby to Clojure...

19:21 SyndFeedInput.new.build(XmlReader.new(url.open_stream)) should become (.build parser (XmlReader. (.openStream url))), right?

19:21 given the proper imports

19:22 oh, and where parser is (SyndFeedInput.)

19:29 hiredman: erg: I don't see how that needs special handling

19:31 are you asking about (recur ...) usage inside multimethods?

19:31 erg: hiredman: if your dispatching function does some preprocessing, you'd only want to do it once and not every time you recurse

19:31 hiredman: multimethods do some catching

19:32 but I don't know much about it

19:32 uh

19:32 preprocessing?

19:32 that sounds like you are doing it wrong

19:33 ouput from the dispatch function does not go to the multimethod that gets called

19:34 the output of the dispatch function is only used to pick which multimethod to use

19:34 erg: ok. that makes sense then

19:34 hiredman: clojurebot: multimethods?

19:34 clojurebot: multimethods is what separates the boys from the men.

19:35 erg: heh

19:35 Chouser: recur in a multimethod doesn't go through the dispatch function again -- it recurs within the specific method where its called.

19:35 hiredman: Chouser: good to know

19:39 timjr: hm. it seems there's no way to interrupt a thread that's in an infinite loop in java!

19:41 walters: timjr: you can Thread.stop

19:43 timjr: hm, yeah, that looks like a likely (if deprecated) option. thanks!

19:43 walters: there was a long discussion about this on the jvm languages group

19:44 one could imagine a special option for Thread which would cause the VM to drop into a thread kill check periodically

19:45 would force code to effectively stay in the interpreter instead of getting compiled

19:50 danlei: (?? :foo) => "foo"

19:50 gnuvince_: name

19:51 jleslie: whats the 'right' way to join [1 2] and [[3] [4] [5]] into [1 2 3 4 5]?

19:51 danlei: (name :asdf

19:51 gnuvince_: perfect, thanks

19:52 gnuvince_: jleslie: probably something with tree-seq

19:52 Chouser: jleslie: jleslie (apply concat [1 2] [[3] [4] [5]])

19:53 technomancy: how do you run a .clj file on the command line without loading the repl?

19:53 Chouser: use Script instead of Repl

19:53 technomancy: Chouser: and where do you specify the script file name?

19:53 just after clojure.lang.Script?

19:54 Chouser: technomancy: yes

19:54 jleslie: Chouser: beautiful. thanks muchly!

19:54 technomancy: Chouser: thanks

19:58 weird... this stuff works in Script but not in Slime.

19:58 hiredman: clojurebot: emacs?

19:58 clojurebot: emacs is hard, lets go shopping!

20:00 technomancy: clojurebot: pretty-print?

20:00 clojurebot: excusez-moi

20:21 slava: < Chouser> recur in a multimethod doesn't go through the dispatch function again -- it recurs within the specific method where its called.

20:21 that sounds like a pretty annoying limitation -- i've written tail-recursive methods before which would need to dispatch again

20:31 Chouser: slava: perhaps you could use the trampoline mechanism in that case.

20:39 timjr: I've seen code that has a {:tag java.io.StringWriter}, e.g., inside a (defn ...) form. anybody know what that's about?

20:39 hiredman: type tag maybe?

20:41 timjr: ah, I see, yeah, in that case it's a return type. it's documented under "special forms".

20:45 it's pretty nice having such easy access to java, because it means almost everything you might need is there already

20:46 like, to list threads, I just ended up using the list method from java's ThreadGroup

20:46 very handy

20:47 hiredman: nifty

21:42 rhickey: svn 1132 adds AOT compilation of proxies, no interface change

21:43 Chouser: very nice.

21:51 duck1123_: how hard would it be to give clojurebot a feed parser so he can announce new commits to clojure and contrib in the room? Would that be desirable?

21:53 has anyone done any real feed parsing with clojure yet?

21:53 * Chouser waves

21:54 duck1123_: Chouser: how'd it go for you?

21:54 Chouser: not a problem. I like zip-filter for obvious reasons.

21:55 technomancy: duck1123_: I'm trying to hook it up to Rome, but it's blowing up pretty hard.

21:55 duck1123_: I haven't gotten the opportunity to make use of zip filter yet

21:55 I've been tempted to use Abdera

21:55 Chouser: I ought to write up a tutorial.

21:56 duck1123_: Ironically, I'm an RDF guy, but I much prefer Atom

21:56 lisppaste8: technomancy pasted "nomnomnom for feeds" at http://paste.lisp.org/display/71291

21:56 technomancy: duck1123_: I think it'd be awesome to hook him up to the feeds though.

21:57 duck1123_: They do that in #laconica, I thought it was very cool

21:58 they also did new tickets, but clojure doesn't have a very definitive bug tracker. (save for the mailing list)

22:00 Chouser: we have a bot hooked up to trac at work -- check-ins, ticket updates, it's really nice.

22:18 arohner: rhickey: can we get an abs that works on ratios and bignums?

22:20 java.lang.Math/abs doesn't cut it

22:20 gnuvince_: arohner: you can write your own, it's pretty easy

22:21 arohner: yeah, but that's the same problem as string libraries in C

22:21 it's easy, but everyone will have their own

22:21 gnuvince_: I meant in the meantime

22:21 hiredman: does contrib have a mathlib yet?

22:21 arohner: gnuvince_: mine's already written :-)

22:21 gnuvince_: Not that I know of

22:21 arohner: k

22:21 arohner: hiredman: I don't think so, sounds like a good idea

22:22 gnuvince_: I was thinking that copying Factor's sequence library could be a good idea

22:22 (at least, what makes sense for Clojure)

22:22 rhickey: arohner: patch welcome

22:24 arohner: rhickey: k

22:44 timjr: hm... what would make something get stuck in alter? my program seems to just hang there forever... it must be something that another thread is doing/has done. this is the backtrace of the stuck thread: http://paste.lisp.org/display/71294

22:47 Chouser: you can reproduce it every time?

22:47 timjr: yep

22:47 I can't get it to stop reproducing it

22:47 I'm almost certainly just doing something dumb

22:48 Chouser: how much code does it take to reproduce? can you get it down to a few lines and post them?

22:54 timjr: I'm trying to figure out how to do that :)

22:55 here's one question: if I've got (dosync (alter foo ...)), where foo is a global variable, after the dosync, should every thread see the new value of foo?

22:56 I added something to a map in one thread, and later when another thread looked it doesn't seem to be there.

22:56 hiredman: erm

22:56 you mean a ref right? not a global variabl?

22:56 Chouser: a ref stored in a global var, presumably

22:56 timjr: it's (def *mailboxes* (ref {}))

22:57 Chouser: but yes, unless the viewing thread is still in a transaction, it should see the new value.

22:58 timjr: and the alter is (dosync (when-not (@*mailboxes* id) (alter *mailboxes* assoc id (java.util.concurrent.LinkedBlockingQueue.))))

22:58 Chouser: timjr: ah! yeah, don't do that.

22:58 timjr: I was hoping you'd say something like that :)

22:58 why not?

22:58 hiredman: (doc alter)

22:58 Chouser: hm, well ... hang on, let me think about that a little.

22:58 clojurebot: Must be called in a transaction. Sets the in-transaction-value of ref to: (apply fun in-transaction-value-of-ref args) and returns the in-transaction-value of ref.; arglists ([ref fun & args])

22:59 Chouser: I don't have a specific reason yet, but doing anything that might block from inside a transaction is probably a no-no.

22:59 but creating a LBQ ... not sure...

22:59 timjr: well, I don't think the constructor will block

23:00 Chouser: timjr: for kicks you could try creating it before the dosync, then assoc'ing it from inside.

23:18 timjr: ah, it looks like it wasn't stuck there, it was just executing that code repeatedly

23:19 sorry for the wild goose chase...

23:21 Chouser: not a problem, glad you figured it out.

23:22 timjr: it was a really mundane bug -- I was using threads as keys in one place and thread IDs in another, so I ended up with two different mailboxes for the same thread

23:22 dumb bugs are good :)

23:24 Chouser: :-)

23:27 Kerris7: I wonder how hard it'd be to get Clojure to work with Scala

23:27 from the same project under NetBeans

23:36 matzero: noob question (never done func programming) : I am trying to understand how the apply function works in clojure; so here is what I did:

23:36 (def x '(1 2 3))

23:37 (defn double-it ([x] (* 2 x)))

23:37 then I try to use those two by saying

23:37 (apply double-it x)

23:38 I expect to get a list with each element in it doubled

23:38 but instead i get a wrong num of args from double-it

23:38 dthomas: Is there a nicer way to write "is X in some-seq" than using (some)?

23:39 Chouser: matzero: no need for apply in that case. just (double-it x)

23:39 dthomas: (some #{item} the-seq) is a common idiom for that.

23:39 (some #{this-item or-that-item} ...)

23:40 matzero: that wont work because the double-it does type inference to figure out that it needs an int so when I pass the list it throws up

23:41 Chouser: matzero: oh, right sorry. apply is useful for calling a fn that takes multiple args, but you have a collection of items each of which should be an arg

23:41 matzero: for example, + takes multiple args, not a collection. so if i have (def x [1 2 3]) and want to add them, (apply + x)

23:41 matzero: oh i see

23:42 ok so i need to figure out how to turn that list into a bunch of args...ok let me chew on that then. thanks!

23:42 dthomas: Chouser: OK, I was not expecting a set to be callable like that. Just found the docs. Thanks for that. I figured there had to be an idiomatic way to express that.

23:43 matzero: You might also find (map double-it x) to yield the result you were originally looking for.

23:45 matzero: ok i'll try that

23:53 technomancy: ok... what's the first thing to check when code behaves differently in SLIME vs the Repl?

23:54 notallama: classpath?

23:54 matzero: maybe what jars each is pointing to? i had a similar problem since I pull from svn and build it every once in a while. But I use enclojure not SLIME

23:55 technomancy: pretty sure the classpath is OK here... how would I double-check though?

23:56 the only difference is I'm using absolute paths in the one that breaks and relative paths in the working one

23:56 no, scratch that; absolute paths both places

23:57 notallama: all that would be different should be ".", depending on where you're launching the repl from.

23:57 what's the problem, though?

23:58 technomancy: notallama: SLIME just gives this, which doesn't strike me as informative: java.lang.reflect.InvocationTargetException (NO_SOURCE_FILE:0) / [Thrown class clojure.lang.Compiler$CompilerException]

23:58 Repl works fine; clojure.lang.Script exits with no output, but no exception either.

23:59 lisppaste8: technomancy pasted "nomnomnom" at http://paste.lisp.org/display/71299

23:59 technomancy: there's the code

Logging service provided by n01se.net