#clojure log - Oct 19 2009

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

0:02 technomancy: ,(macroexpand-1 '(def #^{:foo :bar} heya 1))

0:02 clojurebot: DENIED

0:02 technomancy: so that expands to (def heya 1)

0:03 what happens to the metadata?

0:03 hiredman: it is on heya

0:03 and def transfers it from heya to the var

0:03 (I think)

0:03 technomancy: hiredman: so it just isn't readable?

0:03 hiredman: #^ is a reader macro

0:04 the reader puts the metadata on the heya symbol

0:04 technomancy: yeah, but 'heya expands to (quote heya)

0:04 I would expect other reader macros to expand similarly

0:04 hiredman: it depends on what the reader macro does

0:05 technomancy: is that just an optimization then? so it doesn't involve a runtime call to with-meta?

0:05 hiredman: I dunno

0:05 technomancy: I guess that makes sense

0:05 makes it kinda tricky to debug though

0:17 solussd: what is the difference between (meta str) and (meta #'str) ?

0:18 ,(meta str)

0:18 clojurebot: nil

0:18 solussd: ,(meta #'str)

0:18 clojurebot: {:ns #<Namespace clojure.core>, :name str, :file "clojure/core.clj", :line 334, :arglists ([] [x] [x & ys]), :tag java.lang.String, :doc "With no args, returns the empty string. With one arg x, returns\n x.toString(). (str nil) returns the empty string. With more than\n one arg, returns the concatenation of the str values of the args."}

0:19 solussd: I guess a better question would be, what does #' do?

0:19 hiredman: #' gets the var named by the symbol

0:19 ,(var str)

0:19 clojurebot: #'clojure.core/str

0:19 hiredman: ,(meta (var str))

0:19 clojurebot: {:ns #<Namespace clojure.core>, :name str, :file "clojure/core.clj", :line 334, :arglists ([] [x] [x & ys]), :tag java.lang.String, :doc "With no args, returns the empty string. With one arg x, returns\n x.toString(). (str nil) returns the empty string. With more than\n one arg, returns the concatenation of the str values of the args."}

0:20 mikem`: solussd: it's a var quote; see "Reader Macros" at http://clojure.org/cheatsheet

0:21 solussd: so it is metadata on the var itself instead of the object the var refers to?

0:24 ,(meta #' (with-meta [1,2,3] {:foo true}))

0:24 clojurebot: java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.Symbol

0:24 solussd: (meta #' (with-meta '[1,2,3] {:foo true}))

0:26 rads: is the source available for any compojure sites? I'm relatively new to clojure/FP and I'm looking for somewhere to get started

0:28 hiredman: solussd: vars are named by symbols

0:28 you can't get the var named by a vector

0:28 solussd: yeah, I see that now. :)

0:29 ,(def x (with-meta '[1,2,3] {:foo true})) (meta #'x)

0:29 clojurebot: DENIED

0:29 solussd: whoa

0:30 (def x (with-meta '[1,2,3] {:foo true})) (meta x)

0:30 hiredman: clojurebot doesn't allow def's

0:30 solussd: k

0:30 hiredman: no need to quote that vector

0:30 or use those commas

0:31 solussd: yeah, that's left over from my previous thing. I program in java all day, it'll take awhile to break the comma habit. :)

0:31 hiredman: ,^(with-meta [1 2 3] {:foo true})

0:31 clojurebot: {:foo true}

0:31 solussd: ,(meta #'(with-meta [1 2 3] {:foo true}))

0:31 clojurebot: java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.Symbol

0:32 hiredman: solussd: you just did the same thing

0:32 solussd: guess I actually have to have a var

0:32 hiredman: and a symbol naming the var

0:32 #' gets the var named by a symbol

0:32 ,(meta (with-meta [1 2 3] {:foo true}))

0:32 clojurebot: {:foo true}

0:36 solussd: so for (def x 1), the symbol is x, the var the symbol names is user/x, and both can have their own metadata?

0:36 hiredman: they can

0:36 user/x is a namespace qualified symbol

0:37 a var by itsself doesn't have name

0:38 solussd: ok, that makes more sense.

0:39 hiredman: #' can be read as "var bound to"

0:39 #'x => var bound to x

0:42 solussd: It'll take me a bit to get used to all the subtly different reader macros that start with #. so far i've seen #{}, #'symbol, #^type-hint, #'regex'

0:43 hiredman: I don't recall ever using #' in actually code, besides clojurebot's doc macro

0:43 tomoj: at least you don't have to get used to custom ones people made up for their files :P

0:44 hiredman: and it's #"regex"

0:44 solussd: this is true. My lisp exposure is pretty slim, but I can see that driving me nuts

0:45 hiredman: using ' where you mean " won't do what you want

0:45 ,(cons 'a' 4)

0:45 clojurebot: java.lang.IllegalArgumentException: Don't know how to create ISeq from: Integer

0:45 hiredman: hmmm

0:45 solussd: right. I've stumbled on that a few times. damn python.. :)

0:46 hiredman: indeed

0:46 solussd: so the :tag reader metadata key for type hinting... You can use it for both the return value and arguments to the function?

0:48 hiredman: (defn #^SomeObject f [#^SomeOtherObject x] stuff)

0:48 unless profiling indicates the need for type hints, I wouldn't bother

0:49 solussd: ok, but if they are different (the arg type(s) and the return value) which gets assigned to the :tag

0:49 ?

0:49 hiredman: uh

0:49 I though I just demo'ed that

0:50 #^SomeObject is the type hint for the function's return, it goes before the symbol that names the function

0:50 #^SomeOtherObject is the type hint for the argument x

0:51 solussd: I understand that, but if I weere to look at the reader metadata for f, would :tag be someObject or someOtherObject?

0:51 hiredman: reader macros that start with # usually apply to the following object

0:51 someObject

0:51 the type hint goes on the var, not the symbol or the function

0:52 solussd: ok. If i were to look at the var metadata for the arg x inside of my function, it would have a :tag value of someOtherObject

0:52 gilbertleung: hi

0:52 hiredman: nope

0:53 gilbertleung: i have this function that works fine when i "require" it from the repl

0:53 but when i wrap it with (with-test )

0:53 hiredman: local names (function parameters, let bound names, etc) are not symbols, vars, etc

0:53 tomoj: so, given a var foo, what's #^Foo foo evaluate to?

0:53 hiredman: the compiler just uses the type hints durring code generation

0:54 gilbertleung: and i run tests within the repl, it starts complaining that "no matching ctor found for class X"

0:54 tomoj: that metadata on the var just gets thrown out after the var is evaled, I guess?

0:54 gilbertleung: even though i've imported class X alredy

0:54 hiredman: tomoj: the metadata is added to the symbol foo

0:54 gilbertleung: am i running the tests wrong or something?

0:54 solussd: so arguments to a function are like things bound with 'let'?

0:54 technomancy: I'm seeing a test "failure" where the thing I'm checking with "is" evaluates to true, but for some reason it's being marked as a failure: http://p.hagelb.org/odd-failure.html

0:54 hiredman: def just copies metadata from the symbol to the var

0:55 tomoj: oh, I see

0:55 technomancy: any idea what could cause that?

0:55 tomoj: ah, yes:

0:55 ,^(quote #^Foo foo)

0:55 clojurebot: {:tag Foo}

0:57 hiredman: technomancy: maybe put in an (= true …)

0:57 technomancy: hiredman: same deal

0:57 even an (is true) fails

0:57 hiredman: what about (is :pass)

0:57 technomancy: expected: true\n actual: true

0:58 same brokenness

0:58 bizarre

0:59 tomoj: if that test worked it would be the coolest test ever

1:00 technomancy: it's got to be a broken test runner or something

1:00 maybe a bug in build.xml

1:00 hiredman: technomancy: nah, deftest is a macro built on other macros

1:01 something else is in the chain is clobbering the symbol's metadata before def can copy it to the var

1:01 technomancy: hiredman: I can copy an is assertion from other tests that pass right there, and it fails

1:02 hiredman: even assertions that don't involve metadata are broken

1:02 hiredman: technomancy: I don't understand

1:02 look at the metadata of the var bound to can-add-metadata-to-tests

1:03 no :has-meta because something somewhere is doing it's own meta thing

1:03 technomancy: hiredman: http://p.hagelb.org/test-brokenness.html

1:03 nothing to do with metadata

1:03 the first passes, the second fails

1:06 hiredman: (deftest some-test (is true "foo")) ;passes with no failures here

1:07 technomancy: hiredman: did you add it to Clojure's test suite?

1:07 hiredman: nope

1:07 technomancy: of course, that works fine if I add it to my own project

1:07 hiredman: well, you never mentioned clojure's test suite

1:08 technomancy: oh my bad...

1:08 context is I'm adding a feature to deftest

1:09 hiredman: well, be sure to use vary-meta instead of with-meta

1:10 technomancy: I added it to the other-functions tests and it passed

1:11 have you recompiled? I dunno, maybe the tests are AOT'ed?

1:12 technomancy: yeah, checked that

1:12 thanks for the tip; I had (vary-meta name assoc :test `(fn [] ~@body))

1:12 I mean, I had (with-meta name (assoc ^name :test `(fn [] ~@body)))

1:13 hiredman: everyone using with-meta just steps on eachother's toes

1:14 lemme git pull and try again

1:15 tomoj: in the one example the expected value looked like it was quoted

1:15 oh, but (= 'true true), nevermind

1:16 hiredman: 0 failures

1:17 technomancy: (is true "should pass") <= fails

1:17 (is true "Should pass") <= passes

1:18 * hiredman re-tests

1:19 hiredman: [java] 0 failures, 0 errors.

1:20 have you tried a fresh checkout?

1:20 technomancy: trying that next

1:21 aha... so test.clj has a custom-report defined

1:21 that acts totally differently from the built-in report

1:21 take a look at around line 100

1:22 hiredman: *shrug*

1:23 I still get 0 failures

1:23 technomancy: any tests defined in test/clojure/test_clojure/test.clj that don't have their message set to "Should pass" will not pass.

1:24 hiredman: ah

1:24 so putting the tests in inside test/clojure/test_clojure/other_functions.clj neatly bypasses that

1:24 technomancy: well at least I'm not going insane

1:24 thanks for following my wild goose chase. =)

1:25 hiredman: well, I am watching seinfeld, and irc is just right there...

1:52 abbe: hi everyone

1:53 what is the difference between 'require' and 'use' at REPL ?

1:53 or in general.

1:54 After executing "(use 'clojure.contrib.http.connection)" I can invoke "http-connection" function, but not after "(require 'clojure.contrib.http.connection)".

2:32 hiredman: abbe: use aliases the bound vars in a namepsace into the namepsace where use is called

2:32 require just loads a namepspace

2:32 you can still the functions, you just have to use the full namespace

3:48 abbe: hiredman, thanks for the explanation.

6:09 octe: http://java.sun.com/javase/7/docs/api/java/nio/file/WatchEvent.Kind.html how do i access that class in clojure?

6:09 (WatchEvent/Kind) or (import (java.nio.file WatchEvent.Kind)) would make sense to me

6:09 but that does not work

6:13 arbscht: that looks like an interface, not a class

6:14 nested classes can be accessed with a $ separator, anyway

6:14 WatchEvent$Kind

7:55 eevar2: did anything change in the google groups' spam settings recently? there's been 3-4 spam mail in the last few days

8:01 rhickey_: chouser: what do you mean by 'function params will ever support :as' ?'

8:37 chouser: rhickey_: I mean that fn params currently support & like destructuring vectors do, but they don't support :as in the same way

8:39 it seems to me that they could, though it would be a bit of a lie since whatever object was bound by :as wouldn't actually be the exactly the same object used for passing the args

8:39 so I was just curious if it was in the "maybe eventually" or the "never gonna happen" category.

8:43 cgrand: chouser: there's the ugly [& [a b & etc :as all]] :-p

8:44 chouser: cgrand: ah, good point.

8:44 cgrand: doesn't support multiple arity though

8:45 chouser: I'm not sure how useful of a feature it is; I was thinking more about consistency.

8:45 right now there are two different contexts where & works, but :as only works in one of them.

8:46 cgrand: chouser: I understand

8:48 :as would play the same role as arguments in javascript -- but while I use it frequently in js, I never needed it in clojure because of arglist destructuring I guess

8:51 rhickey: are you talking about, given (fn [a b & c :as d]...) fabricating an object d holding (list* a b c)?

8:51 chouser: yes

8:51 rhickey: hrm

8:52 I wouldn't think that would be half as desired as some way to get rest-as-map

8:53 chouser: for keyword args?

8:53 rhickey: just to automate & xs ... (let [m (apply hash-map xs)...

8:54 not exactly the same as keyword args but good enough if you could destructure it

8:55 chouser: as far as actual desire, you're probably right. I was just curious if the consistency argument carried any weight with you.

8:55 rhickey: on another topic so the design for datatypes + protocols moved forward significantly this weekend

8:55 chouser: there never was a d, so not a consistency thing IMO

8:55 chouser: only came up because I found myself explaining the difference between destructuing & and parameter list &

8:56 rhickey: that's the difference - in destructuring there was one thing

8:56 chouser: ok, that's all I was asking, thanks.

8:56 so -- protocols?

8:57 rhickey: I have to organize my notes (keeping only the move forward ideas and not some of the speculative ones)

8:57 chouser: ah, sure.

8:57 rhickey: It starts with datatypes, if you don't do interface + impl then you need fast access. This also ties into the desire to first-class-ize structs, re compilation etc

8:58 so (deftype org.clojure.Foo fred #^int ethel #^String lucy)

8:58 gives you a proper class, with three fields

8:58 all final

8:58 a ctor

8:58 equality and hashCode

8:59 chouser: map interface?

8:59 rhickey: ILookup-style access via keywords corresponding to :fred :ethel :lucy

8:59 chouser: or strictly interop for access?

8:59 ok

8:59 rhickey: I'm not sure yet about full Associative/expando

9:00 I also have ideas about field aliases, so you could also say name was foaf:name

9:00 this allows for true attribute polymorphism, not just accidentally same local names

9:01 chouser: nice

9:01 rhickey: a long standing problem IMO is classes defining their own languages, this separation of code + data, plus uri-identifiable attributes, solves that

9:02 you'll also get a constructor fn Foo, and possibly nth support, so could destructure with [f e l]

9:02 metadata support

9:03 abbe: closures aren't possible in clojure, right ?

9:03 chouser: abbe: yes they are.

9:03 rhickey: this would be a properly compiled class, but I want to support synamic use without precompilation, subject to the must reload on change

9:03 dynamic

9:04 abbe: chouser, sorry, i mean with mutable bindings. like iterator functions.

9:04 rhickey: no inheritance of any sort

9:05 chouser: abbe: locals are immutable, but you can bind a local to a mutable thing (like an atom or ref) and close over that.

9:05 abbe: chouser, oh, okay.

9:05 thanks chouser

9:06 Chousuke: that's not very idiomatic in clojure though.

9:06 chouser: an iterator isn't, but I don't think there's anything wrong in general with using closures to control access to your mutable state, is there?

9:07 rhickey: datatypes being proper host classes with typed fields means that manipulation code written in Clojure will be fast, not tying that to the inside of reify

9:08 chouser: rhickey: yeah, I figured this would mean a finger tree rewrite. :-)

9:08 rhickey: chouser: should just be moving things around a bit

9:09 chouser: but it's good -- I initially wrote the basics using a map for each node

9:09 rhickey: so, datatypes are nice, immutable, fast, strongly typed but with fast dynamic access

9:09 I imagine something like the new string switch for the keyword lookup

9:09 chouser: converting that to using reify and closures for performance seemed an unfortunate step.

9:10 rhickey: this gives people the type they want for structs

9:10 and a compilation story

9:10 plus primitive members if needed

9:10 so that's the data side, pretty much I think

9:11 chouser: I'm a bit surprised you're ok with the reload-jvm-on-change.

9:11 rhickey: whatever is fastest will require that

9:11 chouser: we've had a few runs at that with gen-class and gen-interface, and walked them both back.

9:11 rhickey: in the reify story that would have been interfaces

9:12 i.e. interfaces would be static, defined up front, and not dynamically alterable

9:13 you simply can make something dynamic that's competitive with field access

9:14 but this way that speed is readily available to all future code, not just at-birth method code

9:15 cemerick: add Associative to this mix, and it's exactly what we've been pining away for. :-)

9:15 rhickey: chouser: i.e. you won't have to move your ft code to map-like code, you can use .this and .that

9:15 just move your impls from methods to protocols or ordinary fns

9:16 cemerick: associative meaning lookup or expando?

9:17 cemerick: heh, I had never heard of "expando"

9:17 But yes, having that is incredibly convenient.

9:17 so much so that I don't think I'd want to back away from having it in most cases.

9:19 rhickey: expando is on the fence right now, one issue is implementing it without datatypes becoming instanceof map/associative

9:19 when associative is a protocol there will be different options

9:20 opps, just noticed above: you simply *can't* make something dynamic that's competitive with field access

9:20 cemerick: well, I'm in late, so I don't know the background on 'datatypes'. I suspect they're one step below the level of abstraction we'd use directly.

9:21 rhickey: datatypes are just typed holders for data - no methods

9:21 so, then protocols

9:21 these are groups of functions, polymorphic using single dispatch

9:21 you create one specifying the method names and sigs

9:22 then implement for various types

9:22 implementation is just (implement AProtocol AClass {:methodA afn :methodB bfn})

9:23 this will allow for handy reuse of impls without any derivation junk

9:24 most of the things Clojure now uses interfaces for will be protocols

9:24 cemerick: In that case, implementing "expando" would be straightforward if we could define an impl for assoc for a given datatype.

9:24 rhickey: cemerick: not quite, as you'll need a slot for the expando map in the data

9:25 and integration with the lookup logic

9:25 so, best if built-in

9:26 but it does highlight an important aspect of protocols, they can't require additional data

9:26 cemerick: ugh, I shouldn't get in so late. This is parallel to reify, right?

9:27 rhickey: the reify work will probably become uber-proxy, a host interop thing you can use to keep doing Java-style

9:28 but I think proxy can be made fast and has a number of important attributes

9:28 separation of code and data

9:28 independent extension

9:28 reuse w/o derivation or composition

9:28 or adapter generation

9:29 oops protocol, not proxy

9:29 cemerick: OK, you really had me confused for a minute.

9:29 rhickey: you can implement a protcol on nil

9:30 chouser: you'd have to, so you can cons onto it. :-)

9:30 rhickey: in order to enable bridging to Java hierarchies, you'll be able to define a protocol on an interface

9:30 that opens the dreaded multiple inheritance of implementation hole

9:31 I haven't decided yet how best to plug it. It could be - an arbitrary choice, which should work since both impls must have same semantics

9:32 or, something like the prefers system on the protocol level

9:33 chouser: yes, many of the core abstractions are defined for nil, it's one of the things in the RT if/else stuff I want to make go away

9:34 protocols will be fully reified, and have useful properties like (aprotocol :amethodname) -> a polymorphic fn

9:34 and (aprotocol AClass) -> a method map

9:35 protocols are fully dynamic

9:36 not sure how clever we can be with protocol mods not disturbing existing impls, but no restart ever required, just re-eval impls

9:37 combining datatypes and protocols, you'll have fast access to the data in the impl

9:38 but new protocols can be defined and implemented on existing datatypes at any time by 3rd parties, solving the expression problem

9:39 you can define more generic protocol impls by using :name instead of .name, or even better, :uri-name

9:40 anyway, that's the basic idea

9:41 I've started on datatype, it's Clojure code in gen-class, lifting lots from there

9:41 chouser: sounds emitently doable.

9:41 rhickey: I could use help, there will be many discrete things like implementing hashCode, equals, fast keyword lookup...

9:42 I imagine there is some sample bytecode for the new String in switch feature of Java 7 we could mimic for the latter

9:42 chouser: I think people will understand how to use it easily (the basics anyway, even if they don't immediately grasp the full flexibility)

9:42 rhickey: then protocol could be defined in terms of datatype

9:43 chouser: it == datatypes + protocols.

9:43 rhickey: chouser: I think so, this will be a major benefit, something most people want even with generic functions, some higher level abstraction mechanism to gather methods

9:44 protocols roughly map to interfaces without the instanceof and at-definition-time aspects

9:44 chouser: right

9:44 and people already try to do many datatype-like things with structs

9:44 rhickey: datatypes just do the right thing immutability-wise, and otherwise look like structs, or maps when convenient

9:45 right, this gives more structure vs structs, types etc

9:45 the dynamic use thing is important, not so much the redef/reload, but just not needed precompile

9:46 it's tricky, possibly the best way to support it is to require a compilation target dir during development. with a target dir in the classpath, deftype can gen to file, and the class can be picked up (once) via normal classloading, and thus generally visible under those rules

9:47 chouser: yes, I very much agree. precompile brings a whole batch of configuration complexity that is nice to postpone until someone is fully hooked on the usage.

9:47 rhickey: with gen-to-memory though there will always be visibility issues

9:47 so I'm favoring gen-to-disk but would like feedback

9:49 chouser: oh, so datatypes wouldn't work at all without the classes dir setup?

9:49 rhickey: i.e. dynamic use requires write-access to dir in classpath

9:49 chouser: there's no way to expose a loaded-from-memory class generally to all possible consumers due to classloader issues

9:50 at least not without wrapping the entire Clojure process in a custom loader

9:51 chouser: that's where I see people struggling, though, trying to get the dir created, given in Clojure config, given in classpath, all at JVM startup time (which means each editor/IDE has their own mechanism)

9:51 rhickey: I'm open to suggestions, but rootClassloader didn't really work

9:51 chouser: yeah

9:52 Can't we get the JVM to include a load-from-memory method in the normal classloader?

9:52 :-P

9:52 cemerick: rhickey: FWIW, hot-reloading of code through a remote repl in NetBeans RCP works like a charm...never any visibility issues as far as I can tell

9:52 rhickey: there's simply no standard way to make a loaded-from-memory class available to the base loaded

9:52 cemerick: (that's with thread context classloader, BTW)

9:52 rhickey: cemerick: every one of those environments has a non-standard enhanced classloading system

9:53 cemerick: yeah, I know, just offering up a data point

9:54 rhickey: cemerick: without Netbeans platform or OSGi or something else in the mix, I don't see a way other than wrapping Clojure process, itself full of caveats

9:55 chouser: what's a common example of visibility failure?

9:55 rhickey: cemerick: also note that Clojure code easily reloads and shares because the actual classes are never exposed, only the shared IFn interface loaded with Clojure

9:56 these datatypes will be referenced explicitly by name

9:56 cemerick: oh, and deftype would create and expose a new named class com.foo.Datatype

9:56 or, interface?

9:56 rhickey: no interface

9:57 cgrand: what about providing a clojure-specific system classloader through -Djava.system.class.loader? Thus simple settings wouldn't need to write to disk.

9:58 chouser: I'm wondering if it would be resonable to prefer the gen-to-disk route, maybe even print a warning if it fails, but fall back to in-memory to help people get more success early before having to deal with directory and classpath issues.

9:58 rhickey: cgrand: yes that's the wrap-the-process I was talking about. I don't have much experience with it, but it should be possible

9:59 the bigger question is, what is the target for dynamic use - is it just interactive development or some sort of dynamic deployment?

9:59 for the latter I'm happy to say precompile deftypes

10:00 but I imagine the wrapping classloader is incompatible with netbeans et al

10:01 chouser: so rootclassloader as fallback?

10:03 chouser: yes

10:03 rhickey: the biggest issue with all dynamic solutions is they often don't work in production without specific bridges to the application host (netbeans, osgi, netkernel etc). Precompilation make the problem go away completely, and there really isn't any such thing as a (useful) dynamic datatype in production

10:04 this is another nice thing about breaking it up this way (data is most static)

10:04 chouser: fallback to baseLoader is only useful if the visibility problem is rare enough during simple dynamic development scenarios.

10:04 rhickey: chouser: but you agree dynamic is mostly about dev-time?

10:06 chouser: I think so. If you actually need dynamic deployment and restarting the JVM isn't an option, you've got a whole lot of other concerns that you'll expect to have to spend effort solving.

10:06 using a new name for your "updated" datatype for example, and making that work with all your running code. ...at that point getting the classpath set right is the least of your worries.

10:07 rhickey: yes, but dynamic code still fine, in fact easier than ever with protocols

10:08 chouser: yes, if your data isn't changing (or it you accepted the performance impact of a regular map up front), then protocols, multimethods, and regular var fns give you a lot of dynamic deployment options.

10:09 but that's also outside my experience -- I've never tried to do real dynamic deployment.

10:10 rhickey: I should play more with -Djava.system.class.loader, it would be easiest for standalone and other repls, would just need some coordination with IDe folks for per-IDE solutions

10:11 cemerick: Totally aside from the technical issues, requiring stuff like messing with the system classloader, setting up designated compilation dirs, etc., is all suicide for new update IMO.

10:13 ack. uptake*

10:14 konr: Guys, I've got a function that prints some data. How can I make it return this data instead of printing it?

10:15 chouser: konr: wrap it in (with-out-str ...)

10:16 though that may be taking your question too literally.

10:16 rhickey: cemerick: well, there's always rootclassloader and its limitations. Perhaps they won't really come to fore in dev only. Most of its problems were in deploy in environments like OSGi etc. So the story would be, precompile before going there

10:18 * cgrand just realized that datatypes could be serialized by default #=(org.clojure.Foo. nil 1 "lucy")

10:19 cemerick: rhickey: I think RCL is totally appropriate in development, and IDEs like enclojure and slime/swank can do what they need to to set things up properly for those environments. I know that I wouldn't bother with any casual programming in a language that required knowing about such things up front.

10:19 rhickey: cgrand: I've been thinking about #org.clojure.Foo{:fred 1 :ethel 2}

10:20 cemerick: yes, the flipside is the confusion that results when it doesn't work

10:20 cgrand: yes, dedicated reader support looks nice

10:21 chouser: fwiw, I'm in favor of late confusion over early complexity here.

10:21 cemerick: well, hopefully Joe programmer only hits that when he's nearing deployment time, at which point he's well into internalizing the awesomeness of clojure.

10:21 +1 chouser Gotta keep the learning curve as gentle as possible.

10:22 * rhickey looks to see if he had completely ripped out RCL...

10:22 cemerick: (modulo the pedagogical references to reify wiki pages and such ;-) )

10:23 ttmrichter: I have a pretty clueless newb question here: where do I get a version of clojure-contrib that compiles under clojure 1.0.0-?

10:23 chouser: It may be worth a warning by default -- if you (deftype ...) at the REPL and gen/load from disk fails, print "Classpath config is not optimal -- see foo if class is not visible later."

10:23 or something.

10:24 * rhickey had

10:25 ttmrichter: Sorry. Not compiles. Works with.

10:25 My bad.

10:26 chouser: ttmrichter: there's a compat-1.0 branch of the contrib github repo that should work.

10:27 Chousuke: rhickey: the #foo.bar{} reader syntax for datatypes would disallow using any letters for # dispatch, though :/

10:28 rhickey: RCL for datatypes might not be as bas as RCL for code was - a big problem for RCL was code loaded there couldn't see other parts of the world, or could load classes then not seen, but here there will be no code other than self-referencing methods

10:28 as bad

10:30 Chousuke: Maybe something like #Cfoo.bar{:key val :key2 val2} wouldn't be too bad (C for constant)

10:31 rhickey: Chousuke: not necessarily, most CL #letter thing specify what must follow, so more letters would mean this isn't #letter

10:32 e.g. #p"...", #c(..), #nA ...

10:32 but yes, it would complicate things

10:35 ttmrichter: OK, I was right the first time. Compiling clojure-contrib isn't working with the 1.0.0- version of Clojure.

10:36 Is there a release of clojure-contrib that is known to work with clojure 1.0.0-?

10:36 chouser: ttmrichter: there's a branch on contrib in the github repo that's compatible with clojure 1.0

10:36 ttmrichter: Thanks chouser.

10:46 dmiller2718: rhickey: Any thought to the CLR implications of all this?

10:47 cemerick: bah, found yet another instance where I screwed up the class/symbol :tag metadata in a macro

10:52 chouser: cemerick: it seems like instances of Class could be supported there. Have you asked?

10:53 cemerick: chouser: no. I've just considered it a mental problem on my part. That, and I try to make sure that I ring the bell on important stuff.

10:54 When we get to HEAD sometime around 2014, I'll probably submit a patch for it.

10:54 :-/

10:56 AWizzArd: cemerick: did you decide which framework you want to use for your rest webservice?

10:56 cemerick: AWizzArd: it's largely not my call, I probably won't be doing the frontend work.

11:06 triddell: Anyone else here use clojure with IBM jvms? As far as I know issue #104 (http://www.assembla.com/spaces/clojure/tickets/104-GC-Issue-100--gen-class-creating-non-compliant-field-names-) still has not been addressed.

11:07 although there was some discussion in sept on the list: http://groups.google.com/group/clojure/browse_thread/thread/ce2b067acb60526f/93db150588425575?lnk=gst&q=issue+100#93db150588425575

11:12 headius: love those IBM JVMs

11:12 they're more stringent on method names too

11:12 peregrine81: Hey I'm trying to learn Clojure and do some of the Project Euler stuff. and I keep running into this http://pastie.org/660665

11:12 Has code + error

11:13 headius: I'd guess it's the "Find the.." string, but I don't actually know clojure

11:15 peregrine81: headius: thats actually the function comments

11:15 konr: Do Java objects use some sort of different *out*? I'm failing to capture what it prints with (with-out-str ...)

11:17 triddell: headius: well, the initial suggested patch replaces "-" with "$" in the method names, which has worked for me in the past... I just didn't know there were deeper issues to be looked at from the gurus

11:17 cemerick: konr: rebinding *out* doesn't change System.out, AFAIK

11:17 headius: I think it was - I ran into an issue with too

11:17 or one of the other operators...maybe +

11:18 actually I have a couple questions about gen-class, if anyone cares to chat

11:18 we're looking at building something similar for jruby

11:19 have it working basically...but the lack of joint compilation or circular dependency mgmt is a hassle

11:19 somnium: peregrine81: its the (e), e is an int, when you wrap it in a list clojure thinks its a function call

11:19 headius: does clojure's gen-class do anything more than just spit out a pseudo-class that's implemented with clojure code?

11:20 cemerick: headius: gen-class classes don't contain any impl -- that's all still in clojure-land

11:20 peregrine81: somnium: THANKS! That makes perfect sense.

11:20 headius: so they classload something-or-other though, right?

11:20 peregrine81: somnium: thanks again, it seems so obvious now

11:20 headius: in JRuby it's similar...the generated class just embeds (as strings, no less) the source you tell it to

11:20 static load of the class evaluates the sources and then you're off to the races

11:21 somnium: peregrine81: np

11:21 cemerick: headius: yeah, they load and bind against the namespace you specify in the gen-class form (which ns provides a reasonable default for)

11:21 headius: but the circularity issues are yet to be resolved, so you can declare two classes with cross-dependencies

11:21 mmm ok

11:21 cemerick: joint compilation is tricky though. I think groovy has that nailed, but I've no idea if the implementation there is reusable at all.

11:22 headius: it's not as far as I know

11:22 there was some discussion on creating an uber-compiler at JVMLS, but I don't know if it has progressed

11:22 if there were a top-level compiler that handled depedency resolution and queried language-specific plugins for the types their sources exposed, almost all jruby's "class" generation would be done

11:23 ericthorsen: has anyone played around with JParsec (java parser combinator) and clojure?

11:24 Makes heavy use of generics and I seem to be having some problems right out of the gate with class access to support classes I'm not directly calling

11:24 cemerick: I'll bet something like that could be put together in short order if all the principals got in a room (e.g. without any Sun/JCP involvement)

11:25 headius: cemerick: probably

11:25 I need it for duby's compiler too

11:26 so far I've been doing it myself, but implementing Java Lang Spec method dispatch is...interesting

11:27 cemerick: presumably the trickiest issues would be around boxing off javac properly.

11:27 headius: very likely

11:28 cfox: who *

11:35 rhickey: dmiller2718: should be very straightforward on CLR, I'm not relying on JSR292 or anything. This stuff is on the path to cinc and the many benefits it has for portability

11:35 jlilly: stupid clojure-learning-weekend and it affecting my work code.

11:35 :-P

12:01 somnium: jlilly: the pain of not using clojure?

12:01 jlilly: somnium: I'm using python, so its not too bad.

12:02 but I wrote a function that accepts functions as an argument etc etc

12:02 somnium: jlilly: I mostly do ruby, used to think blocks and define_method were amazing, now they just seem broken ... :(

12:03 clojure will set you free

12:26 hiredman: eclipse's java compiler might be nicer to use for a project like a super compiler

12:40 rhickey: http://www.assembla.com/wiki/show/clojure/Datatypes

12:41 hiredman: clojurebot: datatypes is <reply>http://www.assembla.com/wiki/show/clojure/Datatypes

12:41 clojurebot: Ok.

12:44 rhickey: feedback welcome

12:47 chouser: with-meta would copy all fields?

12:47 stuartsierra: interesting, esp the URI bit

12:47 rhickey: chouser: yes

12:47 basically calls the ctor

12:47 chouser: but no assoc support with the same behavior?

12:48 rhickey: stuartsierra: yes, I'm tired of these impedance mismatches, this (attribute semantics) is a longstanding problem and RDF's solution is as good as any. Building it in is key, else you are constantly left with mappings

12:48 danlei: how about a deftype read/print syntax like this: #s{org.myns.foo :fred 1 :ethel 42 ...}

12:49 s/#s/#t/

12:49 rhickey: chouser: that's there under Associative/expando

12:49 chouser: oh, yep. sorry.

12:51 rhickey: chouser: the only reason it's not in basics is I haven't thought through all the ramifications. As far as storage overhead, both meta and expando are one word each. For a 2-slot datatype that's a doubling, but the per-object overhead is like 6 words, so only 25% or less

12:51 the dissoc a field = non-type seems fair

12:52 chouser: the URI field alias really is a lovely idea.

12:52 rhickey: the only other thing is I don't want datatypes to show up as instanceof maps necessarily

12:52 chouser: dissoc on a struct field is currently an error, is it?

12:52 rhickey: yes, an error

12:52 but a wart

12:53 should just become non-struct

12:53 cemerick: Is there any other use case for the field IDs that isn't RDF-related?

12:54 rhickey: danlei: very CL-like, but I'm not sure I like mixing the name with the key/val pairs

12:54 chouser: dissoc + assoc wouldn't take you back to a compatible object.

12:55 danlei: rhickey: yes, I'm sceptical about that too, but I don't really like such a long prefix either ...

12:55 cemerick: I'd much rather have an error on dissoc of a field.

12:55 chouser: cemerick: I can imagine using namespaced keyword aliases just for bookkeeping inside a large app

12:55 rhickey: cemerick: I think it is a general problem. Consider, you want to write some type-independent data processing code. Without uri aliases you are left with duck-types on local names, always a mess

12:56 cemerick: but the (error on dissoc) precludes treating structs uniformly as associative things in the relational world, i.e. as information

12:57 uris are interfaces for fields/attributes/properties

12:57 cemerick: well, to chouser's point, assoc and dissoc should be symmetrical w.r.t. types/structs/whatever.

12:57 (IMO, of course)

12:59 rhickey: cemerick: I disagree about the symmetry - the whole point of the dominance of associative types in Clojure is to deemphasize type-specific information processing. So, while you might have a data structure for a specific purpose, when you start using assoc/dissoc/join etc with it you are using it (profitably) as a generic information source

13:00 cemerick: I guess the utility of URI naming is dependent on one's domain, and the complexity of the data modeling therein. I can't say I've had much trouble with name duck typing, although perhaps I don't know what I'm missing in some way.

13:01 danlei: rhickey: how about this: |org.myns.foo {:foo 42 ...}| ?

13:01 rhickey: danlei: I don't think I'm ready to use up || yet

13:01 danlei: ok

13:02 hiredman: what about host independent stuff? it seems like it would be nice to create a datatype constructor fn and have some generated clojure name for a datatype other than a java class name

13:02 rhickey: hiredman: oh, yes, there will be a Foo fn, I forgot to include that

13:05 hiredman: fixed

13:05 hiredman: :)

13:06 if you do end up passing a map to the constructor, I think it would be nice to pass a map to deftype (deftype {:foo String :bar List})

13:14 stuartsierra: rhickey: I'm working on code generation from an RDF ontology: http://tinyurl.com/yhthzjj

13:28 danlei: another possibility would be plain: #t(my.ns.foo {:foo 42 ...}). just #my.ns.foo{:foo ...} feels to "unparenthesized" to me. Personally, I'd prefer #t{my.ns.foo :foo 42 ...}, or one of the other options to it.

13:31 somnium: danlei: its the first time I've heard a complaint that lisp does not contain enough parentheses :)

13:31 danlei: :)

13:32 I actually liked them right from the start :)

13:39 chouser: this is new. spam sent to the group apparently from the accounts of good members such as kotarak and rhickey.

13:39 danlei: design question: for something like a telnet client, what would be an idiomatic clojure approach of handling the socket? atm, I just do like I would in an imperative language: A loop which reads available characters and operates on them. In general, is there a preferred way to do things like this in Clojure?

13:40 Or: Is there a "fp-idiom" to handle things like this?

13:41 (maybe a stupid question :)

13:42 chouser: no, it's a good question.

13:42 I've done it a couple times now and am not exceedingly pleased with any of the results.

13:42 rhickey: chouser: yes, I saw that - I moderated myself. If you see someone else being impersonated, please set moderation on for them

13:42 stuartsierra: I saw that, but haven't looked too closely

13:43 danlei: chouser: what were your approaches?

13:44 chouser: rhickey: I only saw it with kotarak a.k.a. Meikel Brandmeyer, but didn't notice until I had un-moderated him once. sorry about that.

13:44 danlei: all I can suggest is do everything you can to contain the statefulness and mutation.

13:44 rhickey: chouser: np, this is very annoying. when I looked into it I found that it is common on ggroups, and we've just been lucy so far. The only surefire defense is full moderation

13:45 lucky

13:45 chouser: danlei: This amounts to studying each function you write to see if it is impure. If it is, try to make it pure or factor out as many pure parts as possible.

13:46 danlei: chouser: I thought about having just the socket reads in the loop and putting read lines in a ref, than have a watcher on that

13:46 chouser: rhickey: that's quite frustrating. a quick look at the message suggests it's simple smtp envelope spoofing.

13:46 danlei: *then

13:46 chouser: danlei: I'm not sure that's better than just calling a pure function directly from your loop.

13:47 danlei: chouser: me too ... that's why I'm asking :)

13:47 chouser: danlei: I don't have much for you. Maybe somebody else has better ideas.

13:47 rhickey: chouser: yes, just the from: field, but that's what ggroups keys moderation on

13:47 danlei: chouser: thanks anyway

13:48 chouser: danlei: another option would be to send to an agent from your loop -- that would let the work queue up and be handled in another thread, and help enforce purity.

13:48 rhickey: full moderation would be quite onerous.

13:48 rhickey: chouser: yeah

13:49 danlei: yes, that's something I considered, too

13:50 chouser: maybe this would be a good use for monads, but I'm not really at home with them

13:51 rhickey: chouser: have to be careful when getting spam via a valid user to just remove and not flag as spam, else will ban user!

13:51 * rhickey almost just banned himself

13:52 Chousuke: danlei: with the reader (which I still have to finish :() I had a similar problem... The input comes from a PushbackReader, which is stateful.

13:52 chouser: rhickey: bleh. ok.

13:54 Chousuke: danlei: I just converted the input to a seq of chars and made my reader work on that. probably not fast, but at least I didn't have to care about the statefulness :)

13:55 danlei: Chousuke: : I'll take a look at it again. I took a similar approach for my little cl-like format implementation, before I knew about faulhaber's great work

13:56 Chousuke: the thing is not very well designed though (or designed at all, actually). It's basically the simplest possible approach :P

13:57 danlei: well, I wouldn't have done better :)

13:57 also, the simplest approach isn't necessarily the worst one

13:57 Chousuke: I guess.

13:57 it'd be nice if the reader were restartable though.

13:58 as in, if it doesn't get the input it wants it just returns and you can feed it more stuff.

13:58 danlei: more like what you did with my ansi-sequence thingie?

13:58 Chousuke: yeah.

13:58 * danlei nods

13:58 Chousuke: I used monads with that. I don't have monads available for the reader ;(

13:59 danlei: Yes, but there was a nice stateless version before that, too

13:59 I still haven't grasped Monads yet, gotta take some time for it

14:01 I think the big picture is that they are a very general means for composition, but I didn't really understand how to use e.g. the state monad in real code. must have a look at your implementation of the ansi-thing again.

14:02 Chousuke: I guess if I make the reader restartable I'll end up writing a monad anyway

14:02 even if I don't call it one :P

14:02 danlei: :)

14:04 Chousuke: but I should figure out how to integrate the reader with Clojure itself next. that would help with testing.

14:04 danlei: go for it, I'll be an early adopter :)

14:04 Chousuke: it's not complete but it'd be interesting to see what blows up.

14:06 danlei: I could even use it in my client, instead of parsing user input I could have something like ! dispatch for commands and so on

14:07 but atm it's all a horrible mess, I'm just rewriting the whole network stuff and have plowed through the protocol, implemented a little telneg DSL &c

14:09 and, to be honest: there still is the stateful ansi-sequence parser in it ;)

14:46 avital: /j shiftspace

14:47 ...strange

15:17 rhickey: http://www.assembla.com/wiki/show/clojure/Protocols

15:30 liebke: rhickey: very interesting

15:35 chouser: So... I could implement a protocol by providing a datatype instance? :-)

15:37 hiredman: it seems like a mistake to rely on java classnames

15:38 rhickey: chouser: yes, (implement aprotocol adatatype ...) is the idea

15:39 hiredman: datatypes would have a .getName method and protocals would prefer that to classes

15:39 rhickey: hiredman: I'm on the fence about extending to dynamic type slot. It's a flexibility/speed tradeoff.

15:40 chouser: rhickey: oh, right. I meant the more subversive and less useful (implement AProtocol AClass (ADatatype. (fn ...) (fn ...)))

15:40 hiredman: rhickey: I'm not saying it should be dynamic

15:40 just a clojure name vs. a java name

15:40 rhickey: chouser: for what purpose?

15:41 chouser: I have no purpose, just noting how pervasive the core interfaces (map in this case) are.

15:41 rhickey: hiredman: implement is evaluated, you can just put the class in a var

15:41 (implement myprotocolvar myclassvar mymapvar)

15:42 chouser: yes, that's still the plan, everything connects together

15:42 hiredman: yeah, but if you move code to different host that doesn't have java names...

15:42 I guess that is just pie in the sky

15:44 rhickey: hiredman: no, it's a good point. I'm not sure it's a serious problem as there will be several ways to encapsulate the name

15:44 chouser: hiredman: fwiw, ClojureScript used Java-like names for things, and I think the .Net port does too.

15:44 as in, it was still accurate and useful to say (instance? clojure.lang.IPersistentMap x)

15:45 cemerick: Does anyone know what one would use under LLVM in that context? I presume that'd be the next likely target.

15:45 hiredman: chouser: well, java like names just are names with dots in them, which I have no problem with, the issue is tieing this all to the existence of classes

15:45 rhickey: cemerick: that begs my question - where are the libs for LLVM?

15:45 hiredman: a jave name is a class

15:46 rhickey: hiredman: on the CLR it's a CLR class and in ClojureScript an object I presume

15:46 * hiredman just got his file manager to display the llvm dragon logo as the icon for llvm files

15:46 hiredman: hmmmm'

15:46 cemerick: rhickey: I've no idea -- I presume it'd be platform-bound. There was an Apple fellow here a while back talking about how dreamy clojure-on-LLVM would be. *shrug*

15:46 chouser: a dotted name in clojure is a host class name -- exactly what that means can change as long as the required behaviors are supported.

15:47 hiredman: ok

15:47 rhickey: I think the demands on the host from datatypes and protocols are minimal

15:48 cemerick: Clojure on Obj-C is interesting, if only there was GC on iPhone

15:49 chouser: datatypes will be implemented using asm calls like gen-class, right? Those parts will have to be hand-ported along with the gen part of the compiler.

15:49 cemerick: My sense was that that was this guy's idea, but he was sorta cagey about the eventual runtime environment.

15:50 chouser: by protocols will require very little gen support I would guess.

15:50 rhickey: chouser: yes, datatypes are code gen, but protocols should only need datatypes and Clojure itself

15:51 the dispatch function needs to be as fast as possible

15:51 gasc: on protocols, is it a performance reason or a design reason that motivates dispatching on only the first argument, rather than letting the designer of the protocol choose the dispatching argument for a given method? maybe i'm missing something as to why the latter wouldn't make sense...

15:53 rhickey: gasc: no, that's still a possibility. I have in my notes letting the protocol specify a name for the dispatch arg (defprotocol AProtocol [x] (foo [a x y]...))

15:54 it's more complexity and I'm not sure how often it would be used. I couldn't find one case in Clojure where the dispatch arg didn't end up being first in the resulting Clojure fn

15:55 wher eClojure now uses - interface method + RT dispatch wrapper + Clojure fn

15:56 chouser: cons narrowly escapes

15:56 cemerick: The diff between protocols and multimethods narrows.

15:57 rhickey: protocols are like groups of multimethods with hardwired dispatch fn, and implement-as-a-set only

15:58 you always end up wanting some abstraction for sets of generic functions anyway

15:59 AWizzArd: rhickey: the new Datatypes page in the assembla wiki looks very interesting *thumbs up*

15:59 rhickey: I think much easier to manage a protocol than say, 5 independent multimethods

15:59 cemerick: so given arbitrary-argument dispatch, protocols would eventually overtake multimethods as the de facto polymorphism mechanism (assuming most multimethods have very simple dispatch fns)

15:59 (or, type-of-argument dispatch fns, that is)

16:00 rhickey: cemerick: the numbers in any study of multiple dispatch point to vast majority being single dispatch on type

16:00 again, I haven;t seen a lot of call for other-than-first arg, show your use cases now...

16:01 I think the ideal compliment to protocols is full predicate dispatch, something to which I'll eventually return

16:01 but multimethods still have great utility. I know I've used the non-type and multiple arg aspects and so have many others

16:02 I have some high-perf implementation ideas for protocols that may make it back into multimethods - e.g. perfect hashing based dispatch

16:02 gasc: rhickey: got it. first-argument dispatch has a more java interop-y feel, like real methods, but as one gets away from thinking in terms of methods i can see it being pretty cool and useful, gives the author more syntactic freedom etc., cf str-utils2 (i think). but weighing the cost-benefit of that extra form in the definition will of course be up to you.

16:03 cemerick: rhickey: is there any sense in attempting to simplify the aggregate semantics -- e.g. make protocols a specialization of multimethods, where if no dispatch fn is provided, the type of the first arg is used, and dispatched on very efficiently.

16:03 rhickey: gasc: I would still need to analyze any perf aspects as well

16:05 cemerick: simplify or generalize? i.e. generalize multimethod sets

16:05 protocols are pretty simple

16:07 cemerick: Generalize, I suppose. My point being, protocols and multimethods are very similar conceptually (at least as far as I know the former so far). If that's true, then avoiding having to make a choice between them for typical cases would be ideal.

16:09 Chousuke: hmh

16:10 rhickey: cemerick: I don't know. Right now protocols centralize at the protocol, not method level. So multimethod sets would still be different from single multimethods

16:10 Chousuke: I can't quite figure out what I need to do to make clojure use my reader instead of LispReader ;/

16:10 rhickey: a set that included true multimethods would be associated with what at implementation time?

16:11 i.e. a protocol is a relationship between a class and a protocol, what is the correspondence for true multimethods?

16:12 cemerick: dispatch val and fn

16:12 and protocols are just using the class of the first arg as the dispatch val, so...

16:12 rhickey: that's one of the reasons why it is hard to group multimethods, when you implemented the group you've done so for what target? Each method could have a different dispatch val

16:12 hiredman: Chousuke: replace read with a call to your reader?

16:15 rhickey: I guess you could just manually ensure a consistent dispatch value for a set of multimethods

16:16 cemerick: rhickey: my main concern is just that the introduction of protocols muddies the waters quite a bit vis a vis implementing polymorphism. Having two separate and very different mechanisms does not lead to clarity.

16:16 hiredman: Chousuke: stub out a clojure.lang.LispReaderII based on your reader, AOT it, and then replace all refs to clojure.lang.LispReader with LispReaderII

16:17 Chousuke: hiredman: that's what I'm trying to do but so far I'm failing with all kinds of weird initializer errors

16:17 hiredman: :(

16:17 care to share?

16:17 Chousuke: not yet :P

16:18 hiredman: I have spent some time with LispReader

16:19 rhickey: cemerick: protocols will handle the vast majority of use cases and multimethods will be for more advanced cases. But making protocols more complex in order to encompass the set notion, which will be used even less frequently there than the multi- aspect, seems somewhat to defeat the purpose of optimizing the common case

16:20 i.e. if only 5% are multi and only 25% of them are subject to grouping...

16:21 you're down to a 1% case

16:21 cemerick: rhickey: yeah, I was actually suggesting that protocols be folded into multimethods as a fast-path implementation when, i.e. no dispatch fn is provided.

16:21 rhickey: but I'm open to concrete examples of multimethod sets that could map to the same dispatch value

16:21 cemerick: the perf is important, but the grouping is almost moreso

16:23 people come from OO and say 'where do I put my abstractions?' while Clojure is full of abstractions, all as host interfaces. Those interfaces map perfectly well to protocols. So protocols are an in-language alternative to host interfaces

16:24 It's a fair critique of Clojure that some of the things it needed in its implementation are not yet present in it

16:24 but multimethods can't compete with interfaces for perf

16:24 protocols might

16:25 hiredman: I wonder if defprotocols might be more clear then defprotocol

16:25 rhickey: hiredman: a protocol is a collection of sorts

16:26 spuz: lpetit: you there?

16:27 lpetit: spuz: he? how's behind this nickname please ? :)

16:27 still reading the intensive chats on the irc logs, because there has been a lot of things exchanged today !

16:28 hiredman: sure, but hten you could call the fn stubs defined in a defprotocols a protocol

16:28 spuz: lpetit: heh, um behind this nickname is spuz :p

16:28 gasc: what if, as cemerick suggests, you allow (defmulti ...) to define, with slightly different syntaxes, both dispatch function-based multimethods (slower) and type-based multimethods (faster). then you allow the grouping of multimethods with defprotocol or whatever. if all multimethods in a group are type-based then the group is optimized into a high-perf protocol, otherwise it's just a nice...

16:28 ...grouping construct for multis. could be that this doesn't work for reasons i'm not appreciating.

16:28 spuz: lpetit: I was bugging you about debugging a while ago

16:28 hiredman: gasc: what is a multimethod group?

16:29 lpetit: spuz: oh I remember now. Debugging has been bogued by too much work at work and too less work at home :-p

16:29 spuz: lpetit: heh, I know exactly what you mean ;)

16:30 the only solution is to convince work to move from java to Clojure :D

16:31 rhickey: gasc: I have a hard time seeing how multimethods + a grouping construct is going to be seen as anything other than a real pain for those coming from interfaces. And there are many subtle niceties to protocols, method maps, code reuse etc

16:32 spuz: anyway I was going to ask, do you know if it's possible to use the latest master versions of clojure and clojure-contrib with CCW? I've tried putting jars built from the latest check outs of those code branches but the plugin doesn't like them.

16:32 gasc: hiredman: well, maybe i have a bunch of multimethods that dispatch on :type metadata (or some other dynamic tag). since we're concerned with performance we don't want protocols to be able to dispatch on dynamic stuff like this, but maybe i don't care about perf for my application and want the equivalent of a protocol for multimethods.

16:32 rhickey: Of course I've just done a week of implementation design around method sets etc, so I'd have to reconsider grouping and where caches lived. But again, is this for a minority case? Right now protocols will be really simple for many

16:33 spuz: I get the error "java.lang.NoClassDefFoundError: clojure/contrib/repl_ln" I think because clojure-contrib.jar does not actually include an AOT compiled version of repl_ln...

16:34 lpetit: is there a special way you have to compile these jars in order for CCW to work with them?

16:34 rhickey: (defprotocol AProtocol existing-multimethod-a existing-multimethod-b)?

16:34 (implement AProtocol adispatchvalue amethodmap)?

16:35 plus defmultis for the methods?

16:35 lpetit: spuz: which jars are you talking about ?

16:35 spuz: lpetit: the latest versions of clojure.jar and clojure-contrib.jar as build by doing a check out of the git master repos

16:36 lpetit: spuz: I just take care of making clojure-contrib use the AOT compiled version of clojure, so that clojure-contrib itself is AOT compiled (so I carefully set the ${clojure.jar} (or something like that) in the build.xml of clojure-contrib

16:37 gasc: rhickey: are you saying that those usages are already possible under your current idea? or are you asking if that's what i'm thinking about?

16:37 spuz: lpetit: ok, perhaps the way the build works has been changed. I don't think the necessary .clj files are all AOT compiled

16:38 lpetit: spuz: if you want Eclipse to play well with debug on clojure.jar, you'll also have to place both src/clj/**/*.clj files and src/jvm/**/*.java files in a same clojure-src.zip and reference it as the source archive for clojure.jar

16:38 rhickey: gasc: I'm just stating it out loud so it is easier to see what the issues might be. Another set of issues is the relationship between multimethods and hierarchies. Right now protocols don't interact with hierarchies

16:38 lpetit: spuz: currently the clojure-src.jar file bundled by build.xml of clojure project doesn't do that, it just bundles the .java stuff, and does not include the .clj stuff

16:38 spuz: lpetit: I can try to tackle debugging later, first I need to actually run the code :0

16:39 lpetit: so just using the raw clojure.jar and clojure-contrib.jar should work, as far as I know

16:40 spuz: can you pastebin/lisppaste your .project and .classpath files contents ?

16:40 spuz: lpetit: ah, I think I can see the problem. See the changes Mr Hollaway has done to the contrib build.xml: http://github.com/richhickey/clojure-contrib/commit/04a22729691863a5b7e7b1b3c6c1157a02aff3b2

16:41 chouser: oh, protocols use only host class inheritence? I assumed they used the heirarchy.

16:43 lpetit: spuz: no time to test it, but can help think about it. What problem do you see ?

16:44 cemerick: chouser: I presume type and isa? are what limit multimethod perf.

16:44 hiredman: :(

16:45 spuz: When trying to run a program with the plugin: "java.lang.NoClassDefFoundError: clojure/contrib/repl_ln" I guess because the repl_ln.class file is never generated

16:46 hiredman: I know I said ok ealier, but hierarchies seem like another clojure name vs. java name issue

16:46 ngoc: Hi, if you know both Clojure and Scala, how do you "feel" about Scala? I have study a little Clojure and Scala, and I don't feel any happy with Scala. With Scala, I feel I'm talking some kind o primitive language. How about you?

16:46 hiredman: ~tell me about scala

16:46 clojurebot: {((x: Any, y: Any) => (f: Function2[Any, Any, Any]) => f(x, y))(1, 2)((x: Any, y: Any) => x)}

16:46 spuz: lpetit: by the way, where are the logs for this channel?

16:46 The-Kenny: ngoc: I listened to a small talk about scala at Froscon... the syntax just doesn't fit for a functional language.

16:47 (My opinion)

16:47 eevar: static typing is kindof neat. i'm shooting for haskell rather than scala, tho

16:47 s/is/looks

16:47 lpetit: spuz : n01se.net -> last item of the page

16:48 hiredman: ~logs

16:48 clojurebot: logs is http://clojure-log.n01se.net/

16:48 spuz: lpetit: thanks

16:49 gasc: rhickey: got it. i'm sketching it out now and, yes, i'm confusing myself even trying to understand what it would mean in concrete terms for a class/type to implement a protocol based on multimethods.

16:50 Chousuke: hm

16:50 hiredman: ~scala {((x: Any, y: Any) => (f: Function2[Any, Any, Any]) => f(x, y))(1, 2)((x: Any, y: Any) => x)}

16:50 clojurebot: Any = 1

16:53 ngoc: Scala makes me feel I'm a slave to machine. How do you feel?

16:57 chouser: should into-array support chunked seqs?

17:02 Chousuke: I can't figure this out :/

17:02 currently it explodes with "Var clojure.core/load is unbound"

17:03 chouser: trying to use clojure before there's enough clojure there to use?

17:03 hiredman: clojure/src/clj/clojure/core.clj:3910:(def load)

17:03 Chousuke: which presumably happens when I first try to use the reader class and it tries to init itself

17:04 hiredman: oh

17:04 :(

17:04 Chousuke: chouser: this is not in core.clj so I *should* have all of core available. except I don't because apparently it hasn't been loaded

17:05 hiredman: hmmmm

17:06 Chousuke: I managed to compile everything fine using a bootstrap jar but then recompilation attempts using the result from the bootstrap fails

17:07 attempt* :P

17:09 spuz: lpetit: Ah I've found I can disable the "Run in Repl" option and it works fine. Obviously this just requires clojure.main to run, not clojure.contrib.repl_ln.

17:10 lpetit: spuz: ok

17:13 Chousuke: hm.

17:13 lpetit: chouser: if I understand well, protocols would only be explicitly defined per 'implementation call type, no use of any type of hierarchy/host inheritence at all ?

17:15 serp_: in the typical program written in clojure, is it possible to at any time pause the execution and be given a repl to inspect the program's state?

17:16 chouser: surely not. if I have a bundle of fns that will all work for anything that implements APersistentMap, I don't need do multiple 'implements' for all the concrete sub-types.

17:16 lpetit: I hope, anyway.

17:16 lpetit: chouser: you're certainly right, it's getting late here and I'm getting confused :)

17:17 chouser: "call the supplied methods when an AClass is provided as the first argument" suggests anything that "isa?" AClass, which is why I assumed heirarchies were involved.

17:17 lpetit: :-) np -- clearly there's something here I don't understand yet as well.

17:18 rhickey: chouser: only class hierarchies, i.e. instance? not isa?

17:18 Chousuke: I think Clojure would need quite a lot of restructuring to make it possible to use my reader :(

17:18 chouser: serp_: I've not seen that, no. Generally Java debuggers are used, in which case the whole JVM is stopped and examined via interop.

17:18 Chousuke: I really don't want to figure out how loading the stuff works...

17:18 chouser: rhickey: ah, of course 'instance?' not 'isa?'. Clearly I'm also confused. :-)

17:19 rhickey: but there are significant complexities to multiple inheritance of implementation. I would completely avoid it if I could, but need to reach interfaces, which are multiply inheritable

17:19 serp_: chouser: ahh.. too bad

17:19 rhickey: I thought about just attaching to the abstract bases of the collections (pretty universally dervied from) but Iterable is the kicker

17:19 spuz: serp_: as far as I understand there is a single thread for the repl, if you want to use the repl at the same time as your code is executing then you need to run your code in a separate thread. See the 'future' macro

17:19 hiredman: Chousuke: you might see if you can find all the places lispreader is used and abstract it out so you can specify a different reader, that implements IReadLisp

17:20 somnium: hiredman: how many languages does clojurebot speak?

17:20 serp_: spuz: I'd be happy to pause the program while playing in the repl

17:20 hiredman: somnium: speak?

17:20 like evaluate?

17:21 rhickey: chouser: The possibility exists to reach the hierarchy system, which also opens up multiple implementation, but also has cache invalidation issues and other perf costs. Each layer adds more complexity

17:21 chouser: serp_: I have hope that someday somebody will make a clojure-aware JVM debugger, but I'm not aware of such a beast yet, or exactly how useful it would be.

17:21 spuz: serp_: well in theory you can use a debugger to pause the thread you're interested in, and continue to run the repl in another thread. You don't have to stop the entire JVM when debugging

17:21 Chousuke: hiredman: how would that help, though?

17:22 hiredman: it is a stepping stone

17:22 Chousuke: hiredman: how would it solve the loading problem?

17:22 serp_: spuz: mhm I see

17:22 Chousuke: I mean, there are only ~three places where Clojure calls LispReader

17:23 hiredman: you let clojure use LispReader until it gets to a certain point, then flip over

17:23 lpetit: rhickey: you asked earlier in the day for concrete examples for multiple arg dispatch for protocols

17:23 Chousuke: yeah but... the idea is to remove lispreader

17:23 at some point.

17:24 the problem is that when I load Compiler, it loads my ClojureReader (which has been properly compiled during the bootstrap process), which calls its load code... that explodes, because clojure.core is apparently not available :(

17:24 hiredman: well you can't completely remove it yet

17:24 rhickey: lpetit: yes, have you got some?

17:25 lpetit: rhickey: maybe close to :)

17:25 Chousuke: so I wonder, what do I need to do to make the ClojureReader load code use the clojure.core compiled during the bootstrap? :/

17:25 somnium: hiredman: yeah, evaluate

17:27 hiredman: somnium: just clojure really, it sends scala off to the simplyscala online repl thing

17:28 Chousuke: I'm really out of ideas with this. I suspect I'd have to mess with Compiler.java a bit more to get further but I don't really want to touch that code.

17:29 lpetit: rhickey: to speak with the design pattern "GoF" book terminology, I guess the Bridge DP, the Mediator DP are close to be examples of sets of methods that must be defined for couples (or sets) of types as a whole, and not just for a single type.

17:30 rhickey: to speak about what I know more, the Visitor Design Pattern, which requires just double dispatch on types (not open generalized multiple dispatch), could benefit from prototypes by grouping methods, too.

17:31 rhickey: so I'm not at all advocating in favor of prototypes as super-sets of multimethods, since you demonstrated that in the general case the semantics are hard (if at all) to define :), but allowing protocols to be defined on the types of more than the first argument may help evolve a design without having to rewrite everything too early with multimethods

17:32 rhickey: sketch of multprotocols added: http://www.assembla.com/wiki/show/clojure/Protocols

17:32 multiprotocols

17:33 Chousuke: ~def require

17:34 gasc: cool.

17:35 rhickey: the real weakness is the inability to confirm the dispatch fns all return the same dispatch value

17:35 but I'd rather move this way (from protocols towards multimethod capability) than to try to superimpose grouping over current multimethods

17:36 gasc: indeed

17:36 hiredman: I'd prefer for the distrinction between the two to remain clear

17:36 so it is easier to decide when to use each

17:36 rhickey: hiredman: oh great :) now convince cemerick

17:37 gasc: haha.

17:37 hiredman: :(

17:37 rhickey: the thing is, while these now look similar, under the hood they are very different

17:37 hiredman: exactly

17:38 rhickey: although still now have methodmaps, a useful capability vs multimethods

17:39 lpetit: the question remains : when a design evolves, is there a way were at a given step it may "cry" for evolving from protocols to multimethods, or multimethods to protocol, and how easy the move can be made

17:39 I don't have the answer :)

17:39 rhickey: it is a weakness of current defmethod that you can't just say (defmethod amulti aval some-existing-fn)

17:40 lpetit: I wonder what form that evolution might take? Maybe from class-dispatch to class-or-value, but I can't see from single to multi

17:41 dispatch fns + dispatch vals, while powerful, are definitely glaze-over material for many, while single dispatch on type is so easy to explain and by far most common

17:42 but they could have the same shape and different names, although defmultiprotocol is a mouthful

17:42 lpetit: rhickey: not sure about that, but from single to multi: you have a first implementation where you focused on a protocol for a single type, and you don't care about providing variants for other arguments. In the long run you want to evolve your library to be smarter on the 2d argument ...

17:43 rhickey: I understand the binary dispatch case well, but that was something I was considering giving special handling as well. Moving to arbitrary dispatch fn is the big (enabling and complicating) leap

17:44 lpetit: I just advocate for *considering* keeping the protocols as you defined them, with a clear meaning for the dispatch method being predefined (currently instance? is considered), but opening it to work on more than the first arg. Nothing more.

17:44 So we almost agree.

17:45 rhickey: lpetit: it is not just defaulted, it is hardwired and potentially removed internally

17:45 in other words, the protocols don't have a proper dispatch fn step

17:45 at present

17:46 unlikely to ever compete with interfaces if they did

17:46 lpetit: rhickey: Yes, when I wrote (currently), I was referring the the fact that you still are considering (or maybe not anymore ?) whether you add inheritence to types or hierarchies .. but I understand that the final version will hardwire the dispatch fn for protocols

17:48 rhickey: right, a separate issue is how far to reach for 'type' is it just (class x), or possibly a broader (type x) thing, where type becomes a first-class slot of Clojure data structures (or at least maps), like meta

17:50 lpetit: (implement AProtocol AClassForA AClassForB

17:50 {:foo an-existing-fn

17:50 :bar (fn [a b] ...)

17:50 :baz (fn ([a b]...) ([a b & c] ...)...)})

17:51 gasc: that seems like a toughy. on one hand it seems like capitulation to the world of hard-typing everything. on the other hand keeping it as (class x) intertwines it very tightly with java. i'll be interested to see where the decision goes.

17:51 lpetit: Not sure if the defprotocol itself should declare how many args the dispatch on 'type' would have to consider

17:53 (defprotocol #^{:dispatch-on-first 2} AProtocol

17:53 "A doc string for AProtocol abstraction"

17:53 (bar [a b] "bar docs")

17:53 (baz ([a b] [a b & c]) "baz docs"))

17:53 ?

17:55 rhickey: you then will have to reconcile deftype and hierarchies in some way ? People will suppose that all the "accessor" keys of a deftyped instance will work on a "subtype" (as defined per the existing hierarchy stuff) :-$

17:56 rhickey: that is they will consider that the set of "accessor" keys for a deftype define an implicit protocol for the type, hehe

18:01 rhickey: I considered many things, including implementing protocols on protocols. I remain wary of implementation inheritance, and especially multiple inheritance of implementation. That is why protocols are relatively hierarchy free. The way the methodmaps work gives you an easy way to reuse implementations without derivation or composition/wrapping

18:02 lpetit: rhickey: concerning 'how far to reach for 'type'': what types would (with-type {:a :foo} ::some-type}) match ? ::some-type ? IPersistentMap as well ? Map ? ArrayPersistentMap ?

18:02 rhickey: even with 'prefer' at the protocol level, it can get unwieldy quickly

18:02 lpetit: rhickey: indeed

18:03 rhickey: lpetit: if type slot is set, then it and its supers only

18:03 if not set, then class and its supers

18:04 but even looking at type slot could blow perf vs interfaces

18:04 lpetit: rhickey: but still it seems a bit unfair to only provide the 'instance? facility for host defined classes/interfaces, and not plain clojure stuff ... argh

18:05 rhickey: lpetit: deftype will be plain clojure stuff

18:05 lpetit: rhickey: Oh yes I missed something important, protocol is the "interface", no implementation inheritence (as in java), you're right

18:07 rhickey: really, if you had never seen Clojure multimethods, and came to Clojure finding deftype and protocols, you be substantially better off than you had been in Java IMO, for no more complexity

18:09 but I will think more about multiprotocols and dispatching. I have another set of ideas based upon per-arg dispatch, where single dispatch, but on say, broader type, could still be much more efficient than true pass-all-args-to-dispatch-fn, which is really quite opaque to the implementation

18:10 but current protocols are in a great place power/complexity-wise

18:11 lpetit: rhickey: just to speak about something totally different, have you noticed the questions of mwoelker on the ml concerning "side-effect free compilation" ? He did not have (so far) any concrete arguments pros or cons his idea. And since he is willing to help (ah, youth ! :-) ), and is very sympathic (already provided code to clojure-dev), I wondered he you would please either encourage or...

18:11 ...discourage him in this way by adding solid pros/cons arguments to the table, so that he does not spend too much time in a dead-end alley :-)

18:12 rhickey: lpetit: yes, I saw that and need to respond. Unfortunately the answer is, this will have to wait for cinc! Right now compilation is bound to reflection and that will have to change

18:12 It's part of a set of things I want to do to improve modularity and namespace issues

18:14 lpetit: rhickey: so maybe he is wasting his time right now. So bad, because he's really willing to help and has great understanding. And his questions are sometimes challenging to the clojure community, but always well asked, so he is an interesting specimen of people which may help improve to advocate clojure in some circles, if his questions are given argumented answers :)

18:19 maybe specimen was not the more appropriate term, no offense mwoelker if you're reading. I hope you get the idea :)

18:28 rhickey: to rephrase as an hypothetical java user what you said above, and to play a little bit the devil's advocate: "really, if I had never seen Clojure multimethods, and came to Clojure finding deftype and protocols, I would have first though "well, they redefined java interfaces as an internal clojure construct, minus the possibility to extend interfaces. Now they just have to rediscover...

18:28 ...that they can make types derive from types and they will have the full power of java regarding code reuse possibilities". Ouch!

18:28 I mean, they will come from an OO background, and it will not be evident *at all* for them that it is better to do it this way. *And* they will not see any immediate benefit from classic java interfaces (the power of being able to extend existing types with protocols will not occur to them immediately, after all well designed java code is coded towards interfaces, so it is in some way...

18:28 ...already possible to "extend" an existing java type with a new interface by making a decorator for it, as long as the rest of the code is coded towards the interface)

18:30 So this new functionality (deftype / defprotocol) may be a double-edged sword. From the outside, it may well resemble a : "look, they are rediscovering the basic java concepts in clojure. Soon they will reinvent java altogether". Sort of.

18:36 ok I will not spam the chat anymore, I'll go to bed, bye all :)

18:36 gasc: take care lpetit

18:42 serp_: ,(car '())

18:42 clojurebot: java.lang.Exception: Unable to resolve symbol: car in this context

18:42 serp_: ,(first '())

18:42 clojurebot: nil

18:43 serp_: ,(first (first '()))

18:43 clojurebot: nil

18:47 serp_: ,(rest '())

18:47 clojurebot: ()

18:55 serp_: how come first and rest on nil are valid operations?

18:57 The-Kenny: serp_: http://clojure.org/lisps "() is not the same as nil"

18:57 serp_: ,(first nil)

18:57 clojurebot: nil

18:58 serp_: why can I do that then?

18:59 The-Kenny: serp_: I don't know. It's mentioned in the doc for the functions. I'm not a designer of the language.. sorry.

18:59 somnium: serp_: for seqs to work I think its necessary (loop ... (if (nil? (first res)) res recur...)

18:59 to work as they do, rather

19:00 ,(rest nil)

19:00 clojurebot: ()

19:00 somnium: that does look a bit odd ;)

19:01 technomancy: ,(next nil)

19:01 clojurebot: nil

19:01 Chousuke: serp_: I guess the idea is that the first of nothing is nothing :)

19:01 serp_: I think the first of nothing should throw an error

19:01 and the rest of nothing as well

19:02 Chousuke: but that would complicate things.

19:02 danlei: very much

19:02 Chousuke: why throw errors when you can make it valid behaviour?

19:02 serp_: because the semantics are broken

19:02 Chousuke: not really.

19:03 nil is nothing. most operations on nothing result in nothing.

19:03 serp_: I don't see why one would say "nil is not a list" and then keep treating it like that

19:03 Chousuke: it's not a list. it's nothing. :)

19:03 (rest nil) results in () because rest always returns a lazy sequence and a lazy sequence made of nothing is of course empty.

19:04 danlei: nil is a spelling variation of nihil, which is latin for "nothing" btw.

19:04 serp_: ,(nth 3 nil)

19:04 clojurebot: java.lang.NullPointerException

19:05 Chousuke: it's got a lot to do with how seqs work

19:05 serp_: so why does that not work? surely one should be able to implement nth from a sequence of rest and first?

19:05 somnium: first or next on nil has to be falsey

19:05 Chousuke: ,(seq '())

19:05 clojurebot: nil

19:05 danlei: btw. (rest ()) used to be nil, too, so did (filter even? [1 3 5])

19:06 and I, for one, liked that

19:06 Chousuke: yeah, but it made fully lazy sequences impossible.

19:06 so nil punning had to go :(

19:06 danlei: then next became (seq (rest ...)), after the change

19:06 yes, I know

19:06 It's bearable to wrap in seq

19:07 not my first choice, but ok

19:11 anyway, throwing an error would likely be the least thing I want it to do

19:32 chouser: I can understand being in favor of more compile-time errors, but I like to have as few runtime error conditions as possible.

19:36 somnium: how do you type-hint (into-array Klass (set-of-klass-instances)) ?

19:37 ,(class (into-array Integer [1 2 3]))

19:37 clojurebot: [Ljava.lang.Integer;

19:38 AWizzArd: you could type-hint before doing a method call instead of hinting the array itself

19:38 somnium: AWizzArd: how do you mean?

19:38 AWizzArd: (.klassMethod #^Klass (nth 3 my-klaas-array))

19:39 where that call sits in a tight loop

19:39 somnium: right now its (.method #^Hint obj (?hint?) (into-array ...))

19:40 and still getting reflection warning

19:40 the whole array is an argument

19:41 defn: user> (index (rand-int (count vowels)) vowels)

19:41 How do I do something like that?

19:41 somnium: bah, its not important, one reflection call doesn't mean much on array 10,000 documents, just wondering how to do it

19:41 defn: I'm trying to get it to take the count of the (set "aeiou"), and select a random entry from it

19:41 serp_: ,(nth "abc" 1)

19:41 clojurebot: \b

19:42 defn: thanks serp_

19:42 serp_: np :>

19:44 defn: hmm, that doesnt work on something like: (def vowels (set "aeiou"))

19:44 serp_: a set is not ordererd

19:44 defn: oh duh, hence no indexes

19:45 is there a way to take a random element of a set

19:46 somnium: defn: sure, call seq on it

19:46 * defn oohs and ahhs

19:46 defn: thanks for your help :)

19:54 I'm trying to make a word generator thingy

19:54 hmmm - *thinks*

20:01 http://pastie.org/661381

20:01 Could someone take a look and try and figure out what I'm doing wrong :)

20:01 I'm trying to make a function which takes a number as an arg which says how many words to generate

20:02 and then it concats random letters we get from the two sets into 7 letter words

20:02 rhickey: arbscht and hiredman added to contributors - welcome!

20:03 arbscht: rhickey: thanks!

20:04 rhickey: a typo: Arbishek -> Abhishek :)

20:04 hiredman: clojurebot: contrib

20:04 clojurebot: contrib is http://github.com/richhickey/clojure-contrib/tree/master

20:05 durka42: defn: dotimes doesn't return anything

20:05 rhickey: arbscht: sorry about that - fixed!

20:05 hiredman: clojurebot: I'd rather you just gave me the git url

20:05 clojurebot: something

20:06 durka42: clojurebot: good answer

20:06 clojurebot: Titim gan éirí ort.

20:20 hiredman: http://www.thelastcitadel.com/images/contrib.svg

20:20 what a beast

20:21 crap

20:24 I sat down in the library and there is a book right in front of my on the shelf "the power of protocols"

20:36 Chousuke: defn: generating words is a job made for lazy seqs http://gist.github.com/213879

20:42 somnium: what is the "big picture" objective of deftype and defprotocol? some sort of non-imperative duck-type(ish) inheritance system?

20:43 or more like missing-parts for cinc?

20:44 been browsing the assembla wiki but I just can't see the forest

20:45 chouser: somnium: the motivation in cinc-related I think. That is, there are parts of clojure that can only be efficiently written in .java

20:52 somnium: chouser: thanks, it makes a bit more sense now.

21:48 seba: Hi, I have a question abount clojure.contrib.graph. Is this the right place? anyone can help?

21:49 chouser: you can ask

21:50 here or on the google group are your best bets.

21:51 seba: according to clojure.contrib.graph directed-graph is the basic representation, and is a NamedMap. :nodes is supposed to return a collection of the nodes

21:52 what if calculating the nodes is a non-trivial task ..... should I put that in a lazy collection? no other way to easily have a function to return the nodes?

21:52 What am I missing here?

21:53 for instance, if I keep the nodes in a map .... I would like to do (keys my_map) to get the nodes

21:53 how do I do that, without breaking (:nodes graph) interface ?

21:59 hiredman: there is an implementation of a lazy map somewhere, but {} is not lazy

22:00 seba: doesn't graph inferface place a hard constraint on implementations?

22:01 hiredman: I haven't looked at contrib.graph

22:02 seba: it's just algorithms plus a namedmap with members :nodes (a collection) and :neighbors (a function from node to neighbors)

22:03 hiredman: and what's the problem?

22:03 seba: if the algorithms used (graph :nodes) ... a graph could be a function, but they do (:nodes graph)

22:04 hiredman: hmmm

22:04 seba: so I guess a graph must be a map and only a map ....

22:05 hiredman: you could proxy whatever the bare interface keywords need for lookups

22:06 seba: how would you do that ? I'm new to clojure and don't see how

22:07 hiredman: ,(import 'clojure.lang.ILookup)

22:07 clojurebot: clojure.lang.ILookup

22:08 hiredman: ,(proxy [ILookup] (valAt [here] (name here)))

22:08 clojurebot: java.lang.IllegalStateException: Var null/null is unbound.

22:08 hiredman: ,(proxy [ILookup] [] (valAt [here] (name here)))

22:08 clojurebot: java.lang.IllegalStateException: Var null/null is unbound.

22:08 hiredman: bah

22:08 ,(:foo (proxy [ILookup] [] (valAt [here] (name here))))

22:08 clojurebot: java.lang.IllegalStateException: Var null/null is unbound.

22:09 hiredman: huh

22:09 I wonder what it's problem is

22:11 ,(:foo (proxy [ILookup] [] (valAt ([k] k) ([k v] k))))

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

22:11 hiredman: $%@#$%

22:11 seba: jeje

22:11 hiredman: it works here

22:11 seba: but I see ... I thinks thats exactly what I was looking for

22:12 it solves my problem ....

22:12 hiredman: also works in clojurebot's repl, just not from irc

22:12 clojure++

22:12 ~problem

22:12 clojurebot: People have a problem and think "Hey! I'll use a regular expression!". Now they have two problems....

22:12 hiredman: ~problem

22:12 clojurebot: People have a problem and think "Hey! I'll use a regular expression!". Now they have two problems....

22:12 hiredman: forget it

22:12 seba: jejeje

22:13 great, thanks ... will do that

22:13 hiredman: somewhere in there is something about layers of indirection

22:13 seba: good oportunity to learn proxy

22:13 hiredman: proxy is pretty useful

22:14 seba: where can you learn thinks like "keywords use ILookup". I guess only the code right ?

22:19 hiredman: yeah

22:19 well, that is how I just learned it

22:20 I looked at Keyword.java, then RT.java

22:22 actually, there is a nice picture somewhere

22:23 seba: I see

22:23 hiredman: http://github.com/Chouser/clojure-classes/blob/032beae497fddc426db05c7c6367c625a2dad04f/graph-w-legend.png

22:23 out of date, but I guess you could run the code and get an updated version

22:25 ILookup isn't even on there

22:26 seba: In fact, I was planning to use this to get pictures similar to that one

22:26 hiredman: hah

22:26 seba: I see a lot of people is doing this ... even you with your clojure-dependency-grapher

22:26 hiredman: :)

22:27 seba: I thought it was a good way to learn clojure ... and it is in fact.... of course I'm over engeniering things a bit, to know more libraries and stuff

22:28 great, thanks for your help

22:28 hiredman: I wasn't aware of contrib.graph

22:28 no problem

22:29 seba: I don't think graph has a good interface yet ... what I'll have to do seems a little smelly ....

22:29 but .. it will be good to use the algorithms to get cycle detection for instance

22:30 hiredman: I just sort of dump all that stuff on graphviz

22:30 seba: I do that too ... but I create an on memory graph first, to have the oportunity to apply the algorithms

22:31 of course, I'm seeing your code right now and is waaaaay cleaner than mine ....

22:31 hiredman: :P

22:31 seba: but ... I guess I'll improve with a little practice

22:32 get to know the API takes some time

22:32 hiredman: I would not recommend my code as a style guide

22:35 eyeris: I've installed the latest vimclojure. I've started ng-server. ng (the client) is in my path. Running :scriptnames in vim shows the vimclojure scripts loaded. However vimclojure still fails to bind any key sequences.

22:36 :messages doesn't show any errors.

22:41 chouser: I'm also fighting vimclojure

22:43 hiredman: :|

22:43 vimclojure's syntax highlighting and static completion + slime.vim

22:58 chouser: does slime.vim give you completion with arglists and such?

22:59 hiredman: nope

23:00 just sending code the repl

23:00 chouser: ok

23:01 eyeris: What is this b:vimclojure_namespace?

23:02 All of the vimclojure binds are wrapped in a 'if exists("b:vimclojure_namespace")'

23:02 But I have no idea how to determine whether that is evaluating to true or false

23:03 and no idea how to make that namespace exist

23:03 hiredman: b is a buffer

23:04 eyeris: So that is a buffer-local variable?

23:06 hiredman: .vim/autoload/vimclojure.vim:645:let b:vimclojure_namespace =

23:06 that is where it is set

23:06 eyeris: I see that now.

23:14 chouser: vimclojure is working!

23:17 eyeris: Congratulations

23:18 chouser: heh

23:18 hiredman: you say that now

23:18 chouser: except I thought it would omnicomplete arglists, and I don't see how to trigger it.

23:22 steiger: night everyone

23:29 eyeris: wtf

23:30 On ~/.vim/autoload/vimclojure.vim:652, b:vimclojure_namespace doesn't exist

23:30 yet it was just set on :646

23:30 or on :642

23:35 steiger: you're the first lispers ever to use vim to develop in lisp, no?

23:39 eyeris: steiger: there's a reason that lisp hasn't become a real player in the industry. I'm not saying that it's because emacs sucks, but emacs sucks.

23:39 :)

23:43 danlarkin: that is as misinformed as it is rude to us emacs users!

23:43 :)

23:44 steiger: very true, danlarkin

23:44 i don't mean to disrespect vim users, but, well, emacs *is* the standard way of editing lisp code ;)

23:44 eyeris: "we emacs users", I think

23:45 danlarkin: nobody likes a pedant :-p

23:47 technomancy: so there are some particularly onerous JVM libs that require the presence of a property file on the classpath before they can be loaded

23:47 this runs counter to the notion of runtime configuration

23:47 since you can't plop a properties file in a directory and add it to the classpath at runtime

23:47 hiredman: except for what is left of Chousuke's work, clojurebot is written in vim

23:48 technomancy: oddly enough, you *can* do this in JRuby; adding a directory to the load path is equivalent to adding it to the classpath, and loaded libraries respect it.

23:48 so what is Clojure missing that makes JRuby work?

23:48 I suspect JRuby uses a more heavily-modified classloader?

23:49 hiredman: I'm not sure, it might be an easy vs. correct split

23:49 (rhickey of course doing what is correct)

23:49 you could as headius about it next time he pops in

23:49 technomancy: I just might.

23:50 I suspect you could create a classloader that does the right thing and just use it to load a single class and its dependencies ... it wouldn't have to be used by clojure for loading all subsequent classes.

23:51 hiredman: I think there are visibility issues for code that interacts with that class

23:52 technomancy: probably JRuby can get away with it because it's much more insulated from raw java

23:53 hiredman: add-classpath actually works a significant amount of the time

23:54 but, uh, it breaks sometimes, and I don't know why, so I don't use it

23:56 technomancy: mostly I see breakage when interacting with JVM libs; it seems to work well for pure-clj stuff

23:57 hiredman: I've never used it for clojure stuff

Logging service provided by n01se.net