2009-09-05
| 01:50 | hiredman | ~sandbox |
| 01:50 | clojurebot | sandbox is http://calumleslie.blogspot.com/2008/06/simple-jvm-sandboxing.html |
| 03:45 | mathias | I am trying to start swank separately to be able to connect to it from a separate emacs instance. I am able to start the swank server and even connect to it from emacs but I never get a lime buffer up. I can send things for evaluation from a normal emacs buffer but how do I get the REPL? |
| 03:45 | mathias | I start clojure like this: java -cp clojure/clojure.jar:swank-clojure clojure.lang.Repl |
| 03:46 | mathias | I then do: (require 'swank.swank)... |
| 03:46 | mathias | and lastly: (swank.swank/start-server "/tmp/slime02" :port 4005 :encoding "utf-8") |
| 03:50 | hiredman | clojurebot: how can you start swank seperately and connect to it from emacs? |
| 03:50 | clojurebot | with style and grace |
| 03:51 | hiredman | (sorry) |
| 03:53 | mathias | hiredman: ? |
| 03:54 | hiredman | not an emacser, so I don't know anything about swank |
| 03:55 | mathias | hiredman: ah |
| 04:48 | tomoj | aw he left |
| 05:38 | octe | can i refresh a package loaded with the use-method? |
| 05:54 | LauJensen | (use :reload-all ns) |
| 05:56 | LauJensen | @ octe |
| 07:12 | octe | LauJensen: thanks |
| 07:14 | LauJensen | np |
| 10:34 | slyrus_ | rhickey: who was the author of the database book you mentioned near the end of the blip.tv talk? Andres Rieter? I think I'm spelling that wrong. |
| 11:41 | winterstream | I've been poking around clojure-contrib to see how test-is should be used. One thing I can't figure out is how to define a variable that can be used by all tests in a given namespace - that is, I only want to do the work of setting up the variable once. |
| 11:41 | winterstream | Does anyone know how to do this? |
| 11:46 | Chousuke | hmm |
| 11:47 | Chousuke | there's the custom test hook, and fixtures. |
| 11:51 | winterstream | Chousuke: Thanks for the tip. I think I'm just going to take a shortcut now. I want to load a fairly large XML file for my tests, but I think I'll trim it down and include it as a string in my file. |
| 11:51 | kiras | i've been reading through "Programming Clojure" and i have a question about one of the examples. i'm sure it's really simple, but i'm new to clojure/lisp and somewhat confused. is it ok to show code here or is there a pastebin site that people generally use? |
| 11:52 | LauJensen | ~paste |
| 11:52 | clojurebot | lisppaste8, url |
| 11:52 | lisppaste8 | To use the lisppaste bot, visit http://paste.lisp.org/new/clojure and enter your paste. |
| 11:52 | LauJensen | Go go go :) |
| 11:52 | kiras | ty :) |
| 11:53 | Chousuke | winterstream: you could also just use a function that loads it once and caches the result |
| 11:54 | winterstream | Chousuke: That would actually be the best way; I should learn how to memoize in Clojure anyway :). |
| 11:54 | Chousuke | hm |
| 11:55 | Chousuke | (doc memoize) |
| 11:55 | clojurebot | "([f]); Returns a memoized version of a referentially transparent function. The memoized version of the function keeps a cache of the mapping from arguments to results and, when calls with the same arguments are repeated often, has higher performance at the expense of higher memory use." |
| 11:55 | winterstream | So now I can be even lazier :). Thanks. |
| 11:55 | Chousuke | dunno if that works for functions with no arguments though :/ |
| 11:56 | winterstream | If not, I'll just hack it by adding an unused parameter :) |
| 11:56 | kiras | http://paste.lisp.org/display/86614 |
| 11:57 | kiras | my question has to do with line 3. in the book, it says "On line 3, the zero-argument body returns the concatenation of the basis values [0 1] and then calls the two-argument body to calculate the rest of the values." |
| 11:58 | LauJensen | So whats the question? |
| 11:59 | Chousuke | hm, the wording of the book is a bit weird. |
| 11:59 | kiras | so... does concat return values multiple times? or does it calculate the value once and then return it? |
| 11:59 | kiras | did i phrase that ok? |
| 11:59 | Chousuke | concat just concatenates two sequences |
| 12:00 | Chousuke | (lazy-seq-fibo 0 1) call produces a lazy sequence, so concat concatenates [0 1] with that sequence |
| 12:00 | LauJensen | ,(concat [1 2] [3 4]) |
| 12:00 | clojurebot | (1 2 3 4) |
| 12:00 | LauJensen | clojurebot: compute! |
| 12:00 | clojurebot | Pardon? |
| 12:01 | kiras | ok. the way the book put it, it seemed like it was saying that concat returned (0 1) first, then called (lazy-seq-fibo 0 1) |
| 12:02 | kiras | at least, that's how it seemed to me |
| 12:02 | Chousuke | well, the (lazy-seq-fibo 0 1) gets evaluated when it's passed to concat. |
| 12:02 | Chousuke | but the result of it is a lazy sequence, so no *items* of the sequence are actually produced |
| 12:03 | kiras | well, i think i understand the lazy sequence part |
| 12:03 | Chousuke | and since concat is lazy too, no additional items will get computed until you have consumed the first two (the [0 1]) from the resulting sequence. |
| 12:04 | kiras | i was mostly confused about how arguments to concat were evaluated |
| 12:04 | kiras | oh |
| 12:04 | kiras | lol |
| 12:04 | kiras | i think i'm confused again... |
| 12:04 | Chousuke | arguments to functions are always evaluated. |
| 12:04 | kiras | ok |
| 12:05 | Chousuke | but the thing is, when evaluated, (lazy-seq-fibo 0 1) produces a lazy sequence, and unless you actually try to access items from the sequence (which concat won't do until it's needed), then no items will be computed |
| 12:06 | kiras | ok... so basically, if it wasn't lazy, it would produce the whole set of fibonacci numbers? |
| 12:06 | Chousuke | yes. |
| 12:06 | kiras | ok |
| 12:07 | LauJensen | kiras: I dont know if you already got this, but if not this might help: http://paste.lisp.org/display/86614#1 |
| 12:08 | kiras | laujensen: ty, i'll look at that |
| 12:12 | kiras | LauJensen: i understand your example. at the moment, i think i'm ok with the recursion that i've seen, just the lazy sequence part is something i don't remember coming across before. |
| 12:12 | LauJensen | Just the simplest for of dispatching on argument count |
| 12:12 | LauJensen | Alright |
| 12:12 | kiras | ty |
| 12:13 | LauJensen | But you understand now? |
| 12:14 | kiras | well... sort of... i guess to really understand, i might have to look at how lazy-seq actually works with take and similar functions |
| 12:17 | LauJensen | ,(doc lazy-seq) |
| 12:17 | LauJensen | You can use that in your emacs repl when new functions come up |
| 12:17 | clojurebot | "([& body]); Takes a body of expressions that returns an ISeq or nil, and yields a Seqable object that will invoke the body only the first time seq is called, and will cache the result and return it on all subsequent seq calls." |
| 12:18 | Chousuke | hmm |
| 12:18 | Chousuke | ,(lazy-seq 5) |
| 12:18 | clojurebot | Don't know how to create ISeq from: Integer |
| 12:18 | kiras | ty, i was actually reading that just now lol |
| 12:18 | Chousuke | ah, right. |
| 12:27 | kiras | so a lazy-seq is "a Seqable object that will invoke the body only the first time seq is called..." |
| 12:27 | kiras | ? |
| 12:28 | LauJensen | Yes sir |
| 12:28 | kiras | so is it actually a sequence or does it just implement the ISeq interface? if that makes any sense? |
| 12:30 | Chousuke | ,(ancestors (lazy-seq [1 2])) |
| 12:30 | clojurebot | nil |
| 12:30 | Chousuke | huh. |
| 12:30 | Chousuke | ,(ancestors (class (lazy-seq [1 2]))) |
| 12:30 | clojurebot | #{java.lang.Iterable clojure.lang.ISeq java.util.Collection clojure.lang.Seqable java.util.List clojure.lang.IMeta java.lang.Object clojure.lang.IObj clojure.lang.Obj clojure.lang.Sequential :clojure.contrib.generic/any clojure.lang.IPersistentCollection} |
| 12:30 | LauJensen | As I understood it in plain english, its a sequence of items where each expression is calculated when you eval it. Ex (take 5 (iterate inc 1)) will return (1 2 3 4 5), the next item is 6, but its not calculated, and 1-5 is cached for future calls. |
| 12:31 | Chousuke | take itself produces a lazy seq though |
| 12:31 | Chousuke | at least, IIRC :) |
| 12:32 | LauJensen | true |
| 12:32 | Chousuke | ,(take 2 (take 5 (iterate (fn [x] (do (println x) (inc x)))))) |
| 12:32 | clojurebot | java.lang.IllegalArgumentException: Wrong number of args passed to: core$iterate |
| 12:32 | Chousuke | oops |
| 12:32 | Chousuke | ,(take 2 (take 5 (iterate (fn [x] (do (println x) (inc x))) 1))) |
| 12:32 | LauJensen | You forgot the offset |
| 12:32 | clojurebot | (1 2) |
| 12:33 | Chousuke | weird, nothing printed :P |
| 12:33 | LauJensen | its in the inferior lisp buffer :) |
| 12:36 | kiras | when you say "1-5 is cached for future calls" how long are those values cached? |
| 12:38 | Chousuke | kiras: until they're no longer referenced. |
| 12:39 | Chousuke | and they're referenced as long as you hold on to the head of a sequence that contains them. |
| 12:39 | kiras | Chousuke: so if they aren't stored in a variable or the such, they would be calculated again, right? |
| 12:39 | Chousuke | well |
| 12:40 | Chousuke | if you do (let [x (iterate inc 1)] [(take 5 x) (take 10 x)]) then on the first take call, the values get calculated, but for the second the cached ones would be used for the first 5 and then again calculated |
| 12:41 | kiras | that makes sense |
| 12:41 | LauJensen | kiras: but short answer is yes |
| 12:42 | Chousuke | the caching is why you don't want to do (def fibos (lazy-fibo)) |
| 12:42 | kiras | hehe |
| 12:42 | Chousuke | because then if you did (take 10000 fibos) then it'd hold on to the 10000 fibos until the program ends (or until fibos is redef'd) |
| 12:43 | kiras | right |
| 12:43 | Chousuke | accidentally holding on to the head of lazy sequences is the main cause of out of memory errors in programs btw :) |
| 12:43 | kiras | lol |
| 12:44 | Chousuke | it's sometimes difficult to see if you're holding a reference to something or not. |
| 12:44 | kiras | i was wondering if that was a very common mistake or not |
| 12:44 | LauJensen | kiras: Chousuke does it all the time |
| 12:44 | Chousuke | especially because the clojure compiler currently does not nullify references after last use. |
| 12:44 | Chousuke | only at tail calls |
| 12:48 | kiras | i never really thought about that. do you mean that, if you were to do (def fibos (lazy-fibo)) and store a lot of numbers in there, used them once and then never used them again, it might be possible for the compiler to know the fibos was never going to be used again and set it to null? |
| 12:48 | Chousuke | nah, not that. |
| 12:48 | Chousuke | I meant local references |
| 12:49 | LauJensen | kiras: As it is now, that reference would be kept until program termination |
| 12:50 | Chousuke | eg. (fn [x] (let [foo (do-something (drop 100000 x))] "the reference to x still exists here even though it's not needed") |
| 12:51 | Chousuke | if the compiler were smarted it could figure out x is not used after the do-something call and nullify the reference, but currently it doesn't do that. |
| 12:51 | kiras | LauJensen: seems like it would. i thought maybe Chousuke meant that someday the compiler might be able to tell and set it to null. would think that would be very difficult to do though. |
| 12:51 | Chousuke | smarter* |
| 12:52 | kiras | Chousuke: i see... |
| 12:52 | kiras | interesting |
| 12:55 | Chousuke | to get around that you need to do (fn [x] (letfn [(work [y] (let [foo (do-something y)] "no ref to x here"))] (work (drop 100000 x)))) |
| 12:56 | Chousuke | because the (work ...) call is at the tail position the compiler knows x can't be referenced after the call and nullifies the reference |
| 12:56 | Chousuke | of course, the example is rather silly like that, but imagine that the strings returned were something more complex (possibly utilising foo, but not x) |
| 12:57 | LauJensen | kiras: With dynamic code (macros) I think its near impossible. |
| 12:59 | kiras | so do lazy sequences keep track of references to themselves and the parts of the sequence each reference is holding onto (pointing to?)? then when a variable that is using part of the sequence is deleted, the lazy sequence drops that part of the sequence from its cache? or is that handled outside the lazy sequence somehow? |
| 13:00 | Chousuke | kiras: the lazy sequence is like a linked list. it's made of smaller subsequences. :) |
| 13:01 | Chousuke | kiras: and each subsequence just caches its own value after it's computed. |
| 13:01 | Chousuke | the head of each subsequence that is. |
| 13:02 | tomoj | so if you're holding the head, the entire sequence computed so far is not gcable? |
| 13:02 | Chousuke | yes. |
| 13:02 | Chousuke | because there's a reference from the head to the second item, from the second item to the third, etc. until the last actually computed item |
| 13:03 | Chousuke | this might be oversimplified though, because you can have seqs that are just "views" to something that already exists fully in memory, like a vector. |
| 15:01 | fps | hello, could someone give me a hint on how to use the clj-record library? http://github.com/duelinmarkers/clj-record/tree/master/ |
| 15:03 | fps | I already compiled it, but I cannot find a jar to add to the classpath |
| 15:09 | Bercilak | for those of you using emacs clojure-mode, have you had any success using the clojure-update command? |
| 15:10 | Bercilak | I'm running into an error where it tries to run ant in the wrong directory, and I think it's a bug in clojure-mode. |
| 15:11 | cschreiner | I get an error with Git |
| 15:11 | cschreiner | but I've had no success using the clojure-update command |
| 15:12 | Bercilak | out of curiosity, what's the error? |
| 15:15 | cschreiner | just that Git cannot be found |
| 15:16 | cschreiner | I just left it, and continued with what I was doing before |
| 15:16 | cschreiner | there are a couple of things that don't work right in emacs, but I'll manage |
| 15:18 | cschreiner | like; code-completion, java-lookup, some problems with elisp formatting from swank etc |
| 15:19 | cschreiner | especially when doing (println "whatever") statements |
| 15:20 | Bercilak | hmm. I'm still in the process of switching to emacs from textmate, so I'm useless for those... |
| 15:20 | cschreiner | error in process filter: slime-dispatch-event: Elisp destructure-case failed: (:write-string "Whatever") |
| 15:21 | cschreiner | yeah, textmate, never seen much of that since going back to emacs |
| 15:22 | cschreiner | I tend to spend more time browsing elisp code than actually clojouring |
| 15:23 | cschreiner | I still need to understand the big picture though (re. emacs) |
| 15:27 | LauJensen | For those of you who are interested I'm launching a blog which pivots on Clojure but from a business relevant angle. You'll find it at http://bestinclass.wordpress.com |
| 15:27 | cschreiner | sure :-) |
| 15:31 | Bercilak | textmate is very approachable and snippets are simple to understand and damn useful |
| 15:31 | Bercilak | slime is so worth the switch though, and eventually I'll get the hang of emacs |
| 15:31 | clojurebot | slime is icky |
| 15:31 | Bercilak | heh |
| 15:31 | LauJensen | ~forget slime |
| 15:31 | clojurebot | I forgot slime |
| 15:31 | Chousuke | in the end emacs is more powerful than any other editor |
| 15:31 | Chousuke | it just requires some effort :/ |
| 15:32 | cschreiner | I messed with the ergoemacs keybindings, but I returned to a blank slate |
| 15:32 | Bercilak | I always knew that I was going to switch to emacs or vim someday, so recently I set up a linux dev box and I've been doing all my work on that |
| 15:32 | cschreiner | better to build the system bit by bit with functionality I am really going to use |
| 15:33 | cschreiner | on another hand, the original keybindings are really hard on my old hands |
| 15:33 | Bercilak | ergoemacs looked interesting, it's nice to hear from someone who tried it out |
| 15:33 | Chousuke | maybe you just need a better keyboard :/ |
| 15:33 | cschreiner | maybe |
| 15:34 | cschreiner | I need an original symbolics thing |
| 15:34 | Bercilak | hehe. I type in dvorak which makes a lot of these layouts kind of infuriating. They make sense in qwerty but not dvorak |
| 15:34 | Chousuke | I get by with caps lock as meta and cmd as control but still I think a better keyboard would help a lot :P |
| 15:34 | cschreiner | Well, I have three different apple keyboards here, and all of them makes my hand ache |
| 15:35 | cschreiner | I need to think more about typing less |
| 15:35 | Bercilak | maybe it's blasphemy, but I might switch to using vimpulse/viper for basic text movement and manipulation |
| 15:35 | Bercilak | elisp is where it's at for configuration though |
| 15:35 | cschreiner | care to share? |
| 15:36 | cschreiner | vimpulse, is that a vim thing? |
| 15:36 | Chousuke | viper.el is a vi implementation for emacs. |
| 15:36 | Chousuke | and vimpulse adds some vim things missing from viper. |
| 15:36 | Chousuke | I used viper but it didn't play well with paredit so now I'm trying to get used to emacs controls |
| 15:37 | cschreiner | any torough docs/intros? |
| 15:37 | cschreiner | I think the incremental search is the most important thing, and sexp navigation of course |
| 15:37 | Chousuke | paredit is awesome. |
| 15:38 | cschreiner | so few modifiers, so many modes |
| 15:39 | Chousuke | I don't even do much besides some barfing and slurping and sexp-killing with paredit but it's still an enlightening experience. |
| 15:39 | Bercilak | I just googled it... the paredit koolaid looks delicious. |
| 15:40 | Chousuke | I suppose if I learned to use the sexp navigation commands properly I would be one step closer to lisper nirvana |
| 15:41 | cschreiner | examining the pareditcheatsheet now http://www.emacswiki.org/emacs/PareditCheatsheet |
| 15:43 | Chousuke | one of the more common operations I do with paredit is deleting a let, and it's really very easy :/ |
| 15:44 | Chousuke | or the reverse, wrapping some code in a let. |
| 15:45 | cschreiner | working with a non-us keyboard layout, everthing is fucked from the beginning |
| 15:45 | cschreiner | the intention of the original layout does not count |
| 15:46 | cschreiner | or, is non-existant |
| 15:47 | Chousuke | I find it usable on a Finnish layout. |
| 15:47 | Chousuke | though I think if I got used to a US one it would be better |
| 15:47 | cschreiner | Suomi? |
| 15:47 | Chousuke | it's not like I need ä ör ö when coding :/ |
| 15:47 | Chousuke | yeah. :P |
| 15:48 | cschreiner | I would never have guessed it |
| 15:48 | cschreiner | Norway here |
| 15:52 | cschreiner | barfage and slurpage seems reasonable enough, never touched paredit- before |
| 15:53 | cschreiner | guess I've loaded it, but not bound any of the functions |
| 16:21 | quidnunc | cgrand: Is it possible to select a node whose child satisfies some predicate in enlive? I'm trying to do (select foo [[:font (has [:a (attr-contains :href "blah")])]]) but it doesn't seem to be working (the selector on the child works on its own. |
| 17:19 | cgrand | quidnunc: (select foo [[:font (has [[:a (attr-contains :href "blah")]])]]) |
| 17:20 | cgrand | 'has takes a whole selector not a single selector-step |
| 17:23 | quidnunc | cgrand: Thanks. |
| 17:26 | quidnunc | cgrand: There is no way to get a parent of a node once I from the value returned by select right? |
| 17:27 | cgrand | not by select itself |
| 17:30 | cgrand | look at zip-select: something like (zip-select (map xml/xml-zip nodes) [your selector here]) -- where xml is net.cgrand.xml |
| 17:30 | quidnunc | cgrand: One last question. Is it possible to use zip-filter.xml functions on the nodes returned by select? |
| 17:32 | quidnunc | cgrand: I wasn't clear about the difference between zip-select and select. What does zip-select do differently than select? |
| 17:32 | cgrand | zip-filter.xml may barf on xml comments (other than whitespace handling it's the main difference between clojure.xml and net.cgrand.xml) |
| 17:34 | cgrand | 'select returns nodes, 'zip-select returns locs (zips) to these nodes... and you can get the parent of a loc |
| 17:35 | cgrand | once you have a loc you can freely use clojure.zip or zip-filters |
| 17:37 | quidnunc | Thanks cgrand. |
| 17:37 | cgrand | welcome |
| 17:41 | cgrand | quidnunc: bedtime for me |
| 18:11 | cemerick | holy crap, I just grokked what subseq is all about |
| 18:12 | cemerick | I had never read the docs -- thought it was over Indexed colls! |
| 18:35 | cemerick | it'd be great to see PTM become extensible (so as to support building stuff like interval trees on top of it, etc) |
| 18:44 | emacsen | Why doesn't this do what I expect (knowing I clearly misunderstand): (reduce merge [{:a 10} {:b 20} {:c 30}]) |
| 18:45 | Chousuke | ,(reduce merge [{:a 10} {:b 20} {:c 30}]) |
| 18:45 | clojurebot | {:c 30, :b 20, :a 10} |
| 18:46 | Chousuke | isn't that what you want it to do? |
| 18:46 | emacsen | I didn't get that... let me try again |
| 18:46 | Chousuke | though you could also do (apply merge ...) |
| 18:46 | Chousuke | which probably internally uses reduce :) |
| 18:46 | Chousuke | but might not! |
| 18:46 | emacsen | lol, okay this was a slime problem with my display |
| 18:46 | Chousuke | ~def merge |
| 18:46 | emacsen | I was like "I must be going crazy... this should work" |
| 18:47 | Chousuke | hm, merge could be changed to use transients I suppose |
| 18:48 | emacsen | Chouske, okay here's a harder one... given another vector in mynode's content, this is invalid: |
| 18:48 | emacsen | (map #({(:k (:attrs %)) (:v (:attrs %))}) (:content mynode)) |
| 18:48 | emacsen | I've tried that function on a single argument and it works, and (:content mynode) gives me back a persistent vector |
| 18:49 | Chousuke | #() is not fn |
| 18:49 | Chousuke | #({}) means calling {} with no parameters |
| 18:49 | Chousuke | I assume you meant to return the map |
| 18:49 | emacsen | isn't #() a macro for (fn ..) |
| 18:49 | Chousuke | no |
| 18:49 | Chousuke | #(foo) = (fn [] (foo)) |
| 18:50 | emacsen | oh good point |
| 18:50 | emacsen | right... okay this all makes more sense |
| 18:50 | hiredman | > ((x: Any, y: Any) => (f: Function2[Any, Any, Any]) => f(x, y))(1, 2)((x: Any, y: Any) => x) |
| 18:50 | clojurebot | Any = 1 |
| 18:50 | hiredman | :D |
| 18:50 | Chousuke | what. |
| 18:51 | Chousuke | Clojurebot does Scala now? |
| 18:51 | Chousuke | what blasphemy is this. |
| 18:51 | emacsen | oh that's scala? |
| 18:51 | hiredman | yep |
| 18:52 | hiredman | via the simplyscala online repl |
| 20:42 | AWizzArd | Anyone awake who knows well about snapshots in Clojure? When I made a snapshot of a ref, and then the ref is mutated, will it use copy on write, as in forks? |
| 20:46 | hiredman | uh |
| 20:46 | hiredman | what? |
| 20:48 | AWizzArd | when we make a snapshot of a map and have another thread changing the map, will then Clojure have to copy everything from the root to that leaf that gets mutated? |
| 20:48 | hiredman | mutating a ref is just assigning it a new value, te copy-onwrite or not depends on what the value is |
| 20:48 | AWizzArd | imagine a fork.. when the parent or child mutates data then the os will first copy the page, because everything is marked as read-only |
| 20:49 | hiredman | that has nothing to do with refs |
| 20:49 | AWizzArd | but mutating something in a tree may require to copy data from the root to that mutated leaf |
| 20:50 | hiredman | refs do not care, and don't know anything about what they wrap |
| 20:50 | hiredman | and copy on write, etc, is the responsibility of the object wrapped by the ref |
| 20:50 | AWizzArd | i snapshot a ref (i call deref on it) and have a long running function that works on the object |
| 20:51 | hiredman | sure |
| 20:51 | AWizzArd | and now another thread mutates this object.. |
| 20:51 | hiredman | then you are screwed |
| 20:51 | AWizzArd | then COW is happening under the hood? |
| 20:51 | hiredman | that is not how refs work |
| 20:51 | hiredman | the value a ref holds should never mutate |
| 20:51 | AWizzArd | the ref is already forgotten after a snapshotted/derefd |
| 20:51 | hiredman | the ref can mutate and point to different values |
| 20:52 | AWizzArd | yes, let's forget the ref |
| 20:52 | hiredman | we cannot just forget the ref |
| 20:53 | hiredman | if you wrap a mutable object like stringbuilder in a ref, the ref is useless |
| 20:53 | AWizzArd | yes |
| 20:53 | AWizzArd | but say it is a clojure map |
| 20:53 | AWizzArd | we call (foo @our-map) |
| 20:53 | hiredman | ok, clojure maps are implemented using structural sharing |
| 20:54 | AWizzArd | and while foo is running some other function bar mutates our-map |
| 20:54 | hiredman | aand Immutable |
| 20:54 | hiredman | AWizzArd: you cannot |
| 20:54 | hiredman | Immutable |
| 20:54 | AWizzArd | our-map sits in a ref |
| 20:55 | hiredman | doesn't matter |
| 20:55 | AWizzArd | and as you said, the structure is shared |
| 20:55 | AWizzArd | so, it seems to us that we are working on a completely new object, while under the hood the same thing is mutated |
| 20:55 | hiredman | no! |
| 20:55 | AWizzArd | if our-map is 600 mb in size, then not each time those 600mb need to be copied |
| 20:55 | hiredman | no! |
| 20:55 | hiredman | it is a new object |
| 20:56 | hiredman | it just contains a pointer to another object that it shares some structure with |
| 20:56 | hiredman | no mutation |
| 20:56 | AWizzArd | I know, they are not identical |
| 20:56 | Chouser | only the parts that are identical are shared |
| 20:57 | AWizzArd | when we call (foo @our-map) then at those point foo sees an immutable map, and all threads can see the same thing |
| 20:57 | AWizzArd | similar to a fork |
| 20:57 | Chouser | the COW, if you want to think of it that way, happens the moment you do (assoc ...), regardless of whether a ref is involved or not. |
| 20:57 | AWizzArd | yes |
| 20:57 | hiredman | ,(let [a '(1 2 3) b (cons 4 a)] [a b]) ;shared structure, no mutation |
| 20:57 | clojurebot | [(1 2 3) (4 1 2 3)] |
| 20:57 | AWizzArd | this is what i want to know |
| 20:57 | AWizzArd | does a COW happen, and how efficient will it be |
| 20:58 | AWizzArd | some other thread runs the function bar which is doing transactions and alters our-map |
| 20:58 | hiredman | AWizzArd: it happens everytime you cons, conj, assoc, etc |
| 20:59 | hiredman | AWizzArd: you cannot alter the map |
| 20:59 | hiredman | *cannot* |
| 20:59 | Chouser | AWizzArd: http://blog.higher-order.net/2009/02/01/understanding-clojures-persistentvector-implementation/ |
| 20:59 | hiredman | you can create a new map that shares structure with the old map, and place the new map into the ref |
| 20:59 | AWizzArd | yes |
| 20:59 | hiredman | but that in no way effects our-map |
| 21:00 | AWizzArd | Chouser: thanks for the link |
| 21:00 | AWizzArd | yes hiredman I know, but I want to know how efficient it will be under the hood |
| 21:00 | AWizzArd | consing is no problem |
| 21:00 | AWizzArd | but changes in the middle might be |
| 21:01 | hiredman | ,(time (reduce conj [] (range 10000))) |
| 21:01 | clojurebot | [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 13 |
| 21:01 | clojurebot | "Elapsed time: 10.073 msecs" |
| 21:01 | Chouser | AWizzArd: changes on the end and in the middle are handled identically (for both vectors and maps) |
| 21:01 | clojurebot | for is not used enough |
| 21:03 | hiredman | AWizzArd: I recomend you read http://clojure.org/refs and http://clojure.org/state |
| 21:04 | AWizzArd | those pages don't explain much of how structure sharing is done |
| 21:04 | hiredman | correct, I am more concerned with you understanding of refs |
| 21:04 | AWizzArd | that is no problem at all |
| 21:05 | hiredman | … |
| 21:05 | AWizzArd | only that i was not talking about them, and fortunately Chouser understood this and gave me an interesting link |
| 21:06 | mabes | any vimclojure users here? When I try to run ant in the plugin dir the build fails: |
| 21:06 | hiredman | are you following the directions in the readme? |
| 21:06 | mabes | http://pastie.org/607372 |
| 21:07 | mabes | hiredman: I was following a screen cast.. I'll double check the readme to see if something has been updated |
| 21:08 | hiredman | you need to follow the build instructions for contrib |
| 21:08 | mabes | it is as if it can't find my clojure-contrib.jar but I defined it in the local.properites |
| 21:08 | mabes | hiredman: ok.. so I just don't run "ant"? |
| 21:09 | hiredman | mabes: run ant and check for a "Warning ..." and follow the instructions |
| 21:09 | mabes | hiredman: k, thanks for the help |
| 21:10 | AWizzArd | Chouser: when there is a big map and in a snapshot we have the k/v pair [:a 100] and some other thread dissocs it, then the snapshot still sees it. Will that operation require very much work under the hood, or is that still very efficient? |
| 21:18 | Chouser | AWizzArd: that has nothing to do with threads or refs. 'dissoc' will do what it does |
| 21:19 | hiredman | ,(time (let [v (vec (range 1e6))] (nil? (reduce #(assoc % %2 (* %2 3)) v v)))) |
| 21:19 | clojurebot | "Elapsed time: 2788.926 msecs" |
| 21:20 | hiredman | 1e6 new vectors |
| 21:22 | AWizzArd | I will definitly need to look into that. It seems interesting to see how dissoc can remove elements in such a way that no snapshots will see it. |
| 21:22 | AWizzArd | Oki, thanks you two and good night |
| 21:22 | hiredman | No! |
| 21:23 | hiredman | dissoc doesn't effect any "snapshots" |
| 21:23 | hiredman | the snapsots are immutable! |
| 21:23 | AWizzArd | exactly |
| 21:23 | AWizzArd | they won't see the change |
| 21:23 | AWizzArd | but when the structure is shared then some copying must happen, so that the snapshot is not a full copy but still can see the dissoc'd element |
| 21:24 | AWizzArd | n8 n8 |
| 21:24 | Chouser | yes, clojure's persistent structures are amazing. |
| 22:04 | emacsen | n8? |
| 22:04 | emacsen | oh, night |
| 22:29 | emacsen | hey technomancy |
| 22:30 | emacsen | technomancy, how mature is your http abtraction library? |
| 22:39 | technomancy | emacsen: in terms of age/usage, not very |
| 22:39 | technomancy | I wrote it in three days and haven't touched it yet |
| 22:39 | technomancy | I've got like three patches contributed that I've been sitting on.</shame> |
| 22:40 | emacsen | I don't need any http library yet but soon will |
| 22:40 | emacsen | and looking for something other than the java one, because I don't know Java, I find it distracting to go back and forth between documentation and programming styles |
| 22:41 | emacsen | unless Clojure comes with another one that I've missed |
| 22:44 | technomancy | the java one certainly requires a lot of ceremony |
| 22:45 | technomancy | emacsen: there's one in contrib too; uses agents |
| 22:45 | emacsen | that's a lot of overkill for what I'm doing |
| 22:47 | technomancy | if you're working with a restful API then I'd recommend the "resourcefully" namespace in clojure-http-client |
| 23:05 | nathanmarz | any monad masters around? |
| 23:38 | emacsen | technomancy, I am indeed working with a restul api |
| 23:53 | prospero_ | how do I reset the state of the repl? |
| 23:58 | hiredman | what state? |