#clojure log - Sep 30 2009

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

0:45 thedoor: wow

0:45 a lot of people at this channel :P

0:45 arbscht: it is growing :)

0:46 thedoor: a work friend talk to me about clojure today, now im installing the nescessary thing to star :)

0:46 start*

0:51 Raynes: thedoor: And it's the middle of the night for a lot of people. We get new people in here all the time.

0:52 thedoor: I hope you have lots of fun with Clojure. :)

0:52 thedoor: here is 02:00 am :)

0:53 i need to sleep but i need to star this :P

0:53 start*

0:53 sorry my bad english :(

1:44 hiredman: clojurebot: ping?

1:44 clojurebot: PONG!

2:56 yason: re

3:06 vy: Reading the Agents documentation... What does "dispatch" in "If during the function execution any other dispatches are made (directly or indirectly), they will be held until after the state of the Agent has been changed." expression?

3:07 hiredman: send or send-off

3:08 vy: Thanks.

3:11 Dispatches on an agent are placed in a queue that are consumed by a thread pool? Right? If so, assuming mutation of the agent is serialized, what's the necessity/role of a thread pool in here? Wouldn't it be more simple to dedicate a single thread for an agent and its dispatch queue?

3:13 Hrm... Or that "thread pool" is dedicated to "whole available agents"?

3:14 hiredman: send sends to a fixed size threadpool (I think it as 2+core count last I checked)

3:14 send-off sends to a non-fixed size threadpool

3:15 well, have 200 threads try to run on a 2 core machine is kind of, well, not entirely optimal

3:16 jdz: hiredman: optimal for what?

3:17 when i look in the process browser on my machine, there are 261 threads running currently

3:17 hiredman: thats a lie

3:17 vy: Hrm... Yeah, that's for sure. What I now realize is that: 1) There is a single (actually 2, one for "send" and another one for "send-off") dedicated thread pool and mutations to a single Agent is serialized. 2) No more than one thread tries to write to the same Agent at a time in the pool.

3:17 jdz: hiredman: says who?

3:18 hiredman: the processor is switching back and forth between 261 processes

3:18 jdz: I just did (according to my logs)

3:18 jdz: well, then by your logic, what's the point of having 2+core count threads? why 2 more?

3:19 and JVM starts with how many threads?

3:19 hiredman: jdz: because threads might block for io or whatever

3:19 jdz: so, the original question stands...

3:19 vy: Sun Java System Application Server 9.1 Performance Tuning Guide > Thread Count [http://docs.sun.com/app/docs/doc/819-3681/6n5srlhod?a=view]

3:26 jdz: vy: that's about very specific purpose

3:27 vy: namely HTTP request handling

3:27 hiredman: everyone has some heuristic

3:28 I've seen 1+core count, 2+core count, 5*core count

3:28 there was a paper in acm like eight years ago that did some real math on the subject

3:28 jdz: lol, "real math"

3:29 hiredman: well, more than multiplication and addition

3:33 Fossi: hi

3:38 cgrand: sorry to bother you, but you seem to be involved into hashmap development: is there a chance to make it serializable?

3:52 cgrand: Fossi: personally I don't care about java serialization so I won't push for it. Plus other clojure data structures doesn't implement serializable either.

3:54 Fossi: cgrand: well, at least in my clojure PersistenHashMap implements Serializable, but BitmapIndexedNode prevents it from actually being it

3:54 cgrand: hmm let me check

3:55 Fossi: and it's a pita to serialize a deep map (for memcache/jcache in this case) either way through serializable (because of maps and keywords) and through the reader because of 'custo,m' java classes that we can't read back

3:56 so wanting to cache an object graph, we're stuck with walking it and transforming or such

3:56 hiredman: Fossi: you know about print-dup and #=()?

3:56 Fossi: hiredman: what does #=() do?

3:56 hiredman: #=() allows for limited read time evaluation

3:56 Fossi: i've tried print-dup and we couldn't get the things to read back in

3:57 hiredman: so you hook a custom method into, uh, I think it's called print-method

3:57 ,(doc print-method)

3:57 clojurebot: "; "

3:57 hiredman: how useful

3:57 Fossi: ;D

3:57 hiredman: which prn uses

3:57 Fossi: yeah, i get that part, but how do i read it back in?

3:58 hiredman: it emits a some thing like "#=(java.util.ArrayList (1 3 4 5))"

3:58 ,#=(java.util.ArrayList (1 3 4 5))

3:58 clojurebot: Can't resolve java.util.ArrayList

3:58 hiredman: ,#=(java.utils.ArrayList (1 3 4 5))

3:58 clojurebot: java.utils.ArrayList

3:58 hiredman: bah

3:58 ,#=(java.utils.ArrayList. (1 3 4 5))

3:58 clojurebot: java.utils.ArrayList

3:58 Fossi: ok, that should prolly work

3:59 hiredman: ,#=(java.util.ArrayList. '(1 3 4 5))

3:59 clojurebot: #<ArrayList [quote, (1 3 4 5)]>

3:59 hiredman: ,#=(java.util.ArrayList. (1 3 4 5))

3:59 clojurebot: #<ArrayList [1, 3, 4, 5]>

3:59 hiredman: gah

3:59 read time arraylist

4:01 Fossi: hiredman: i'll try and snoop around some more in the read and print code

4:05 cgrand: Fossi, for the record, PersistentHashMap implements Serializable through AFn and AFn was marked Serializable in commit "cleanup for findbugs" http://github.com/cgrand/clojure/commit/7cd3b285328e7e7e71b23080303d66640e0f21e8#diff-0

4:14 LauJensen: Morning cgrand

4:14 cgrand: morning LauJensen

4:24 Fossi: cgrand: ok, so i guess that's a smallish 'bug' then

4:24 since a lot of stuff is marked serializabel since a lot of things implement ifn :)

4:24 cgrand: ,(ancestors (class #(42)))

4:24 clojurebot: #{clojure.lang.IMeta clojure.lang.IFn clojure.lang.IObj java.lang.Object clojure.lang.Fn clojure.lang.Obj java.util.Comparator java.util.concurrent.Callable java.lang.Runnable :clojure.contrib.generic/any java.io.Serializable clojure.lang.AFunction clojure.lang.AFn}

4:26 Fossi: also a bit weird to have something callable marked as serializable :)

4:36 serp_: ,(funcall)

4:36 clojurebot: java.lang.Exception: Unable to resolve symbol: funcall in this context

4:37 serp_: ,(#(42))

4:37 clojurebot: java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn

4:37 serp_: ,#(42)

4:37 clojurebot: #<sandbox$eval__4764$fn__4766 sandbox$eval__4764$fn__4766@1324de2>

4:37 serp_: I don't get it =(

4:37 why would the second one work.

4:39 funkenblatt: well i think a better question is why the first one didn't work

4:39 the second one is supposed to work

4:41 serp_: I'm talking about ,(#(42))

4:41 funkenblatt: oh

4:41 serp_: shouldn't #(42) return a lambda function that simply returns 42, and is later evaluated

4:43 Fossi: ,(macroexpand-1 '(#(42)))

4:43 clojurebot: ((fn* [] (42)))

4:44 serp_: oh I see...

4:44 Fossi: a smallish annoyance and source of common confusion

4:44 but better than having to type #(( all the time

4:45 serp_: I don't know... seems like magic to me... makes the language harder to understand

4:45 opqdonut: you can always use #(int 42) ;)

4:45 serp_: unless...

4:45 ,(macroexpand-1 '#42)

4:45 clojurebot: No dispatch macro for: 4

4:46 serp_: ,#42

4:46 clojurebot: No dispatch macro for: 4

4:46 serp_: nope

4:46 Fossi: # is not the reader macro #( is

4:46 opqdonut: anyways, (constantly 42) is better

4:46 Fossi: sind # is used for a lot of things

4:46 *since

4:46 opqdonut: , ((constantly 42) 0)

4:46 clojurebot: 42

4:47 serp_: so a construct with #( has an implied function call in it

4:47 Fossi: otherwise you would have to type #((some-fn %)) all the time

4:48 serp_: sure, but then it is very clear what's going on =)

4:51 jdz: no, if just don't use the #() construct at all

4:51 then it's very clear what's going on

4:57 Chousuke: #() is a very useful shortcut sometimes, but it's not intended to replace fn

4:58 you can think of # as transforming a single expression into a function, if you want :P

4:59 (and that expression must be a list form)

5:27 Fossi: sometimes i miss #([(:a %) (:b %)]), but destructuring works better anyway

5:41 Chousuke: Fossi: or the new juxt

5:41 ,((juxt :a :b) {:a 1 :b 2 :c 3})

5:41 clojurebot: java.lang.Exception: Unable to resolve symbol: juxt in this context

5:41 Chousuke: hm

5:42 clojurebot: you're old :(

5:42 clojurebot: No entiendo

5:43 Chousuke: Fossi: well, anyway, a new function was added recently, and #(vector (:a %) (:b %)) = (juxt :a :b)

5:44 cgrand: ,(#(map % [:a :b]) {:a 1 :b 2 :c 3}) ; not a vector though -- and juxt is better

5:44 clojurebot: (1 2)

5:44 serp_: ,(#(list % %) 1 2)

5:44 clojurebot: java.lang.IllegalArgumentException: Wrong number of args passed to: sandbox$eval--4786$fn

5:44 cgrand: (#(list %1 %2) 1 2)

5:45 serp_: what does just % mean?

5:45 Chousuke: same as %1

5:45 serp_: oh

7:42 Drakeson: how can I use incanter on a headless machine? incanter imports processing.PApplet, which apparently asks for a graphical environment. Is there a standard way to deal with graphical packages when you run on a headless machine and don't need them but they are imported in the package?

7:46 dliebke: Drakeson: I shouldn't import PApplet in incanter.core, I'll try and remedy that today

7:47 Drakeson: thanks

7:49 one more thing, incanter places the dependencies in the git repos. maybe what compojure does is a bit better. compojure zips and puts the deps in github using the `upload' feature, and just places a link in the main repo.

7:50 dliebke: Drakeson: there has been discussion about using Maven to manage dependencies

7:52 Drakeson: that would be cool :) (I often follow discussions about package managers, and dependency resolvers).

8:38 Fossi: i'm getting a "Caused by: java.lang.NoSuchMethodError: clojure.lang.Namespace.importClass(Ljava/lang/Class;)Ljava/lang/Class;" when building from ant, but not from emacs using the same clojure.jar

8:39 it's behaving really weird

9:00 ar1: It's so quiet.

9:16 Fossi: ar1: so?

9:16 btw: my problem was solved by running ant clean and thus deleting our target dir. no idea what went wrong inbetween

9:38 AWizzArd: Is there an easier way to do (.toString (.format (java.text.SimpleDateFormat. "yyyy-MM-dd_HH-mm-ss-SSS") (java.util.Date.) (StringBuffer.) (java.text.FieldPosition. 0)))?

9:38 ,(.toString (.format (java.text.SimpleDateFormat. "yyyy-MM-dd_HH-mm-ss-SSS") (java.util.Date.) (StringBuffer.) (java.text.FieldPosition. 0)))

9:38 clojurebot: "2009-09-30_06-43-03-925"

9:39 rsynnott: heheh, poor clojure hasn't quite escaped the terrifying Java date classes, then? :)

9:39 someone should write a nice wrapper

9:39 chouser: someone did

9:39 they got shouted down for not just using JediDate or whatever it's called

9:40 * tmountain spits out his coffee

9:40 chouser: ,(.format (java.text.SimpleDateFormat. "yyyy-MM-dd_HH-mm-ss-SSS") (java.util.Date.))

9:40 clojurebot: "2009-09-30_06-45-36-693"

9:41 * rsynnott seems to remember Java date stuff involving horrible things to do with GregorianCalendar

9:41 rsynnott: (presumably there on the basis that the world might arbitrarily start using a different calendar)

9:41 AWizzArd: chouser: oh good, this is much nicer

9:42 strange i didn't see this on the api page of SimpleDateFormat

9:44 manic12: this may sound like backward steps to clojurites, but it is true that ordinary single-object dispatch (smalltalk/flavors style) is quite useful to engineers...

9:45 chouser: manic12: sure. Clojure uses it all the time.

9:45 manic12: I haven't learned enough clojure to do that in clojure

9:45 chouser: because the JVM can do it *fast*, mostly.

9:46 manic12: and I also haven't learned how to create generative style extensions to that

9:47 chouser: conj is single-dispatch on the type of the first arg

9:48 for example

9:50 manic12: another thing, I haven't learned how to write declaratively in clojure, just functional with procedural aspects mostly talking to java libs

9:52 Fossi: re serialization: now we have some trouble serializing structs. it seems that they are treated as an persistentMap and that has a "create" method, but the structs don't

9:53 so naturally, things break

9:57 manic12: I would like to create an 'object' which behaves a bit like a map, that instead of simply fetching the value, it calls a function on itself to compute and memoize the value, seems a bit anti-immutable

9:59 but maybe that's ok, because it would be easier to implement 'undo'

9:59 anybody there?

10:00 chouser: did you ask a question?

10:00 manic12: i am asking how to do that sort of thing with clojure

10:01 chouser: one way would be to implement clojure.lang.IPersistentMap using proxy

10:01 manic12: what about just deriving a actual java class?

10:03 chouser: ,(let [m (proxy [clojure.lang.APersistentMap] [] (valAt [_] 5) (seq [] nil))] [(get m :foo) (:bar m) (seq m)])

10:03 clojurebot: [5 5 nil]

10:04 tmountain: chouser: that's pretty nifty

10:06 jdz: why the hell does slurp declare the f parameter as String?

10:07 tmountain: jdz: it takes a string pointing to the file

10:07 jdz: and why does it care if i pass it an instance of java.io.File?

10:07 tmountain: $ echo "foo" > /tmp/foo.txt

10:08 (slurp "/tmp/foo.txt")

10:08 "foo\n"

10:09 jdz: tmountain: and notice that (slurp (new java.io.File "/tmp/foo.txt")) does not work :/

10:10 tmountain: jdz: yeah, looking at its implementation, slurp creates a FileInputStream in the background with f as it's argument

10:10 jdz: despite the fact that java.io.FileInputStream accepts java.io.File in the constructor

10:10 tmountain: jdz: yeah, that does sort of limit it's utility

10:13 jdz: slurp uses the two argument form for the FileInputStream constructor

10:14 jdz: to allow specification of encoding

10:14 jdz: tmountain: your point being?

10:14 tmountain: it uses it anyway even when passed only one parameter

10:15 tmountain: jdz: point being, you'd need another declaration to make it work with both a File and String

10:15 jdz: no

10:16 just drop the #^String thing

10:16 easy as that

10:16 manic12: chouser: how do I access the proxy object if valAt is being defined in the proxy definition?

10:17 i need the keys to be able to reference other keys

10:17 tmountain: jdz: my mistake, I see it's the InputStreamReader that takes the encoding argument

10:18 jdz: tmountain: my gripe with this is that somebody added the declaration although it does no good.

10:18 tmountain: same for the encoding

10:19 tmountain: jdz: yeah, you're right, I removed the type hint, and it works with a File as well

10:20 Chousuke: I suppose the type hint gives no measurable performance gain. :P

10:21 so it'd be better to remove it.

10:21 tmountain: yeah, I'd imagine there's miniscule difference in performance

10:22 Chousuke: if you wanted performance you wouldn't use slurp anyway

10:22 it's wasteful ;P

10:22 tmountain: using string builder

10:22 Chousuke: str uses a string builder internally. I mean storing an entire file in a string

10:23 tmountain: wasteful memory wise

10:24 manic12: chouser: if you're there I want to post something

10:28 AWizzArd: Compojure users: anyone here who handles json requests?

10:36 manic12: i would like to use clojure in a practical application, is there anyone here who can discuss how i might be able to satisfy some of the requirements with clojure?

10:38 is anyone here at all?

10:39 rsynnott: hiding :)

10:40 manic12: must be a coffee break

10:44 cemerick: we're all working :-P

10:44 arbscht: manic12: state your question and anyone who can answer it may...

10:46 manic12: clojurebot: lisppaste

10:46 clojurebot: It's greek to me.

10:46 manic12: is there a specific lisppaste for this irc channel?

10:47 ambient: M-x package-install lisppaste ;)

10:47 manic12: tehe

10:49 Fossi: lisppaste8: url

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

10:50 Fossi: manic12: there you go

10:51 lisppaste8: manic12 pasted "how to do in clojure?" at http://paste.lisp.org/display/87950

10:51 manic12: thx

10:58 raek: how do I add my own directory to the CLASSPATH and still have the library paths in it?

10:58 or -- how do I find my system default CLASSPATH?

10:59 I ran "find /usr -name \*.jar -print" to find the jars in my system

10:59 but they're evererywhere!

11:05 liwp: raek: on unix with bash: export CLASSPATH=path/to/foo.jar:path/to/classes:$CLASSPATH

11:05 raek: yes, I know

11:06 but I sort of found a solution to my problem

11:06 liwp: ok, so what's the problem exactly

11:06 ok

11:06 raek: I specified the path to my own clj files with the -cp option to java

11:06 liwp: raek: that'll work

11:06 raek: but then I also had to add the path to the system jar files

11:07 liwp: you shouldn't have to do that. What do you mean with system jar files?

11:08 raek: I'm trying to get compojure running

11:08 but it turned that I missed a dependency

11:09 java.lang.ClassNotFoundException: org.mortbay.jetty.servlet.Context (jetty.clj:0)

11:09 this is what I get when evaluating (use 'compojure)

11:10 oh wait

11:10 forgot to put the jar files produced by "ant deps" into my classpath

11:11 you may ignore my previous 10 lines

11:12 liwp: heh

11:12 raek: java.lang.SecurityException: sealing violation: package org.mortbay.jetty.servlet is sealed (jetty.clj:0)

11:13 ok, what have I done now?

11:21 ok, working now

11:22 removed jetty and firends with my package manager and used the jars supplied by compojure

11:29 kunjan: Is Clojure dynamically scoped in some cases?

11:36 yason: kunjan: I'm not an expert by any means but IIRC no. You could probably simulate dynamic scope with vars and (binding ...)

11:40 raek: (let) in clojure introduces lexically scoped variables

11:40 and (binding) dynamically scoped ones

11:44 rhickey: raek: they aren't dynamically scoped, just dynamically bound. If you do (defn foo [] (use-some free-var)) it will fail at compile time if free-var isn't in scope, vs true dynamic scope where someone could establish free-var then call foo and have it find it

11:45 sproingie: http://onclojure.com/2009/05/06/simulating-dynamic-scoping/

11:46 raek: ah, please bear with me. i've only used clojure for a week

11:46 sproingie: doesn't look like a general solution tho

11:47 raek: :rhickey ah, I see.

11:49 these things are new to me, as I come from languages that doesn't have these things

11:49 or I wasn't aware of them

11:53 is it un-ideomatic to use variables with dynamic bindings as a way to not have to pass a certain arg to function?

11:53 i'm coding some things that calculates the width and height of texts that will be drawn

11:53 and these things depends on the Metrics of the font in use

11:54 rhickey: raek: if you are just starting out you should avoid dynamic binding

11:54 yason: raek: so what you want is an easy way to pass on state?

11:55 stuartsierra: I think it's idiomatic, but subject to a number of tricky bit when laziness & concurrency are involved

11:55 raek: (binging [metrics (.. label .getFont .getMetrics)]] (calculate-width "text"))

11:56 and (calculate-width) then uses metrics

11:57 but as the width is a function of both the text and the metrics, maybe I should pass along metrics as an arg

11:58 that is the way I do it now

12:04 manic12_: are object systems in general anti-clojure philosophy?

12:05 rhickey: manic12_: http://clojure.org/state

12:05 Makoryu: manic12_: Stateful objects are the bane of both concurrency and common sense.

12:06 rhickey: I don't know that anyone has reconciled OO with the problems enumerated there, but I don't think it is impossible. Whether the result would be considered OO anymore is another question

12:07 OO includes a lot of things that Clojure delivers a la carte, like polymorphism and hierarchy

12:07 manic12__: sorry my internet connection dropped, i think the router was rebooted

12:08 Makoryu: manic12__: http://clojure-log.n01se.net/ <- You can always use this to see what you missed.

12:08 manic12__: thanks

12:08 Makoryu: Or, er, not, I suppose

12:08 I thought it updated more frequently

12:09 chouser: every 15 minutes right now

12:09 20 minutes

12:10 Makoryu: manic12__: Anyway... https://gist.github.com/61e9ffb761b574428cc4

12:10 manic12__: i've got a declarative DSL built into clos, and i am interested in doing the same things with clojure

12:11 sproingie: might try spinoza or categories. not tried either myself so i couldnt say how good they are

12:12 dammit..

12:12 manic12__: ^^^

12:13 manic12__: are those on github or somewhere?

12:13 sproingie: google code i think

12:13 teh googelz knows :)

12:13 Draggor: Are there any lexers for Clojure? Something like cl-yacc?

12:13 manic12__: oh wow

12:14 sproingie: neither spinoza nor categories defines a call-next-method tho, let alone a formal MRO

12:15 manic12__: i actually don't need call-next-method because it makes no sense in the DSL

12:16 so categories is a drinking game

12:16 sproingie: hard to reconcile with the predicate dispatch of multifn's anyway

12:16 stuartsierra: Draggor: you could use ANTLR or JavaCC to generate a lexer

12:17 sproingie: manic12__: categories is at http://code.google.com/p/explorersguild/

12:17 somewhere in the source

12:17 Draggor: stuartsierra: the JavaCC site appears to be down. Does one have any particular features over the other?

12:18 cemerick: wasn't cgrand working on a slick clojure DSL for grammars?

12:18 sproingie: antlr has oodles of features. also a vertical learning curve, and some annoying conventions around lexer/parser distinctions

12:20 cgrand: cemerick: still working

12:22 cemerick: cgrand: just giving you the intro to do some promotion :-)

12:22 stuartsierra: Draggor: ANTLR is generally considered easier to use, but it requires a runtime library to run your parser. ANTLR generates recursive-descent parsers, JavaCC generates (I think) bottom-up parsers

12:23 cemerick: I got tired of javacc and antlr years and years ago.

12:23 stuartsierra: For very simple grammars (e.g., Lisp) they're overkill.

12:23 But essential for parsing something like C.

12:25 manic12__: cannot each change to an object be a new structure entirely?

12:25 Draggor: I'm just having fun and writing a parser for a die roller, something like [5d6] or [[1d6]d6]

12:26 And then put math operations in it too

12:26 rsynnott: stuartsierra: quite a few C compilers have awful hand-made parsers

12:27 Draggor: Really it's just a calculator with another operator d and using [] for grouping instead of ()

12:27 sproingie: isn't g++'s new parser a hand-rolled recdescent parser?

12:28 stuartsierra: rsynnott: really? ugh

12:32 manic12__: i don't understand the difference between altering a ref and mutating state

12:34 sproingie: they are state

12:34 but you can only change them in a transaction

12:34 manic12__: it says that is "identity"

12:34 it doesn't matter if it's transactional

12:35 sproingie: clojure doesn't lack state completely, it just shoves it into some well-defined areas

12:36 manic12__: that statement should be put on the clojure.org/state webpage

12:39 sproingie: that page gets a little overly focused on identity. refs are essentially first-class slots, just not necessarily "owned" by some structure.

12:39 manic12__: ok

12:40 but oo is a bad idea?

12:40 sproingie: hardly

12:41 oo doesn't even necessarily have to throw around uncoordinated mutable state

12:41 it's just that most oo languages have few alternatives to doing so

12:42 java has some immutable collections in libraries that are pretty efficient, but most people don't use them

12:42 C++ STL is pretty much hopeless

12:43 scala's the only oo language i can think of that has seriously decent functional objects

12:43 manic12__: I'm looking at the "memoize" example and thinking about declarative oop

12:45 arohner: manic12__: in clojure, refs, atoms etc are a way to cleanly declare and isolate when & how state changes happen

12:45 manic12__: not absolute declarative like prolog though, declarative where it makes sense to do so: storing knowledge

12:45 arohner: yes, they're all state changes, but clojure has much stricter guarantees about how they happen

12:46 sproingie: clojure has all the state of any imperative language, but everything stateful in clojure has some kind of synchronization primitive baked into it

12:46 refs are transactional, agents have asynchronicity, and atoms are, well, atomic

12:46 clojure has all kinds of state, it just doesn't have "naked state"

12:46 manic12__: i haven't determined the difference yet

12:47 that's good

12:47 because it will make it easier to implement undo

12:48 sproingie: you could easily write a clojure program in completely imperative style, it's just that clojure steers toward a functional style

12:48 by using immutable collections and so forth

12:49 rhickey_: a point of Clojure is to separate identity, state and value

12:49 manic12__: so clojure needs some object systems

12:49 rhickey_: people throw around the term state without considering its meaning

12:50 manic12__: i read the clojure.org/state page, and i'm one of those people apparently

12:50 sproingie: most people who aren't FP geeks will conflate them somewhat :)

12:51 "pure" fp geeks don't even go in for the concept of "identity"

12:51 insofar as being distinguishable from value that is

12:51 manic12__: fp=functional programming?

12:51 sproingie: yep

12:51 milep: Hello, is there a good/standard way to use structmaps with sorted-set? Or should I create custom compare function and use that with normal set?

12:51 dnolen: sproingle: being the creator of spinoza, I would say don't bother. I haven't touched that project in ages :) it's best to just dive into fp style programming.

12:51 rhickey_: by being atomic, and pointing to immutable composites, Clojure's reference types ensure transitions from value to value, and you can grab one of those values without getting trounced by future state transitions

12:52 contrast that with objects that change in your hands

12:52 sproingie: dnolen: aw. i rather liked the idea of first-class protocols.

12:52 rhickey_: those objects don't have obtainable state at all

12:52 dnolen: sproingie: yes, I think mikel's generic functions project is less half-baked tho.

12:53 sproingie: dnolen: is that the categories thing in explorersguild?

12:53 manic12__: so if one thread grabs the state from the ref, it won't change on it underneath if another thread grabs it next

12:53 dnolen: sproingie: yes

12:53 rhickey_: a state is a value at a point in time, being a value it can't change

12:53 references just manage time

12:54 objects typically conflate all three and become impossible to reason about

12:54 manic12__: the most unfortunate thing about my code is that i use a huge c++ library!

12:56 but is my statement correct? about the state not changing from under a function in one thread because it's immutable?

12:57 rhickey_: manic12__: state of what? values don't have state. If you get a value from a ref you are done with state

12:57 manic12__: ok, so yes

12:58 the state doesn't change because it's not a state in the first place it's an immutable value

12:59 rhickey_: manic12__: there is a thing with state (the reference). When you dereference it, you obtain its value at a point in time. That value is an immutable thing and has no state/time at all

12:59 manic12__: i understand now

13:00 rhickey_: I don't mean to be pedantic, but I am on a mission to clarify this I guess. So tired of OO muddle...

13:01 manic12__: the c++ library suffers from exactly this stuff clojure is intended to solve

13:01 rhickey_: Clojure disassembles OO and delivers it in orthogonal pieces

13:01 manic12__: that's fine, i get it

13:03 but to do what I have coded in clos will require implementing some constructs i didn't have to before, that's what i was wondering

13:03 rhickey_: the prize is obtainable values and the fact that you can write pure functions that work with them, completely independent of things relating to state. In most OO values are relegated to primitives

13:03 manic12__: i should say meta programming in clos

13:04 rhickey_: manic12__: porting from CLOS will require looking at how it is being used, what's stateful, what's inheritance driven etc. It is a rich polymorphism system for sure

13:04 manic12__: it uses memoization heavily

13:06 i don't want to introduce uses of 'state' just because that's the way clos does it

13:08 the C++ code often destroys objects you pass into functions and you have to explicitly copy them first if you want to keep it

13:10 so it will be a challenge to make it appear like native code

13:11 chouser: "Take an old man's word; there's nothing worse than a muddle in all the world. It is easy to face Death and Fate, and the things that sound so dreadful. It is on my muddles that I look back with horror--on the things that I might have avoided." -- http://tinyurl.com/ychwqfp

13:18 rhickey_: Chouser: love it!

13:18 Draggor: Anyone tried http://kotka.de/projects/clojure/parser.html ?

13:19 chouser: rhickey_: I'm not sure he was talking about identity-value conflation, but it'll do.

13:30 drewr: ,(#{false} [true false])

13:30 clojurebot: nil

13:30 drewr: shouldn't that be false?

13:31 chouser: ,(#{false} true false)

13:31 clojurebot: java.lang.IllegalArgumentException: Wrong number of args passed to: PersistentHashSet

13:31 chouser: hm

13:31 stuartsierra: ,(#{false} false)

13:31 clojurebot: false

13:32 chouser: drewr: sets return the matching value, else nil.

13:32 stuartsierra: ,(#{:a} :a)

13:32 clojurebot: :a

13:32 stuartsierra: ,(#{:a} [:a])

13:32 clojurebot: nil

13:33 stuartsierra: ,(some #{false} [true false])

13:33 clojurebot: nil

13:33 stuartsierra: ,(some #{:a} [:b :a])

13:33 clojurebot: :a

13:35 drewr: chouser: isn't false the matching value though?

13:36 chouser: #{false} does not contain the vector [true false]

13:36 ,(#{:foo [true false] :bar} [true false])

13:36 clojurebot: [true false]

13:42 hiredman: (#{false} false)

13:42 ,(#{false} false)

13:42 clojurebot: false

13:42 hiredman: ,(#{nil} nil)

13:42 clojurebot: nil

13:42 hiredman: :(

13:43 chouser: ,(#{'spam} 'spam)

13:43 clojurebot: spam

14:02 drewr: chouser: oh, ok; I thought it wanted a coll there

14:02 which is what stuartsierra was demonstrating :-)

14:04 which makes sense when the set is callable there

14:09 bitbckt: Anybody have an easy way of taking an Array of N^2 items and splitting it into an NxN matrix?

14:11 ambient: x+y*width

14:11 chouser: ,(partition 4 (range 16))

14:11 clojurebot: ((0 1 2 3) (4 5 6 7) (8 9 10 11) (12 13 14 15))

14:11 bitbckt: chouser: That's what I was looking for. Thanks.

14:16 tmountain: has anyone seen this before? http://pleac.sourceforge.net/

14:17 it's a website featuring recipes from the perl cookbook implemented in a variety of programming languages

14:17 good resource for finding out how to do something quickly in a given language

14:18 I was thinking of starting a clojure module if anyone else is interested

14:19 I contributed the ruby section on directories, and it was pretty fun

14:20 sproingie: pleac is pretty nifty

14:20 good way to compare expressiveness

14:20 adding clojure would be awesome

14:21 tmountain: sweet, I'll contact the project admin and see about getting it added

14:35 drewr: stuartsierra: your some example was also confusing me

14:36 stuartsierra: which one?

14:36 drewr: ,(some #{:foo} [:foo false true])

14:36 clojurebot: :foo

14:36 drewr: ,(some #{false} [:foo false true])

14:36 clojurebot: nil

14:36 stuartsierra: That happens because "some" tests the result of applying the predicate to an element in the sequence. "false" tests false!

14:37 drewr: that seems like a bug

14:37 stuartsierra: Not a bug, I think, but certainly an edge case.

14:38 ,(some #(false? %) [:foo false true])

14:38 clojurebot: true

14:38 chouser: you just have to be careful dealing with collections that might contain nil or false

14:46 drewr: kotarak: how's ClojureCheck coming?

14:47 kotarak: drewr: uhweuhm oehmm...

14:47 drewr: falling off the spare time clip at the moment, I'm afraid.

14:48 Although I'd really like to work on it.... I have to cut done my projects...

14:49 drewr: what's it lack?

14:49 kotarak: drewr: The TAP part is more or less complete, but the QuickCheck clone is a mess. I'd really like to clean that up.

14:51 drewr: k

14:51 kotarak: .. and make it work, actually...

14:52 drewr: a coworker started working on his own and didn't know whether to tell him to use yours :-)

14:53 kotarak: drewr: -.- I have to win in the lottery, so that I can quit my day job and start working full time on fun projects. )

14:53 :)

14:54 drewr: yep

14:55 kotarak: the job cuts away 43h (effectively 48h) per week, with the recently grown family and soon to be bought apartment the prospects are rather depressing from the clojure project point of view. (Although the last two points have higher priority than clojure... :))

14:57 drewr: please put your family before clojure :-)

14:58 kotarak: Of course! :D

14:59 drewr: but now that you asked, I will probably invest some time to drive CC a bit more. VimClojure ate a lot of time lately, too...

16:08 ngoc: Why "Logging str" is output 5 times in the example at http://clojure.org/concurrent_programming?

16:10 kotarak: ngoc: What do you expect? Have you had a look at the implementation of str?

16:10 arohner: lisppaste8: url

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

16:11 kotarak: ngoc: http://groups.google.com/group/clojure/browse_frm/thread/9f8b14cd7cdf9f4d/90158571284ac1ef?q=loves+ethel+lucy+group:clojure for details

16:12 lisppaste8: arohner pasted "get the value of a local at runtime?" at http://paste.lisp.org/display/87966

16:13 arohner: is there any way to get the value of a local at runtime? and is there any way to implement value-of in a way that doesn't use eval?

16:14 hiredman: uh

16:14 kotarak: arohner: the only way I see is just returning expr from my-fun.

16:14 arohner: is there a way to edit the paste?

16:14 kotarak: you can annotate it

16:14 hiredman: there is no value at runtime

16:14 err

16:14 at compile time

16:15 lisppaste8: arohner annotated #87966 "untitled" at http://paste.lisp.org/display/87966#1

16:15 hiredman: when is when macro expansion happens

16:15 there is just a datastructure

16:15 kotarak: arohner: that's not possible, as hiredman says.

16:16 arohner: the macro turns into code that calls (my-fun 'foo)

16:16 my-fun is run at runtime

16:16 ah, the paste is missing a `

16:17 kotarak: And a quote on the expr.

16:17 lisppaste8: arohner annotated #87966 "untitled" at http://paste.lisp.org/display/87966#2

16:17 kotarak: But here expr gets evaluated.

16:17 manic12__: i implemented a "destructive" assoc for structmaps which obviously doesn't destroy anything but does allow for undo and redo, you have to pack the structmap in another map and make a ref to it and pretend the ref is the structmap

16:18 arohner: sorry for the mistakes. I'm trying to create a simplified example. obviously I'm making mistakes in the translation

16:18 `(my-fun expr)

16:18 hiredman: manic12__: sounds horrible

16:18 manic12__: that would have been a pain in CL because you need to copy the objects yourself

16:18 lisppaste8: kotarak annotated #87966 "quoted expr" at http://paste.lisp.org/display/87966#3

16:19 manic12__: hiredman: why?

16:19 hiredman: manic12__: because then you are going to have a lot of little "mutable" structmaps

16:20 manic12__: but you can undo them

16:20 arohner: interesting kotarak. is it possible to do the work in my-fun?

16:20 kotarak: arohner: which work?

16:20 tomoj: being able to undo doesn't make mutable state a good thing :)

16:20 hiredman: while controled mutation is better than uncontroled, immutability is better still

16:20 arohner: getting the value of expr. doing it in the macro rather than the function would make my code a lot more complicated

16:20 (or maybe my design is just wrong)

16:21 kotarak: arohner: well you do the work in the function. The macro just wraps everything up in a thunk, which is (maybe) called in the function to obtain the value.

16:22 manic12__: i want to be able for the user of the DSL to def to the ref and keep a constant ref to an dynamic object

16:23 hiredman: :(

16:23 manic12__: for animation and changing inputs/attributes

16:25 Chousuke: wouldn't a simple ref for the input do?

16:25 or inputs.

16:26 manic12__: how do you synchronize the state of the object to acheive the undo/redo?

16:26 lisppaste8: arohner annotated #87966 "untitled" at http://paste.lisp.org/display/87966#4

16:26 Chousuke: hm.

16:27 I'm not quite sure what it is that you are doing now

16:27 how does your scheme allow for undo/redo? :/

16:27 wavis: manic12__: instead of using a ref, just create and undo function that returns the previous map, which you had originally used assoc on

16:28 manic12__: and even if the struct map gets really big I don't think clojure's copying of it would slow it down compared to the fact that the object may need to recompute all of it's values

16:28 kotarak: arohner: that cannot work, you can't eval an expression passed to a function (at least not in general)

16:28 manic12__: generators?

16:28 wavis

16:28 Chousuke: no, really, I have no idea what you're thinking

16:28 you might have a good idea but I can't make sense of it.

16:29 kotarak: arohner: besides the macro would need to look like: `(my-fun (quote ~expr)). Your expansion is (my-fun your.name.space/expr).

16:29 ngoc: kotarak: Thank you. This is a pitfall for new comers. Since this example is for new comers, I think it should be explained in the example.

16:30 manic12__: it's like a spreadsheet

16:30 but it's a tree of objects

16:30 (refering to clos implementation)

16:31 inputs and specially declared modifiable attributes can be changed

16:31 tmountain: maniac12__: I'd determine if you really need "objects" or if you can use Clojure's native types to represent whatever data you're referring to

16:32 manic12__: i'm using structmaps from spinoza

16:32 Chousuke: hm

16:32 manic12__: i'm trying to implement a declarative DSL from clos to clojure

16:33 i haven't used cells very much at all, but it's like cells but lazy eval

16:35 it's not for specially trained computer scientists, it's a DSL for mechanical & civil engineer types

16:35 wavis: ,(defn undoable-assoc [the-map key val] (with-meta (assoc the-map key val) {:undone the-map}))

16:35 clojurebot: DENIED

16:36 manic12__: wavis: at some point the user needs handlebars

16:36 wavis: manic12__: anyway, with that you could (^new-map :undone)

16:36 handlebars?

16:36 manic12__: probably

16:37 there has to be at least one mutable thing in the program, and that is the object which gets displayed in the viewer

16:39 Chousuke: the object displayed is probably a function of the inputs, which are the mutable stuff :)

16:39 wavis: assuming I have a clue, you just need to change what the viewer is holding to display. the collections to display can still be immutable

16:39 ngoc: Is there a way to redefine functions? (defn str [& args] 123) will throw error.

16:40 wavis: so represent the whole display as an immutable structure and swap it

16:40 manic12__: the inputs are just going to be entries in the struct map and clojure will copy the whole struct map which gives the ability to synchronize an undo/redo

16:40 hiredman: ngoc: because str is not defined in the namespace you are in

16:40 manic12__: wavis: you are correct

16:41 ngoc: hiredman: How to solve the problem?

16:41 manic12__: but sometimes it's nice to spawn one at the repl

16:41 if it's not viewing properly or something

16:42 kotarak: ngoc: you don't want to do this!

16:43 Chousuke: ngoc: redefining core functions is going to break everything

16:43 ngoc: what you might do is temporarily rebind them though.

16:43 hiredman: ngoc: there are many ways to solve it

16:43 ngoc: (ns clojure.core) then (defn str [& args] "123") solved the problem

16:44 hiredman: #$%@#$%

16:44 that is not a solution

16:44 Chousuke: and created a thousand more :)

16:44 hiredman: clojure.core/str is part of the core of clojure and depended upon by other functions

16:44 changing it breaks all those functions

16:44 kotarak: People sure have funny definitions for "solved" and "problem"...

16:44 manic12__: mutable is not a dirty word

16:44 hiredman: yes, it is

16:45 manic12__: then get rid of refs, agents and atoms

16:45 Chousuke: cutting off your head solved headache but...

16:45 solves*

16:45 kotarak: Chousuke: hmmm? Phantom pain?

16:45 sproingie: it's a dirty word, but sometimes your problem wants you to talk dirty ;)

16:45 ngoc: I want to do alias_method_chain like in Ruby/Rails: http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Module.html#M001219

16:45 technomancy: noooo!~

16:45 sproingie: clojure gives you mutability all over the place. it's just managed.

16:46 technomancy: alias_method_chain is a maintenance nightmare

16:46 hiredman: manic12__: but mutation is needed

16:46 so you minimize/control it

16:46 manic12__: exactly

16:46 sproingie: heck atoms arent even all that managed

16:47 ngoc: I save the original str, redefine it, and call the original function inside the new one

16:47 sproingie: that's what let is for

16:47 hiredman: they are managed in the sense that future state is a function of past state

16:47 ngoc: don't

16:47 kotarak: ngoc: and broke the whole system....

16:48 ngoc: monkey patching is not a good idea. Don't do it.

16:48 ngoc: But Rails plugins all work this way, and they do work

16:48 hiredman: ngoc: when you create a new namespace you have the option of not aliasing bindings from clojure.core

16:48 technomancy: ngoc: no, they break

16:48 all the time

16:49 hiredman: so you can leave str out of your namespace and redefine it there

16:49 manic12__: I have to implement a memoization scheme for rest of that attributes, but it has to be finer grained than copying the whole struct map, it has to memoize each attribute individually but be able to unbind itself when dependent things change

16:49 Chousuke: manic12__: copies are cheap

16:49 manic12__: just give the user a reference :P

16:49 manic12__: but for EVERY attribute call?

16:50 hiredman: attribute call?

16:50 manic12__: message

16:50 hiredman: I would not use spinoza

16:50 Chousuke: manic12__: in which situation would you even copy the struct map entirely? :/

16:50 technomancy: ngoc: rails 3 is removing as many alias_method_chain calls as possible due to this

16:50 Chousuke: manic12__: I mean, if you assoc to it, that doesn't copy the whole map

16:51 ngoc: If redefining does not "solve" the problem, is there a way? I want to add feature to an existing function, just like in Rails plugins.

16:51 Chousuke: (doc binding)

16:51 clojurebot: "([bindings & body]); binding => var-symbol init-expr Creates new bindings for the (already-existing) vars, with the supplied initial values, executes the exprs in an implicit do, then re-establishes the bindings that existed before."

16:51 kotarak: ngoc: you want multimethods

16:51 sproingie: "just like in Rails" often means "doing it completely wrong"

16:52 hiredman: I'm pretty sure the original author of spinoza even removed his repo

16:52 sproingie: monkeypatching everything onto Object... OOP, You're Doing It Wrong

16:52 hiredman: or not

16:53 sproingie: there's reasonable use cases for opening up base classes, sure. most of ruby's uses aren't it

16:53 manic12__: Chousuke: yeah but I should only need to copy the struct map when information "changes" that invalidates dependent attributes

16:53 Chousuke: manic12__: I still don't see what "copying" happens if the struct map doesn't change

16:54 sproingie: you don't need to copy the whole map, you just record a sequence of changes

16:54 manic12__: clojure copies just about everything you can look at the source code

16:55 sproingie: when you need to get everything into the same state, you can condense the changes to a minimal set then generate exactly one new object from that

16:55 hiredman: eh?

16:55 Chousuke: huh?

16:55 hiredman: copies?

16:55 Chousuke: manic12__: you need to copy *something* to keep the data structures immutable, but it doesn't copy *everything* all the time.

16:55 that'd be slow

16:55 manic12__: sproingie: you're right and that's what i do in clos

16:56 hiredman: http://blog.higher-order.net/2009/02/01/understanding-clojures-persistentvector-implementation/

16:56 Chousuke: hmm, well, that's possible with clojure transients.

16:56 manic12__: go to IPersistentMap assoc method and show me that it's not copying every value

16:56 Chousuke: manic12__: it's not.

16:56 it shares structure.

16:56 with its "parent" maps

16:56 ngoc: How to implement something like (defn f (+ (original-f) + 1)) with multimethods or binding? Binding does not work as expected as the example at http://clojure.org/concurrent_programming shows ("Logging str" is output 5 times).

16:56 manic12__: newVals[i]=val;

16:57 hiredman: ngoc: it does work as expected

16:57 kotarak: ngoc: bindings works as expected, the output depends on the definition of the original str

16:57 hiredman: str is called internally by println and the love function

16:57 Chousuke: manic12__: if you have a map with a thousand objects and you assoc to it, Clojure surely does not copy each of those thousand values

16:57 sproingie: love?

16:57 manic12__: PersistentStructMap.java

16:58 Chousuke: manic12__: assoc is O(log_32 n)

16:58 hiredman: sproingie: if I recall, the example on that page defines a function named love

16:58 sproingie: ah

16:58 hiredman: loves, pardon me

16:58 sproingie: i was digging around in the API looking for it ;)

16:59 manic12__: ok, Chousuke if you're right than that's even better

16:59 tomoj: Chousuke is right

16:59 Chousuke: manic12__: how many items will your struct maps have, anyway?

16:59 stuartsierra: ~seen jochu

16:59 clojurebot: no, I have not seen jochu

16:59 ngoc: hiredman: I thought str called itself, not by println

16:59 manic12__: they can have alot, but not enough to make a full copy slow, like 100 to 200 "slots"

17:00 sproingie: log32 n aka "fast enough for you old man"

17:00 kotarak: ngoc: yes, str calls itself, which is your str (it print logging and then calls the orig-str)

17:00 Chousuke: manic12__: maybe *struct* maps do copy all of their values (because usually you don't have so many of them). but it's hopefully not going to be too slow

17:00 hiredman: ngoc: that is possible as well

17:00 Chousuke: manic12__: after all, every value is just a pointer. copying a hundred pointers is not too expensive :P

17:01 manic12__: it won't

17:01 no

17:01 sproingie: i thought structs used a vector underneath

17:01 manic12__: in the clos version, it would have to actually go through and unbind dependent slots, I'm sure that's slower than just copying it

17:02 hiredman: I wonder if there is a point to using structmaps with 200 keys

17:02 sproingie: oh right struct vs structmap. confoozing

17:02 Chousuke: ... creating instances of them would be painful :)

17:02 hiredman: structmaps are supposed to be a optimized case for small maps with the same keys

17:02 manic12__: yeah, after a point you would think it would have the offsets in a class object

17:02 sproingie: hiredman: i could see writing a virtual machine with a slot per bytecode

17:03 but chances are it'd be a singleton

17:03 hiredman: sproingie: eh?

17:03 sproingie: you know a big table

17:03 manic12__: i'm using structmaps right now because that's what spinoza uses

17:03 sproingie: nevermind my babbling

17:03 hiredman: I wonder at what number of keys a struct map ceases to be an optimization

17:03 sproingie: manic12__: the author of spinoza told me not to waste my time with it

17:04 hiredman: spinoza :(

17:04 Chousuke: hiredman: probably never, as the keys are shared between structmap instances

17:04 manic12__: maybe so, but I don't plan on using it like a clos, it's a learning tool

17:05 sproingie: if it's just to learn, then stop optimizing up front

17:05 manic12__: real clos does all kinds of optimization tricks for fast generic function dispatch and accessor methods

17:05 who's optimizing?

17:05 hiredman: multimethods!

17:05 manic12__: i implemented an undo

17:06 sproingie: you're fretting about copies of data structures that never actually get copied

17:06 ngoc: Hmm, I feel that binding forces the callers to explicitly list all the plugins they wants to use all the time, like (with-feature1 (with-feature2 (with-feature3 str))), this is ugly. How to plug all the plugins only once when the program starts?

17:06 sproingie: sounds like optimization concerns

17:06 tomoj: ngoc: the whole point is that you shouldn't do that :)

17:07 hiredman: ngoc: I would really recomend you spend more time learning clojure before you begin worrying about writing something that needs a plugin system

17:07 sproingie: multifns have the start of a nice generic function dispatch, but building on that is still in roll-your-own territory

17:07 Chousuke: ngoc: design a system that allows people to create new functions by combining the plugins with the base functions

17:07 manic12__: there is no declarative programming paradigm in clojure

17:07 sproingie: looking at watches, i would argue otherwise

17:07 Chousuke: ie. (def my-cool-function (plugin1 (plugin2 (plugin3 base-function)))))

17:07 sproingie: it's certainly not declarative like prolog, no

17:08 manic12__: i'm not saying declarative is the best, but it makes sense for my application

17:08 mechanical engineers are visual people

17:08 spatial

17:09 (they're so spatial)

17:10 hiredman: there are a lot of primitives available that a declarative system can be built upon

17:10 manic12__: so far I feel like I can't describe anything geometric with clojure because it feels like some kind of strange scheme with an emphasis on immutability

17:10 hiredman: promises,delays,etc

17:10 manic12__: structmaps and vectors?

17:10 ngoc: hireman: I have been studying Clojure for one month, no big progress at all. Do you have any tips on studying Clojure?

17:11 hiredman: ngoc: write something small first, the sidebar on the clojure.org website has a list of features to try out

17:11 manic12__: as "dumb" as smalltalk and flavors, or even clos is, you can still describe types of objects and how they are contained

17:12 hiredman: manic12__: erm

17:12 sproingie: you do have to think functionally. clos with all its declarative syntax sugar still usually comes down to OO

17:12 manic12__: um, yeah

17:12 hiredman: we may have different understandings of "declarative programming"

17:12 manic12__: declarative and object oriented are not mutually exclusive

17:13 hiredman: what do you mean by declarative?

17:13 sproingie: you can get a lot of declarative behavior out of multifns

17:13 manic12__: car has chassis, chassis has wheels

17:14 sproingie: struct, works fine

17:14 manic12__: you can but you can get a lot of milage of of single object dispatch too!

17:14 ngoc: Chousuke: Do you mean I should study macro?

17:15 sproingie: multifns have multiple dispatch, they just don't have any kind of MRO for call-next-method to work

17:16 manic12__: sproingie: i am very familiar with multiple-object dispatch from clos

17:16 sproingie: multifns are insanely more powerful than just switching on class. you can destructure an object and switch on some arbitrary function of it

17:16 hiredman: manic12__: that seems to relate to the dictionary definition of Declarative in that you are declaring relationships, but I don't see how it relates to declarative programming

17:16 sproingie: that's probably why there's no MRO, how the heck do you determine what the "next" thing is from that

17:17 kotarak: ngoc: consider a simple program, eg. a logfile parser or something overlookable. And start implementing that.

17:17 ngoc: get comfortable in Clojure before you start with macros...

17:17 manic12__: sproingie: that's great, get a bunch of gearheads doing it

17:17 sproingie: floating around in my head is the idea of dispatching on a sequence instead of a single value, but i don't know offhand what the code would look like

17:18 manic12__: make a bunch of macros that look like autolisp, done

17:18 * manic12__ pukes

17:18 * manic12__ pukes again with a higher velocity

17:18 sproingie: not saying it's a good lisp, just saying that's what they know

17:18 manic12__: they also know icad

17:18 which is built on flavors

17:19 hiredman: sproingie: you can dispatch on sequences, just works better with vectors

17:19 Chousuke: sproingie: the dispatch fn would just be (comp vec map your-dispatch-fn) :P

17:19 er, wait

17:19 hiredman: ↑ yeah, use vectors

17:19 Chousuke: (partial map dfn)

17:19 sproingie: hiredman: yeah a vector would probably be more efficient, i'm thinking the sequence could be lazy though.

17:20 given arguments foo, bar, baz, generate a MRO. now given foo, bar, baz, a MRO, and a current position, find the next method

17:20 hiredman: sproingie: the isa stuff is all built to work on vectors already

17:20 (isa? [Object Object] [String Character])

17:20 ,(isa? [Object Object] [String Character])

17:20 clojurebot: false

17:20 hiredman: bah

17:20 manic12__: it's great that clojure has all of these great features with multifns & metadata, but if simple people have a hard time doing simple programming, well I'm sure you would say they need to re-learn

17:21 hiredman: ,(isa? [String String] [Object Object])

17:21 clojurebot: true

17:21 sproingie: it ain't logo yet

17:21 manic12__: I'm trying to apply a simple object system paradigm from flavors and clos to clojure

17:21 sproingie: i'd rather the bike gets built before the training wheels

17:22 clos is anything but simple

17:23 hiredman: (defmulti new (fn [& args] (vec (conj (map class (rest args)) (first args)))))

17:24 (defmethod new [:box String Integer] [_ name size] {:name name :size size})

17:24 manic12__: yeah, well clos can be simplified with some meta programming and macros

17:24 hiredman: of course you couldn't call it new

17:25 it would have to be my-new

17:25 manic12__: make-instance?

17:25 hiredman: and you'd want to map type not class

17:26 and you'd want to add :box as the :tag metadata to the resulting {}

17:26 manic12__: you know why java is popular...it creates a framework where programmers don't have to think as hard

17:26 hiredman: that is a lie

17:26 sproingie: *snort*

17:26 manic12__: icad is the same way

17:27 hiredman: well, they don't think they have to think

17:27 so they write crap

17:27 sproingie: i have to think all the time, long and hard, about how to get around the limitations in the language

17:27 manic12__: and i hit a limitation in clos, that's why I'm here

17:27 sproingie: usually i can find a nice library that helps out. which is great til i want to make it work with another library that solved another problem

17:28 manic12__: i would like to create a dead-simple geometric library for the icad style declarative/generative/object-oriented programming

17:29 sproingie: you may be the only one familiar with it. pastebin an example of what it looks like?

17:30 manic12__: sometimes i think computer scientists have lost touch with the problems the science was created to solve

17:31 kotarak: "Computers help us to solve problems we wouldn't have without them."

17:31 hiredman: ~clojure

17:31 clojurebot: clojure is a very attractive hammer with a nice heft to it

17:33 manic12__: if you have used parametric cad to design physical objects such as machine parts, it shows that things have progressed, but at the same time the software designers lock out the user from being able to really write flexible applications

17:34 that's why I became a programmer

17:35 sproingie: computer scientists have never particularly been in touch with the real world. that's not their job.

17:35 engineers create stuff, scientists figure out new principles to create stuff on.

17:36 theory, meet practice. practice, theo-- hey theory, stop wandering off, pay attention.

17:37 hiredman: manic12__: I think you might want to get a blog

17:39 manic12__: i don't think anyone would read my blog

17:41 hiredman: I dunno, you could grab the mic and inspire the masses to rise as one and throw off the shackles of the computer science intelligentsia

17:41 sproingie: you have nothing to lose but your boot times!

17:41 manic12__: i think i should be an arborist

17:42 drhodes: there's a race of men who live in the trees

17:43 manic12__: tarzan of the kbe trees here

17:45 i am going to have to get this thing to do a deep copy

17:46 if it finds a "pointer" to a struct map as a value of an entry, it needs to copy that whole thing too, not just the pointer

17:46 hiredman: manic12__: :(

17:46 that is horrible

17:48 manic12__: the structmaps don't need to contain keys for every message, just the ones that are "changeable" (I hate these "")

17:50 hiredman: still sounds horrible

17:52 Chousuke: why does it need a deep copy?

17:53 I mean, maps nest just fine. :/

17:53 manic12__: alibre design is written i java, i should just get a license to that and run clojure as a scripting language and be done

17:54 because if you don't deep copy, you when you undo or redo you will get state that belongs to something else

17:54 it's a very thin skeleton

17:54 Chousuke: oh, so the pointer is a ref then?

17:55 manic12__: no, by "pointer" i mean (identical? val1 val2)

17:55 Chousuke: but that's not true

17:55 or, at least I think it isn't.

17:58 sproingie: not that i don't love clojure, but if you have a clos thing you want to port to java, perhaps you should consider ABCL?

17:58 or one of the many scheme implementations where there's a tinyclos port

17:58 Chousuke: ,(let [a {:a {:deep :map}} b {:b 1} ] [(assoc b :foo (:a a)) b a])

17:58 clojurebot: [{:foo {:deep :map}, :b 1} {:b 1} {:a {:deep :map}}]

18:00 Chousuke: the :foo value and :a value are identical, but there is no connection between the "parent" maps

18:02 manic12__: is that what you're worried about, or something else? :/

18:03 manic12__: the submaps can freely be the same object, because it's not like anything can change them :)

18:23 spuz: Hello, I've having a really straing problem accessing external files from clojure

18:23 first of all, I cannot load any files using load-file

18:25 hiredman: have you read the load-file docs?

18:25 spuz: also, I cannot seem to 'see' files on my hard disk. Running (.exists (java.io.File. "C:/pe5.clj")) returns false even though that file exists

18:26 hiredman: yes, I can use relative or absolute paths apparently, but neither seem to work

18:26 hiredman: have you tried "C:\pe5.clj"

18:26 spuz: yes

18:27 at least "C:\\pe5.clj"

18:27 manic12__: Chousuke: those sub objects may be immutable, but if they are the wrong ones then that is a problem

18:27 spuz: however "C:/Windows" returns true

18:27 it's very strange

18:28 hiredman: spuz: does the pe5.clj file exist?

18:28 spuz: hiredman: yes!

18:28 Chousuke: manic12__: how would they be wrong?

18:29 spuz: I've tried putting it in the current dir and using "pe5.clj" as well

18:29 hiredman: spuz: what does dir c:\pe5.clj say?

18:29 Chousuke: manic12__: or is there some situation where the deep copy actually "changes" some of the inner map? :/

18:29 spuz: hiredman: hmm file not found!

18:30 hiredman: so it doesn't exist

18:30 problem solved

18:30 spuz: hiredman: uh well, not exactly, typing that path into explorer finds the file, but clearly it's not a clojure problem

18:32 hiredman: ah, how annoying, I have extensions turned off on this machine and the file was actually called "pe5.clj.txt"!

18:32 yes I'm a retard

18:34 sproingie: blame notepad

18:35 akhudek: While playing around building a small svg-like vector library using Java2d, I ran into an interesting problem dealing with mutable trees.

18:35 I decided to represent a scene graph as nested vectors inside a ref.

18:35 hiredman: notepad++

18:36 akhudek: Since the scene graph is a shared mutable resource that theoretically multiple threads may modify.

18:36 hiredman: I actually did a few euler problems in notepad++

18:36 akhudek: Now, a common operation may be to frequently change one specific node in the graph.

18:36 Say for a text label during an animation.

18:37 hiredman: have you seen zippers?

18:37 akhudek: yes, but you can't have multiple cusors

18:37 A simple animation would likely change a label node in one place, and say another object somewhere else.

18:37 Traversing the tree between both positions each frame seems ineffecient.

18:38 hiredman: (require '[clojure.zip :as zip])

18:38 ,(require '[clojure.zip :as zip])

18:38 clojurebot: nil

18:39 akhudek: The only decent solution seems to be to put frequently mutated nodes into references.

18:39 And have the rendering code automatically deref any references it encounters.

18:40 hiredman: :(

18:40 why do you want multiple cursors?

18:40 how deeply nested are the vectors?

18:41 akhudek: So that you can refer to more than one object in the scene.

18:41 hiredman: eh?

18:41 ,(-> '[:a [:b :c]] zip/vector-zip zip/next zip/next zip/next (zip/replace :x) zip/next (zip/replace :y) zip/root)

18:41 clojurebot: [:a [:x :y]]

18:41 akhudek: Right, but in a graphics context where you modify more than one node each frame.

18:42 You'd need to move between all nodes you need to change

18:42 hiredman: that modifies two nodes

18:43 akhudek: my complaint is that having to move between the two nodes may be a lot of work

18:43 sproingie: could collect a list of changes and sort it

18:43 sort of like elevator queueing

18:43 hiredman: you could use something besides vectors

18:43 sproingie: that too

18:44 akhudek: such as?

18:44 hiredman: you could flatten nest vectors by wrapping them into a map

18:44 akhudek: and have nested maps?

18:44 sproingie: you normally have to sort scenegraph updates anyway

18:44 hiredman: {[0 1] :x [0 0] :a} => [[:a :x]]

18:44 no, just one map

18:45 akhudek: hmm, maybe the problem is in my representation of the graph then

18:45 hiredman: {[0 1] :x [0 0] :a [1] :p} => [[:a :x] :p]

18:46 akhudek: I was translating svg elements into vectors like [:group :width 10 :height 10 [:rect :x 1 :y 1] [:rect :x 20 :y 20]]

18:46 my idea was to render these during paint

18:47 by traversing the tree and carrying the state as needed by the svg rendering model

18:47 hiredman: akhudek: have you looked at how clojure.xml/parse represents xml?

18:47 akhudek: I should probably do that.

18:47 It doesn't use zippers?

18:48 hiredman: no, it uses a structmap, but you can traverse it via zippers

18:48 akhudek: ok, I'll take a look, thanks

18:49 hiredman: I am rather taken with {[0 1] :x [0 0] :a [1] :p} => [[:a :x] :p] myself

18:59 danlarkin: ,(+ nil 1)

18:59 clojurebot: java.lang.NullPointerException

18:59 danlarkin: suggestions other than try/catch?

18:59 hiredman: ,(or nil 0)

18:59 clojurebot: 0

19:00 hiredman: ,(-?> nil (partial + 1))

19:00 clojurebot: nil

19:00 hiredman: ,(when nil (+ nil 1))

19:00 clojurebot: nil

19:01 akhudek: ah, my current code is actually nearly the same as clojure.xml in terms of representation

19:01 danlarkin: I think the first suggestion is best so far

19:01 akhudek: I simplified to nested vectors here, but really I use structs where a content field contains a vector of structs

19:02 it's great for reading the data, but not so great for rapidly changing several deeply nested nodes

19:03 hiredman: you're representation is interseting

19:04 hiredman: "I find your representation intriguing, and I would like to subscribe to your newsletter"

19:05 Chousuke: danlarkin: the maybe monad :P

19:05 danlarkin: Chousuke: oh jeez!

19:06 Chousuke: hey, monads are sometimes actually useful :)

19:06 not just for pretending IO is mathematically pure.

19:19 akhudek: hmm, your rep. with using a sorted map with an appropriate sort function defining dfs order would work. I'll work with that for now, thanks. :)

20:52 bpattison: is there anyway in clojure to create/define a hash value through a macro? something like (defmacro m [a] `(func :~a)) ?

20:55 arohner: bpattison: can you give an example of how you want it to work?

20:56 macros transform s-exprs, so it's much easier to figure out what you want if you know the start and end points

20:56 :-)

20:57 bpattison: here's the macro I'm trying to get working

20:57 (defmacro def-keyword [word]

20:57 `(def k-~word

20:57 (constant-semantics

20:57 (lit-conc-seq "~word" nb-char-lit)

20:57 (make-node-keyword :~word))))

20:57 sorry about all the newlines

20:58 Makoryu: bpattison: http://gist.github.com

20:58 :p

20:59 arohner: right, but you haven't explained where you're starting and where you're ending up, and I have to guess at what this code is supposed to do

20:59 give me an example of working code without the macro, and what you want the result of the macro to be

20:59 bpattison: http://gist.github.com/198618

21:01 okay, I want it to create a def named "k-~word" that makes use of a hash named ":~word" so the macro would produce "k-new" with hash value ":new" when the macro is invoked with word=new

21:02 and so :new would used in other parts of the code

21:03 arohner: so calling (m {:word "new"}) would call (def k-new) ?

21:04 or (m {:word :new}) would call (def k-word :new) ?

21:06 bpattison: hmm, its more like creating a short-cut for a larger expression and naming it k-new where that larger expressions uses a hash key of :new as well

21:08 (def-keyword new) would produce (def k-new .... :new ...)

21:10 but I get a syntax error on :~word in the macro

21:19 arohner: :word is a literal

21:20 if you want the keyword-ized version of an argument, use (keyword word)

21:20 where word is a symbol or a string

21:20 sorry, only a string

21:20 i.e.

21:20 ,(keyword "foo")

21:20 clojurebot: :foo

21:20 hiredman: ,(keyword (name 'foo))

21:20 clojurebot: :foo

21:28 bpattison: arohner: excellent! thanks

21:46 Makoryu: , (+ 1 "food")

21:46 clojurebot: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number

22:01 kevin__: , (+ 1 2 3) ; curious

22:01 clojurebot: 6

22:02 kevin__: nice, i can write a distributed computing app

22:23 hiredman: ~suddenly

22:23 clojurebot: CLABANGO!

Logging service provided by n01se.net