#clojure logs

2008-04-15

00:23abrooksChouser, frodwith: -> turns (-> x c b a) into (a (b (c x))). x is placed into a list if it's not a list already.
03:56vincenzWhat does . do?
04:43vincenzDumb question, how do I clear the repl variables if I'm doing interactive programming with SLIME?
04:58vincenzclojure is great )
04:58vincenz:)
05:18cgrand. is a pecial form for java interop
05:19cgrandjava: myObject.myMethod(arg1, arg2)
05:19cgrandclojure: (. myObject myMethod arg1 arg2)
05:27vincenzOh I thought the syntax was
05:27vincenz(. myObject (myMethod arg arg2))
05:27vincenzthat's what I've been using, since it complained n (. myObject method)
05:50cgrandIt depends which version you are using
05:51cgrandsee http://groups.google.com/group/clojure/browse_thread/thread/dd64bd49191f8062/9ef373abfb6e5b57
05:52vincenzThank you
05:52vincenzBtw, does the designer of clojure ever come in here?
05:55cgrandHe connects to this channel every day but right now it's a bit early.
05:56vincenzAlright thank you, I've watched the two movies, one one clojure and concurrency and one on clojure squences. Ihaven't dug in yet into actually using it but overall it gave me a good feel for the language, and I agreed with most of his design decisions.
05:57cgrandOn which decisions do you disagree?
05:57vincenzne
05:57vincenzWel more like the lack of one
05:58vincenzAnyways, in regards to sequences, I very much agree with the interface he chose for, and in my own research I have come to conclusions about a similar interace
05:58vincenzWhat I feel is missing...
05:58vincenzHmm
05:58vincenzDo you mind if I delay this conversation? colleagues are asking me for lunch
05:59cgrand(no, pb we seems to be in the same timezone... lunch time!)
05:59vincenzTtyl
06:58vincenzre
07:26vincenzrhickey: Hi
07:27vincenzrhickey: You're the author of clojure?
07:27rhickeyyes
07:27vincenzI saw your two presentations on the concepts behind it and must admit I'm rather interested, and wanted to throw an idea at you.
07:28vincenz(The one on clojure and concurrency, and the one on sequences)
07:28rhickeyok
07:30vincenzIf I were to analogize clojure with an existing lisp, I would look at scheme. However scheme has something which clojure does not have: continuations. There are several types of continuations: the old noes, then the direct ones (shift/reset). I doubt the first would be well-behaved in the presence of the STM-stuff you have. The secon might be, but only limitied to some contexts. However, there is a third type coof continuation, 'sub-con
07:32rhickeyThat did get cut off - seems like a good question for the google group
07:32vincenzAlright, I will write a post tonight then. I am not certain how feasible it would be on the JVM.
07:33vincenzBut it would be an interesting excercise to find out how this meshes with the concurrency model of clojure.
07:33vincenzIs there some white paper on the core primitives?
07:33rhickeyJust the web site
07:33vincenzOk
07:40vincenzJust so I get it correctly: functions passed to agents enter into the agent's thread, and threads block on sync-blocks until such sync-blocks succeced, and only then continue with any possible code that may fall after it?
07:43rhickeyNot quite. Each agent doesn't have a thread, but actions sent to agents are asynchronous and will happen on 'another' thread eventually, i.e. send returns right away. sync is synchronous, but not necessarily blocking at all - but a sync block may be run more than once until it succeeds
07:46vincenzJust like STM in Haskell :)
07:46rhickeysort of, there is no or-else
07:47vincenzI presume side-effects are delayed just as agent-calls are?
07:47vincenz(E.g. IO)
07:47rhickeythe only side effects you can use are agent sends
07:47vincenzWhat about 'println'
07:47rhickeybut that is by convention - I can't control Java
07:49vincenzActually, it would be interesting to make an IO agent. That way IO happens similarly to how all other agent stuff works. Maybe you could bottle the java-stuff in that IO agent as well. Sort of like an IO monad, except in this case it's a separate thread.
07:49rhickeyI don't like monads
07:49vincenzYou wouldn't have monads
07:49rhickeyAnd not all Java stuff has side-effects
07:49vincenzBut that way you wouldn't have something happen twice in case a sync-block is rerun.
07:50rhickeyPeople can use agents for that, but I'm not going to automate since I can't determine when the Java call would need that isolation
07:50vincenzE.g. (dosync (print "Hello") (readsomevariable) (writesomevariable))
07:50rhickey(dosync (send an-agent print "Hello") (readsomevariable) (writesomevariable))
07:51rhickeyDIY
07:51vincenzFair enough :)
07:51vincenzI wasn't here to critique that choice, just an interesting topic to talk about :)
07:52rhickeyJava is a hole I'm not going to plug - instead I've focused on giving safe, correct, efficient alternatives
07:52vincenzWell I wasn't targetting Java specifically, more the IO stuff, since that's well defined as a library as is. But indeed, a DIY approach there would suffice.
07:53vincenzBesides, the JAva-side would probably make coding some stuff really painful if you needed data to come back.
07:54rhickeyyes, transactional IO is not straightforward in any case
07:54rhickeyespecially the I
07:55rhickeyinput/transaction/output will be a common pattern
07:55vincenzEither way, I would block your thread and thus block your sync pattern.
07:55vincenzSo it's probably a poor choice to do I insidea transaction
07:55rhickeyblocking in sync is a no-go
07:55vincenzContinuations and transcations are also an open problem
07:56vincenzI'll try to reread your exact threading model tonight as well as that paper I have in mind
07:56vincenzand try to figure out an early possible solution, open for discussion
07:56vincenzThough I wonder if this would even be possible on the JVM :|
08:00vincenzFinally, I must say that your abstraction for sequences is really elegant. I've -vaguely- envisioned something similar (I work on optimizations of data-types, concretely sequences), but this was a very nice crystalization :)
08:01rhickeyIt's just cons/car/cdr freed from cons cells :)
08:01vincenzSure, but you
08:01vincenz'
08:02vincenzWhoops, but you need a persistent model of a vector :)
08:02rhickeyyes, extending to vectprs and maps is probably Clojure's contribution, though I don't claim novelty for any of Clojure
08:04vincenzAnd in the end, this is the model you need
08:04vincenzIt's a zipper like model
08:04vincenzIterator models are fundamentally broken
08:05vincenz(And are completely useless, as soon as you alter your sequence through one of the iterators, you invalidate the other ones..)
08:06vincenzAnd working in clojure almost makes me want to work in java again, as now you acn use emacs + clojure to do online coding + introspection quite easily :)
08:06vincenz(defn get-methods [x] (. (. x (getClass)) (getMethods))))
08:07rhickey(.. x getClass getMethods)
08:08vincenzThanks
08:08vincenzBut the fundamentals as explained in your videos made a lot of sense.
08:08rhickeygood
08:08vincenzThen again, as you said it "All the haskellers in the audience should be nodding"
08:09rhickey:)
08:09vincenzyou mean (.. x (getClass) (getMethods)) ?
08:10rhickeyThey all work but what I showed you is possible with the latest syntax
08:10vincenzAh, I guess the version I have doesn't have that yet.
08:10vincenzI tend to get 'No matching field found' exceptions when I don't use the parens.
08:10rhickeyok, not the latest
08:11jteothe perks of being the creator.
08:11rhickeyNo, it's up on SVN
08:11rhickeyI share :)
08:11jteotechnically, you always get first dibs rhickey.
08:11jteo;)
08:11rhickeytrue
08:12vincenzHow hard was it ot make the backend for clojjure? Say that continuations won't work on JVM, how hard would it be to to make an interpreter on some other language to test out the combination of transcations with continuations?
08:17rhickeyI'm not sure I believe in continuations ;)
08:18vincenzThey can be quite powerful when properly used.
08:18vincenzBut perhaps you're thinking of traditional continuations, not direct-style ones.
08:18vincenz?
08:20rhickeythe future-of-the-computation notion is bound to a notion of programs as calculations that doesn't resonate with me, and the implementation difficulties don't speak well for their practicality.
08:20vincenzRight, you're thinking of traitional ones
08:21vincenzThere are other types of continuations, namely direct-style/functional ones, which are far more interesting imho
08:21rhickeypaper?
08:21vincenzThey do not only have a starting point, but an ending point as well, and you only reify the path between those two points
08:21vincenzsec
08:24vincenzhttp://www.cs.rutgers.edu/~ccshan/recur/recur.pdf
08:24vincenzThis is my favourite paper on the subject
08:25vincenzand it seems I abused dterminolgy, the proper terminology is "delimited continuations"
08:26rhickeywill read, thanks
08:34vincenzI know that you can't run 'alter' outside of a sync body, but I made an alter statement escape by putting it inside a function. I get a very odd error when I run this
08:34vincenz(let ([dum (dosync (fn [](alter foobar (fn [x] (+ x 2)))))]) (dum))
08:34vincenzfoobar is simply (def foobar (ref 1))
08:35vincenzhttp://rafb.net/p/p8ehT552.html
08:36vincenznm
08:37vincenzWrong let syntax, disregard, please.
09:55vincenzrhickey: Let me know when you care to discuss the paper :)
09:56rhickeyI won't get to read it until later on
09:57vincenzrhickey: No rush :)
12:09ModiusJust wondering - and I don't know if Clojure would have to "inherit" this from the JRM or from how it interacts with it - does Clojure tend to make a reference eligible for garbage collection the last time it is referenced, or when it leaves scope? I have seen GCed languages do it both ways (C# does, Lispworks does, SBCL doesn't).
12:51ModiusI fiddled around enough to answer my question - but now have one - if (make-huge) makes a new data structure of size such that only one fits in RAM, (let [x (make-huge)] (let [y (make-huge)] (+ 1 2))) <-- This runs out of RAM - would static analysis in Closure allow this sort of code to work, or would it be some JVM limitation? What would be the pros and cons of getting something like this working?
12:54Chouserwhat was the answer to your first question?
12:54ChouserI imagine it might depend on which JVM you use.
12:55jteoi presume that since closure compiles to bytecode, it would follow the rules of the GC in the jvm you use.
12:56ModiusThe answer was, the language is retaining the reference for the full scope.
12:57ModiusThe behavior may be JVM related, or may be the language - both would be required to release x and/or y inside-scope.
12:57ModiusIt would take code analysis to know that x and y won't be used again.
12:58ModiusIf a desirable behavior, this could be taken care of via static analysis. What would be harder would be dealing with the case of calls - i.e. having the caller keep the reference alive. If this is inherent to Java calling, this early release may not be possible.
13:00ChouserI'm no language designer, but it may be impossible. Any function name can be made to point to a new definition at any time.
13:01Chouserwell... I guess if you have a lexical variable (like x above), you can see at compile time that it's not used or passed to any other funcs, so it could be freed.
13:01ChouserBut if it's passed to function f, even if f currently doesn't use it a later re-definition of f might.
13:03ModiusIt's possible as I've used environments that do it. Has nothing to do with function definition but how parameters are evaluated stored and handled at point of call.
13:04Modius(some-function (make-huge)) <-- "huge" will be made at point of call, and some-functoin will take it. To have it be eligible for collection, nothing about the caller can keep a reference to the "huge" after the call is made (or during).
13:55jgracinrhickey: thanks for elaborate explanation on my post regarding thread starvation.
13:56vincenzjgracin: link?
13:57jgracinhttp://groups.google.com/group/clojure/browse_thread/thread/960b717c4d5b95ad
13:58rhickeyjgracin: sure, it'll take a while before everyone gets comfortable with the Clojure way of looking at those issues
14:00rhickeyModius: Clojure does do releasing of locals on tail-calls, but no mid-function analysis
14:03Modiusrhickey: Thanks! I'm interested to know if the caller releases its reference to a function, and if the behavior is inherently dictated by JVM to preclude if not.
14:03Modius(Or by Java calling conventions)
14:04rhickeyno help from Java/JVM, there is no TCO, so the references are still on the stack. I manually set them to null before the tail-call.
14:13ModiusI meant on "normal" calls - function to function
14:13Modius(somefunction (make-huge)) <-- Does my call maintain a reference as well, or does somefunction have access to all of the references? (Which it could, theoretically, null out)?
14:15rhickeyall references are live until you make a tail call, no mid-function releasing
14:16ModiusI'm talking about non-recursive cases now.
14:16ModiusThe normal call to a normal function.
14:16Modius(Thanks for the answers btw)
14:17rhickeytail has to do with the position of the call, not its recursiveness. a tail call is a call whose return value is the return value of the function that called it
14:18rhickey(defn foo [] (bar) (baz)) - baz is a tail call
14:24ModiusThanks for helping me out with terminology. (defn foo [] (bar (make-huge)) (baz)) <-- when is the "huge" eligible for collection here - and to what degree is THAT dictated by Java calling?
14:26rhickeythe stack for the call to bar should be unwound on return from bar, and thus huge eligible for collection then, no help needed from me.
14:27rhickeyBut in this case, I release bar before calling baz:
14:27rhickey(defn foo [] (let [bar (make-huge)] (baz)))
15:27MarkJPrhickey: I swapped a netbeans static java framework class with a clojure generated java wrapper that forwards calls to a clojure proxy....
15:28MarkJPobject gets created on startup as it did before and the methods are being forwarded to the clojure proxy at runtime...
15:29MarkJPI am getting an assertion in one of the proxied methods about not being in an AWT thread
15:29MarkJPAssertion failed. WindowsAPI is required to be called from AWT thread only
15:30MarkJPI should still be on the AWT thread as the wrapper is being triggered just the same as it was before
15:55ericthorsenrich: If a clojure proxy is created on 1 thread and later called from another thread there _should_ not be a problem there yes?
16:20rhickeyeric: should be no problem
16:21rhickeyMarkJP: how do you ensure it gets called on the AWT thread?
16:33MarkJPrhickey: If I replace the forwarding call with the original java code, it works
17:31ericthorrich: The threading issue was related to a override of a protected method needed at the java class level...guess we will have to look at that as well.
17:32rhickeyyou can override protected methods in proxies
17:32MarkJPhow do I represent the backslash character in clojure
17:32vincenzrhickey: thanks for reply on list (I'm Christophe Poucet)
17:33ChouserMarkJP: \\
17:33ericthorI does bring up a question: What happens if you have a protected method in your proxy call? Does the clojure compiler cough on that?
17:33rhickeyyou can't access protected members in a proxy
17:34ericthori know...but you can add additional clojure functions not overridden yes?
17:34ChouserMarkJP: that's either in a string literal, or a literal directly in the code: (print (str "hi" \\ "there\\Mark"))
17:34MarkJPcool thx
17:34rhickeyeric: no, you can only implement/override methods from superclass/interfaces
17:35MarkJPand forwardslash is \/
17:35MarkJP?
17:35ericthorremember, I'm generating the java class source from the clojure code...I was wondering if I could take advantage of that to have the static java class override the protected member and forward the call to a clojure call.
17:38rhickeyif you are generating a Java shim class you can define a public method that exposes the protected member, then you can use that in Clojure
17:39ericthorok...just wondering what options were open to me there.
17:40rhickeyprotected member exposing could be a good feature for he stub generator
17:41ChouserMarkJP: \/ or just "/"
17:44ericthoragreed
17:45MarkJPericthor: there where 2 problems, the protected method, and overriding a method I shouldn't have
17:51ericthormark: ok
17:51ericthor...and oops
18:04vincenzrhickey: how hard was it to make STM?
18:22rhickeyvincenz: hard