#clojure log - Jul 28 2008

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

1:47 mebaran151: if I have a function in the form of (fn [x] (+ x 1)) or something, is it possible to get its quoted form back

1:50 hoeck: mebaran151: please explain, do you mean its backquoted form or the functions source code?

1:51 mebaran151: I meant the src of function

1:51 what does the backquote do?

1:51 (I'm still learning Lisp)

1:52 shoover: a single quote could give you the code as a list: '(fn [x] (+ x 1))

1:52 hoeck: backquote and un-backquote are basically abbrevations for list and for eval

1:52 shoover: and if you put that into a variable with let, you could later eval it

1:53 hoeck: you could, but thats considered bad style

1:55 shoover: ok. I was thinking if you did need the code as a list and you also needed it to evaluate, that would be one way. Is there another way you're thinking of?

1:55 hoeck: mebaran151: instead of writing (list 'a b c 'd) you can write `(a ~b ~c d)

1:56 mebaran151: I just want to be able to get at the underlying src of a compiled of function just in case

1:56 I'm writing a little object persistence layer in clojure I've named Oscar, and this might come in handy

1:58 (Oscar searches creates and removes) or (Object store: creation and retrieval)

1:58 hoeck: shoover: i guess if you write something like a repl, this is okay

1:59 mebaran151: I'd basically like to quote an already eval'ed function, but maybe clojure throws away such minor points

1:59 hoeck: mebaran151: cool, i had the same idea, storing a functions source code (as string) in its metadata

2:00 mebaran151: the metadata is coming in very handy

2:00 shoover: Clojure emits the source as debugging information during compilation, but I'm not sure how you could access that.

2:00 mebaran151: it's where I keep all of oscars internal state

2:01 hoeck: then it would be nice to browse the source like in delphi or slime

2:01 mebaran151: yeah that could be nice

2:01 I thought lisp was all about that whole getting the syntax tree back

2:01 but I guess the tree has to be cut down at some point

2:02 shoover: The tree is available to you in macros, but once those are resolved to function calls, Clojure compiles everything down to Java classes.

2:03 mebaran151: I see

2:04 shoover: http://clojure.org/lisp goes into it a little bit

2:05 ... at least the part about how macros get to see the tree and transform it

2:06 mebaran151: I sort of get macros

2:06 shoover: That sort of makes 2 of us :)

2:08 mebaran151: so here's my idea for an object persistence store in lisp and I'm wondering if you guys have any feedback on the general idea of the design

2:09 my basic unit is the hash: I derive a database template from it, recursing to define nested templates under it

2:09 these templates define how I later run the insert statements and do joins and what not

2:10 I'm trying to make up for the fact I don't have classes to play with, so the next time I try to save an object, it looks in a central ref'ed var and attempts to match the hash given by its keys

2:14 shoover: What would one of these templates look like?

2:15 Also, are you talking about clojure HashMaps or computing a hash using some hash function?

2:17 hoeck: and what kind of objects do you store, clojure data-structures or any kind of (clojure) object?

2:19 mebaran151: I'm starting just with hashes

2:19 the templates are pretty simple

2:20 shoover: mebaran151: This sounds interesting, but I gotta run. I will be glad to check the log later to see the answers to these questions

2:20 mebaran151: just a list of mappings of functions to keys to attributes and relationships

2:20 where I'm stuck is modeling intra db relationships

2:21 (serializing and retrieving single use hashes is easy)

2:24 hoeck: mebaran151: what do you mean with 'hashes'?

2:24 mebaran151: I mean hashmaps

2:24 I started with ruby where they're called hashes

2:24 hoeck: ahh, okay

2:24 mebaran151: I'd like to eventually do any clojure object

2:25 the goal would be that I provide sane templates to get you started but a user could smack it around if they wanted via customizing the archetype I slyly stored in the metadata, which I have to admit, was an inspired invention

2:27 I always hated how rigid activerecord felt, but I Hibernate never had any dynamicness, and besides, neither project has as great a name as Oscar

2:29 hoeck: :) i've never used any (object) persistence system, so can you explain to me what are the templates for and how such a persistence system works??

2:31 i was always pretty satisfied with lisps loading their own code and data (at least in a small scale)

2:32 mebaran151: well I'm expecting a lot of objects on this scale

2:32 in this app

2:34 I basically am planning to allow designers to specify a template against which their objects will be persisted: within the template you would provide either symbols or functions which I would run over the hash and their results would be inputted properly in the database

2:35 (hash in this case meaning hashmap)

2:38 it would record which keys were of interest and whether to serialize them to the filesystem or to sql

2:40 hoeck: i see, have you any simple use-case for explanation to me?

2:40 mebaran151: well you have a lot of users

2:40 each has a profile per se

2:41 and can have a profile picture

2:41 you wouldn't want to put the profile picture in the database

2:41 so that's a simiple nested requirement

2:42 you should have a table for the flat information about users like his name and hashed password, andprobably have a separate table for profile data while keeping his jpg in a hash somewhere on the file system

2:43 hoeck: ahh, cool, i got it!

2:43 mebaran151: *jpg in a file somewhere on the file system

2:43 now let's get a bit more complex

2:44 users have profiles in whcih they can customize the fields, like add favorite soups or something

2:44 building a new column for that would be sort of silly, esp if only one user ever declared himself to have a favorite soup

2:44 so that part of the hash is probably best serialized to the file system

2:46 that's why I think a hybrid approach is best for a dynamic language like lisp where some objects might not look exactly like the rest

2:48 this profile might also be modeled as sequence of sections or something

2:48 hoeck: what is the non-hybrid approach?

2:48 mebaran151: just using SQL for everything

2:50 jykrd: hi

2:50 mebaran151: I'll be back in a moment

2:50 hoeck: jykrd: hi

2:52 jykrd: So I'm using (take n (repeatedly (fn [] (. (new BufferedReader (new InputStreamReader (. *param* getInputStream))) readLine))) to pull in lines

2:52 but I don't want to use take n

2:53 I want it to keep on taking values until it his a nil, and then stop

2:53 hoeck: then use (take-while identity ..)

2:54 jykrd: what does the identity part mean?

2:54 hoeck: identity is a function

2:54 (identity 1) -> 1

2:54 (identity nil) -> nil

2:54 jykrd: right, so basically take-while (not-returning-nill)

2:54 hoeck: and serves in take-while as a predicate

2:54 exactly

2:55 jykrd: oh, so actually write identity

2:56 hoeck: you could also write it more verbose (take-while (fn [element] (not (= nil element))) ...)

2:57 jykrd: right

2:57 identity sounds easier

2:58 I'm getting strange results here now

2:59 i do this to make processes:

2:59 (import '(java.io BufferedReader IOException InputStreamReader))

2:59 (defn $ [p] (.. Runtime getRuntime (exec (str p))))

2:59 then this to get input on it:

2:59 (defn $in [n obj]

2:59 (dorun (map println (take-while identity

2:59 (repeatedly (fn [] (.

2:59 (new BufferedReader (new InputStreamReader (.

2:59 obj getInputStream))) readLine)))))))

2:59 (sorry 'bout the flood)

3:00 and when I do a ($in 10 ($ "ps -ef")) I get strange results

3:00 doing it repeatedly returns different sections of the results

3:00 hoeck: you can use lisppaste for bigger code chunks

3:00 jykrd: rather than all of it, but perhaps the output has escape characters?

3:01 hoeck: i guess its because you create a new BufferedReader each time you request a line

3:02 jykrd: hmm

3:02 ok, so I could chop it into smaller functions

3:04 hoeck: or put the reader creation into a let

3:08 (let [r (new BufferedReader (new InputStreamReader ..))] (take-while identity (repeatedly #(.readline r))))

3:09 jykrd: yup

3:10 that works

3:10 good eye

3:11 so #() is short for (fn [] ())

3:12 hoeck: yes

3:12 jykrd: all this new syntax

3:12 hoeck: yes, kind of

3:13 jykrd: and .method

3:13 thats new to me

3:13 I remember it was talked about

3:13 hoeck: are you using svn or a release from the clojure site?

3:13 jykrd: site

3:14 but that all works

3:14 hoeck: in svn there is also (Object. ..) instead of (new Object ..)

3:14 i think its in the release too

3:18 jykrd: yea, that works here

3:19 so I've got it to do system commands.. so I might be able to do some system scripting clojure once I figure it out :)

3:23 what to make though.. maybe yet another backup tool

3:26 hoeck: jykrd: fetching clojure sources would be cool :)

3:27 jykrd: but on shell-level, it wouldn't be too portable

3:32 jykrd: hoeck: yea, I guess that's why there isn't much system scripting done with java or it's derivitives

3:34 hoeck: i'm going to work, bye

3:34 jykrd: later, thanks for the help

3:35 hoeck: np

3:38 jykrd: lisppaste*

3:38 lisppaste8

8:05 rhickey: jykrd: you might want to check out line-seq

8:17 jykrd: rhickey: ok

8:47 Yea, that's smoother

8:48 rhickey: find-doc is your friend - e.g. (find-doc "line")

8:50 jykrd: Why is is that, if i wrap the line-seq with a (map println(...)), then it puts a nil on the front of each line?

8:51 Chouser: jykrd: println returns nil, which the repl prints

8:51 rhickey: map is functional and lazy and println is a side effect. To get side-effects to happen you need some form of 'do' - (dorun (map ...

8:51 jykrd: oh

8:52 ohhoh

8:53 I never knew. That's been getting me for a while. That should go somewhere in the wiki.

8:53 rhickey: map returns a sequence of the values of the function you call, which as Chouser said, is nil in this case. You really don't care about those values, only about the side effects

10:05 cemerick: Chouser: I'm suddenly feeling very uneasy about the underscore name mangling

10:05 Chouser: really? why's that?

10:08 cemerick: It's a totally workable approach technically, but putting myself in the shoes of someone who doesn't necessarily know what gen-class is or how it works, it looks like a serious wart.

10:09 Chouser: hm. I have actually drifted the other direction. When actually looking at the example namespace I cobbled together, I thought the underscores looked quite nice.

10:09 cemerick: You'd like to be able to point someone at a namespace, and say, "here's the implementation of the same-named class", period. With this, the most common FAQ will be, "What's with all of the underscores?" "Oh, don't worry about that."

10:09 rhickey: When thinking about the namespace relationships last night, I thought perhaps ClassName-methodname might be best

10:09 Chouser: ...with the possible exception of underscores when calling the functions directly.

10:09 cemerick: rhickey: you mean a namespace per method?

10:11 rhickey: if you are gen-ing org.myns.Foo, under the Java rules the package is org.myns, and thus the Clojure namespace should be org.myns too. This would make it easy to gen and implement several fns in a single file

10:12 Chouser: hm!

10:13 several classes in a single file?

10:13 cemerick: rhickey: That's actually something like what I was thinking of over the weekend, except instead of ClassName-methodname, have a map of method names and fn's def-ed to each ClassName,

10:13 rhickey: so make a org/myns/myns.clj with Foo-doThis, Foo-doThat fns. org.myns.Bar could be defined in the same file, or have org/myns/myns load Foo.clj and Bar.clj is you want them separate

10:14 cemerick: using a map requires a special defing form

10:15 Chouser: Foo-doThis is still probably more terse than "public static final doThis"

10:16 cemerick: rhickey: Not sure I follow; wouldn't it be simply (def ClassFoo {:toString (fn [this] "blah")}), etc?

10:18 rhickey: cemerick: if you do that then redefining/testing single functions becomes ungainly, and you lose dynamic per-thread rebinding of methods

10:19 one of the cool things about gen-class is that Java classes inherit Clojure goodness, like that rebinding capability, or transactionality if state is a Ref

10:21 cemerick: I'd say that rebinding probably isn't a very common use-case in connection with gen-class impls -- and, if someone wanted to support that, it'd be a piece of cake to have the real impl of a function in a val (which can be rebound) that is invoked from within the class impl map.

10:22 rhickey: Java methods can also be multimethods

10:23 cemerick: true, it's hard to know what the use-cases are yet. Per-context logging is particularly useful

10:24 cemerick: sure, and the class impl map could dispatch to a multimethod elsewhere, too. My only point is that, right now, getting the simplest stuff done via gen-class requires just as much work/mental overhead/understanding of gen-class as the the most ambitious stuff.

10:25 rhickey: if these uses become common you'll have to write 2 functions, the second of which will have ad-hoc names

10:25 speaking of names, the anonymous fns in the map won't have useful ones during debugging

10:27 I guess it seems to me like you could have a (defimplementation ClassFoo .. that looks like what you want but generates real named fns

10:27 cemerick: via the ClassFoo-methodfoo naming pattern, you mean?

10:27 rhickey: right

10:29 all I see the map saving you is repeating the ClassFoo- prefix, at the cost of making the class definition atomic, and thus not very Clojure-like

10:29 cemerick: Yeah, that seems like it'd be OK.

10:30 Well, in the nexus of Java and Clojure (gen-class), I'm happy to sacrifice a little bit of clojure-ness in order to minimize the appearance of magic. Perhaps we can have our cake and eat it too, though.

10:32 Yeah, I'll +1 the ClassFoo-methodname notion, with the defimpl macro.

10:34 lisppaste8: rhickey pasted "method def options" at http://paste.lisp.org/display/64357

10:37 rhickey annotated #64357 with "defimpl" at http://paste.lisp.org/display/64357#1

10:40 rhickey: a nice thing about the defimpl macro is you needn't put everything in there, if you have a couple of multimethod methods you can define just them a la carte

10:40 hoeck: i would prefer the (defn Foo-doThis [] ..) form

10:40 rhickey: hoeck: me too, defimpl is optional

10:41 but I can understand its appeal

10:44 hoeck: maybe it is because of my long exposition to emacs-lisp, where usually function-names have a common beginning

10:58 Chouser: Could defimpl could be rolled into genclass?

10:59 rhickey: Chouser: I think it's important to remember the dual static/dynamic nature of genclass.

10:59 Chouser: I guess it would then have to do namespace magic as well, but you'd get something that feels more like a "normal" class definition.

10:59 rhickey: or do you mean put the macro into genclass.clj?

10:59 Chouser: no, you understood me.

10:59 rhickey: Chouser: normal class definitions suck, as they are static

11:00 Chouser: I understand, but it would actually be normal, just give the illusion. If that's something you're specifically trying to avoid, then so be it.

11:00 s/would actually/wouldn't actually/

11:01 rhickey: I think it would be a shame if you had to rebuild your Java when you changed your Clojure implementation code

11:01 maybe others disagree

11:02 I like generating a servlet stub once and forgetting about Java

11:02 Chouser: yes, I agree. Well, that is I'm entirely willing to agree. I'm not arguing against that, as you could still use the (def Foo-doThis) form for rebinding.

11:02 ah, nevermind, I see what you're saying.

11:02 * Chouser drops it.

11:03 * Chouser picks it up for just a second longer...

11:03 Chouser: there's a usage style difference here between gen-and-save-class and gen-and-load-class.

11:04 For the -load- case, I wouldn't at all mind having the definitions optionally embedded in the gen-class statement.

11:04 rhickey: gen-and-load-class has such marginal utility, IMO

11:05 Chouser: In fact it's be nice to not have to switch around namespaces and such. Dynamic re-binding would still be supported, but having the "canonical" version of your implementation in your gen-class statement wouldn't hurt anything.

11:05 rhickey: most of the time you genclass it's because some Java code needs to know the names

11:06 Chouser: with gen-and-save-class it makes a lot of sense to have it in a separate -gen.clj file that you very much leave alone, and would want any implementation inside.

11:06 cemerick: we use gen-and-load-class specifically to make it possible to at least co-locate the gen-class definition near the impl

11:07 (see the save-gen-class macro in my genbean post from Friday)

11:07 rhickey: what I foresaw, which may not have come to pass, was that gen-class wouldn't normally be enumerating the members, given that they come from superclasses or interfaces

11:08 (gen-and-save-class FooServlet :extends HttpServlet)

11:08 Chouser: when a gen-interface exists, that may become more true.

11:08 rhickey: why would I want to stick method defs in that?

11:09 Chouser: hm, it looks like my one real-world use of gen-class is a gen-and-load-class that could probably now be replaced with proxy, since super-calls are now supported there.

11:10 Maybe my experiences are much help in this conversation. :-)

11:10 aren't

11:10 sheesh

11:10 cemerick: rhickey: well, you'd certainly want to add methods to class definition -- not in a HttpServlet context, but elsewhere, that's very desirable

11:10 whether the impl defs are inline with the gen-class is another story

11:12 rhickey: cemerick: I understand that when they are not inline, you have to repeat the method names, like in c++ headers/source

11:12 cemerick: rhickey: very tangentially to this conversation, I'd urge you to not over-focus on the web development use-cases. I don't think you have to date, but how to hook into a servlet container is a very narrow context.

11:13 rhickey: cemerick: I'm not, enclojure is the biggest consumer of genclass from my perspective - many of the features, including adding members, came from their use cases

11:15 cemerick: Name repetition sucks, but dislocation of source code sucks more. That's why we have save-gen-class, and that's also why I'm sure I'll be writing something similar so one form can utilize defimpl and spin off a gen-and-save-class class at build time.

11:15 rhickey: OTOH, having done C++/Java/C# for 20 years, I often miss headers when in C#/Java, especially from a build dependency standpoint. Thus I'd emphasize interfaces whenever adding member so you get decoupling from implementation changes

11:16 cemerick: agreed, but they are 2 different things. save-gen-class doesn't need the impls inline

11:17 cemerick: rhickey: true, but that's only the case because of how gen-class works. All of our gen-class usages at the moment are 100% static, so I'd be perfectly happy dropping impls into it.

11:17 I'd emphasize "at the moment" :-)

11:18 rhickey: ok, let me think about it

11:18 cemerick: FWIW, that's very, very low on my personal wish list. Nailing down the namespace/lib/gen-class-naming issues within the current architecture is far more important, IMO.

11:22 rhickey: cemerick: I think the org.myns.Foo -> org/myns/myns.clj with Foo-doThis, Foo-doThat conforms to the new system, and Steve seems to be moving along with lib

11:23 just need to do the genclass changes

11:24 cemerick: rhickey: Sounds good, thanks. I've not kept up with Steve's progress in svn, though; been distracted elsewhere.

11:25 we're still holding at r937 until that's stabilized

11:25 Chouser: genclass's arguments would remain unchanged, right? Just the namespace name and function names would change?

11:28 rhickey: Chouser: right. I'm thinking now the file name should still org/myns/Foo.clj, but the code in it will be in org.myns. This way you can still get per-class load-on-demand

11:29 Chouser: I think you can just change your patch from _ to ClassName-

11:29 Chouser: you want to do the changes this time, or do you want to wait again for me to fumble my way through?

11:29 ah. I'll try it.

11:30 cemerick: rhickey: would it be bad for the load-on-demand to load /org/myns/myns.clj and /org/myns/Foo.clj? Having both options work automatically would be a plus, I think.

11:30 rhickey: I'm finishing up multimethod dispatch-value preferences

11:31 cemerick: what happens when you genclass multiple classes in the same ns, independently?

11:32 would load myns.clj more than once

11:32 cemerick: rhickey: ah, I'm presuming that lib is available

11:33 rhickey: cemerick: yes, lib will be rolled into Clojure soon, then genclass will use it

11:34 cemerick: nifty

11:50 Chouser: huh. The class doesn't exist yet, so I can't ask it for its simpleName. I guess I'll just chop off everything thru the last "."

11:50 rhickey: Chouser: right

12:02 Chouser: rhickey: as a general rule, do you prefer diff/patch files, or whole replacement files?

12:04 rhickey: Chouser: diff files as attachments are best

12:04 Chouser: ok

12:05 cemerick: (def a (new java.util.ArrayList<String>)) => error; is there a different incantation for referring to parameterized classes, or is this not yet supported?

12:05 Chouser: no need to provide the param class

12:05 (java.util.ArrayList.)

12:06 cemerick: right, no reification

12:07 I've been targeting 1.4 forever; I need to adjust my expectations :-P

12:18 Chouser: http://n01se.net/paste/cIN?pretty=no -- genclass-classname.patch

12:23 example usage: http://n01se.net/paste/9g3J

12:59 rhickey: Chouser: cool, thanks! I don't understand:

12:59 ; the follow would fail because when we have a namespace and class

12:59 ; named the same, the "/" syntax is ambiguous?

12:59 ;(prn (net.n01se.TestObj/makeone 9))

12:59 Chouser: oh, those are left over from the last patch. I haven't tested them with this one.

13:00 indeed, that works now.

13:01 rhickey: could you please post patch to group, with diff as attachment? (can't take contribs from pastes) - thanks

13:01 Chouser: sure, just a sec.

13:12 sent

13:15 It's interesting that this removes the class/method vs. namespace/function ambiguity.

13:15 rhickey: yes

13:15 Chouser: since now its package/simpleclass-function for the latter case.

13:29 rhickey: Chouser: patch applied, thanks

13:30 Chouser: of course just as you said that I was realizing I failed to update the doc string.

13:31 rhickey: ah

13:37 Chouser: would you prefer to have your existing test code in (comment) at the end? or mine, or nothing?

13:38 rhickey: something that works would be good :) mine doesn't

13:47 Chouser: well, I posted a patch to be applied on top of the old one. Of course feel free to edit to your preference.

13:53 rhickey: Chouser: that's up, thanks again

13:53 Chouser: sure, sorry for the stutter. :-)

13:53 * rhickey just gets patches and eats ice cream now

13:53 rhickey: :)

13:55 Chouser: sounds like a good life

13:57 rhickey: actually, the multimethod enhancements are huge, once people figure out what they can do with them

13:59 Chouser: I believe you. It's fascinating to me how many things are (apparently) lumped into the OO class and hierarchy model that I had never conciously separated.

13:59 Clojure seems to be aggressively deconstructing OO.

13:59 rhickey: :)

14:00 CL's generic functions were an eye opener for me, after so many years of the C++ system

14:00 Chouser: why should the namespace be a class? why should the class of the first argument be the only dispatch criteria? Why should the heirarchy control inheritence?

14:02 I worked for a couple year in a C++ codebase that had custom-built a sort of runtime-resolved two-argument multi-method system. The implementation was unimpressive, but the idea fascinated me.

14:02 So when I read onlisp, I was ready for CLOS. I still haven't used it (or Clojure multimethods) yet.

14:03 rhickey: Now I think objects are a trivialization that is holding us back, and many new languages are content to stick with the same-old worldview

14:04 Chouser: But anyway, this is a good system. If having folks writing two-line patches to genclass or architecting lib.clj frees you up to keep thinking through the tricky stuff, then we all win.

14:04 rhickey: Greenspun's 10th is true, once the systems get large you need the flexibility of Lisp, and end up implementing it ad-hoc

14:05 Chouser: I don't know how it'll help you feed your family though. I hope they all like ice cream.

14:06 * Chouser uses GMapEZ donations to rent movies and support more worthy free software projects.

14:06 * rhickey working around lack of Clojure in a C++ Report article 14 years ago: http://www.tutok.sk/fastgl/callback.html

14:06 rhickey: Chouser: thanks

14:08 Chouser: Qt is sort of an attempt to fix some of the problems metnioned in that paper.

14:09 rhickey: Yes, RougueWave, boost et al all moved the idea forward in subsequent years

14:10 Chouser: But it's amazing the amount of work they've done to implement signals/slots in C++. A somewhat naive implementation in a dynamic language like JavaScript took only a couple dozen lines.

14:11 rhickey: Chouser: exactly

14:59 kotarak: is it possible to assign doc strings to multimethods?

15:04 Chouser: (defmulti #^{:doc "foo does foo stuff"} foo identity)

15:05 kotarak: But what, when the docs actually depend on the defmethod part?

15:05 Chouser: ah. hm.

15:06 How would you look up the doc on a defmethod?

15:06 rhickey: kotarak: there should be a generic way to describe what a multimethod does. A multimethod is an open set, so it better represent an abstraction of some sort. Individual methods should all be implementations of that abstraction.

15:07 i.e. the same way you can read the docs for an interface and use it

15:07 kotarak: I thought about something like: (defmulti foo) (defmethod foo :a "bla" ...) (defmethod foo :b "blub" ...) (doc foo) -> ":a:\n bla\n:b:\n blub"...

15:09 rhickey: the problem comes from my monad adventures. There you have a bind function, which takes a monad and a function which does something to the monad returning another monad. But how this is actually established depends on the actual monad.

15:10 But maybe I should do it differently.

15:10 Just because this is done like that in Haskell, it's not necessarily a good idea to do it like that in Clojure.

15:11 rhickey: a user of a multimethod needs for there to be a single logical abstraction behind it - they shouldn't need to know or care what the methods are

15:14 ericthorsen: chouser: Sorry to have to ask...but where are the archives of this chat room?

15:15 Chouser: not a problem: http://clojure-log.n01se.net/

15:17 rhickey: That should probably go in the login banner on the IRC - logged at: ...

15:17 ericthorsen: thx

18:51 shoover: Along the lines of lisp features and thinking differently than mainstream languages, I'm curious if there's any interest in a CL-like condition/restart system to allow error handling directives to be established at a higher level without unwinding the stack.

18:51 I know at times my C# methods get bloated in order to wrap all the error situations (or I have to pass additional arguments down the stack). Is it too complicated, too slow, does anyone need it?

18:52 slava: shoover: restarts are very handy and lead to a whole new way of thinking about error handling

18:57 shoover: slava: It definitely seems that way. On the other hand, with CL's handler-case, handler-bind, restart-case, invoke-restart, and unwind-protect, there's more to get the mind around than good old try/catch. I'm wondering if those who have used restarts find them that useful in practice.

18:57 slava: I do

18:57 I wouldn't want to do serious programming in a language without them.

18:58 shoover: Wow, that's a strong statement. You must not use a lot of languages for serious programming!

19:05 rhickey: The recommended pattern for Clojure is to dynamically bind a handler fn at a higher level - the lower level code can call it in order to get alternative values etc, the handler can possibly handle, or throw if no alternative

19:06 one way to look at the CL condition system is as a special purpose set of dynamic functions in a language that otherwise doesn't have them

19:07 dynamic functions + exceptions let you build whatever you want

19:07 slava: the real benefit of having conditions comes when they're actually used pervasively by the standard library

19:09 rhickey: maybe, I don't know that there is enough evidence to support that, and that conditions are needed to supply those benefits

19:10 any high/low level coordination has to be pretty carefully orchestrated, I think it is more likely to work when you own both levels

19:20 shoover: rhickey: Interesting, thanks. I'll chew on this. All else aside, binding a dynamic function is easier to remember how to use.

19:40 Of course, now that you mention it it comes flooding back that dynamic vars were made for this context. If someone wanted the handler-bind, invoke-restart terminology I think it could be built on binding and find-var

19:43 rhickey: shoover: right, and defns end up in vars already, so no find needed. A fn need only say: if I get stuck I'm going to call handle-unparseable-input if it is bound, and use its return if not nil, and ignore if nil.

19:45 Chouser: gen-interface would really be gen-and-save-interface and gen-and-load-interface?

19:45 or "would also have" I guess.

19:47 rhickey: Chouser: I'm trying to imagine a scenario for gen-and-load, who could be the consumer of such an interface?

19:47 but generally, yes, a code generator and then helpers that use the code, like gen-class

19:48 Chouser: gen-and-load still creates the named class, just not the class file. So any combination of proxy and gen-and-load-class could use it.

19:49 rhickey: Chouser: I guess more generally, if you proxied/loaded an interface you just made up, who could use it?

19:50 the logic for gen-and-load-class was that other Clojure code could new instances by name

19:50 interfaces are contracts between independent pieces of code

20:33 Chouser: does gen-interface need to supported nested types?

20:33 I assume it should at least support constants.

20:52 rhickey: Chouser: no, interface constants are not something I want to support, nor nested

21:53 hashendgame: I'm trying to write a def- macro that is identical to def, but adds :private true to the metadata (similar, I think, to defn- vs defn). My best attempt is at http://pastebin.ca/1085831 , but (def- woot 3) gives me a "second arg to def must be a Symbol" error.

21:56 Chouser: I think you want the with-meta to happen when your macro is called, rather than being put into the expansion.

21:56 did you look at how defn- is defined in boot.clj?

22:00 hashendgame: I am now. Looks like the with-meta gets evaluated at call time.

22:04 http://pastebin.ca/1085839 has a working version, for those interested.

22:05 thanks Chouser

22:05 Chouser: sure, glad you got it working.

22:35 using real classes and getInternalName for :extends means all your interface classes must be *loaded* before you can gen your derived class?

22:39 rhickey: It seems so

23:21 Chouser: but by using a real classes you can take advantage of imported class names.

Logging service provided by n01se.net