#clojure log - Jul 25 2008

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

3:12 meredydd: Chouser: A-ha.

3:12 Chouser: I had no idea what you were talking about, until I grepped the API document for ":state"

3:13 and realised that what I thought was part of the paragraph about factory methods was in fact a description of another option.

8:32 Hey...does the Java interop work with Java var-arg methods?

8:33 rhickey: there are no real var-arg methods in Java, they take arrays and, for now, to call them you have to pass arrays

8:34 meredydd: I'm aware that they're arrays behind the scenes

8:34 I take it there's no tag you can examine to see who is and who isn't a var-arg method?

8:36 rhickey: there is, the problem is that Java uses types to detect the difference between passing an array (to match the array arg) and passing a non-array (which Java will turn into an array auto-magically)

8:38 so it's (String/format "%d%d%d" (to-array [1 2 3])) for now

8:55 Chouser: probably warrants a mention on the java-interop page

9:02 cemerick: an impl of defbean (now called genbean) that I'm mostly happy with is finally done, along with a generalized approach for integrating it (and other gen-and-save-class usage) into a build process; hopefully, I'll get to writing it up for the group later today

9:03 rhickey: cemerick: cool, is there something you still wish you had for that?

9:04 cemerick: rhickey: not much, aside from the ability to define method impls in a gen-class body

9:05 I ended up ditching the proxy approach entirely because invoking the polymorphic "makeNew" function was way too cumbersome

9:07 a small thing would be to have a *verbose-gen-class* (or whatever) var that would println where gen-and-save-class is trying to save bytecode

9:09 lisppaste8: rhickey pasted "group-by partition-by" at http://paste.lisp.org/display/64190

9:10 cemerick: rhickey: oh, right the rumored, forthcoming name munging in gen-class would be *really* helpful in general

9:19 rhickey: Chouser: I think partition-by is a better name for what you were trying to do

9:20 the version I pasted call f once per item

9:30 Chouser: yeah, group-by sound enough like relation-speak that it's better working on sets or maps.

9:31 ok, very clever use of "identical?" on a lazy seq

9:34 f gets called one extra time on the first item of each partition, doesn't it? for fv?

9:35 rhickey: could be drop-while ... (rest s) I guess, to avoid that

9:36 Chouser: ah, yep.

9:37 lisppaste8: rhickey annotated #64190 with "partition-by with no redundant calls" at http://paste.lisp.org/display/64190#1

10:03 blackdog pasted "no matching field?" at http://paste.lisp.org/display/64193

10:04 blackdog: hi can someone tell me why i get a no matching field exception

10:04 please

10:05 rhickey: blackdog: Woot doesn't derive from anything that has an actionPerformed method. You can't add methods by just putting them in the Clojure side

10:05 blackdog: oh,

10:06 ok, i thought gen- classes were much more general than proxy,

10:07 rhickey: blackdog: they are, but you still have to make sure your methods are in the Java class itself, either by deriving or using the :methods argument to gen-class

10:08 Java class signatures are not dynamic

10:08 blackdog: is there any way then to create a new class with some methods totally in clojure?

10:09 i'm trying to attach some handlers to a gui designer, and it's looking for an object with actionPerformed methods

10:10 rhickey: the gen-class system partitions class definition into 2 parts - the part Java requires be static, i.e. the signature, and everything I can make dynamic (the implementation)

10:10 the gui designer is looking for an instance of java.awt.event.ActionListener, no?

10:11 blackdog: well. it

10:11 it's a runtime lib (jformdesigner) that reads xml descript

10:11 and then you simply say setTarget(handlerobject)

10:11 so i'm trying to setup the handler object

10:11 in clojure

10:12 the handler object is a pojo

10:12 with just the correct methods names

10:13 so i don't have anythign to derive from, but maybe i should investigate further the runtime api

10:13 it may have more,

10:13 rhickey: well, you can proxy ActionListener, gen-class ActionListener, or gen-class :methods ... actionPerformed ...

10:14 blackdog: ok, i'll go off and think about that, thanks rhickey

10:24 rhickey, gen-class :methods allows one to define the static part then?

10:25 rhickey: blackdog: everything in the gen-class defines the static part, but the :methods are just signatures. The definition still goes in the Clojure code as you had it

10:26 blackdog: but does the :methods get around having to derive or implement something - sorry for my denseness

10:27 rhickey: right, :methods are in addition to anything you get by deriving

10:27 blackdog: ok good, so that should work for me then

10:28 ha! lift-off

10:29 thanks!

10:29 rhickey: sure

14:58 cemerick: ach! why doesn't Google Groups support at least 80-column text? :-/

14:59 ach! why doesn't Google Groups support at least 80-column text? :-/

15:00 rhickey: cemerick: yeah, if you have something substantial, you can attach it

15:01 cemerick: rhickey: where? I don't see any way to attach a file to a post. Or, do you mean upload it to the files section of the group?

15:01 Chouser: you may need to post via email, and attach to your email

15:01 rhickey: what he said

15:02 cemerick: ah. I should have done that.

15:03 rhickey: cemerick: you can still

15:04 cemerick: Yeah, I suppose I'll repost. It'll create a new thread, though, yes?

15:04 rhickey: or you can follow up to your original message with a short note and the attached file

15:05 * rhickey is still reading your post

15:07 cemerick: ah, I'll delete the original and send an email

15:13 much better

15:22 rhickey: cemerick: a couple of thoughts, using the current ns as a name is very troubling - I know that's on me to provide defs of qualified names

15:22 as far as get/set, setProperty is a problem - while it would be familiar looking, it won't be familiar behaving, as it doesn't modify the object in place.

15:26 anyone want to take a crack at gen-interface? should be really easy, learn a little bytecode gen?

15:30 cemerick: rhickey: using the current namespace for the method impls and classname certainly isn't "hygenic", but that's what the typical usage would be anyway

15:31 I don't mind at all having a setProperty that returns a new Foo, rather than having mutable semantics. That might freak out some Java/.NET people, but that's better than having broken equals semantics.

15:31 Chouser: gen-interface would take a single class, no options, and do the minimal gen-class equivalent for it?

15:31 rhickey: Chouser: no, allow the definition of an interface from scratch, just signatures

15:31 Chouser: I was thinking I might poke at gen-class function name mangling if nobody beat me to it.

15:32 ah.

15:34 rhickey: Chouser: if '.' prefix is too clever, what about '-' ?

15:35 other genclassers please chime in

15:35 Chouser: I was thinking I'd do something lengthy (and internally configurable), and just provide a def-gen-method to match the same mangling.

15:36 cemerick: we're talking about mangling names so as to avoid the name clashes with referred namespaces?

15:36 rhickey: cemerick: yup

15:36 Chouser: at least that would could be done now safely, and allow any code written using it to be forward compatible with any more minimal mangle that might be chosen later.

15:36 s/would//

15:37 cemerick: I'd definitely avoid '.' as a prefix. A '-' prefix would be a 99% solution, certainly.

15:37 rhickey: the problem with a mangle hidden by a special def is - how do you call/test it? It's still a normal function

15:37 Chouser: i'd be worried (defn -foo) looks a lot like (defn- foo)

15:39 you might need to have "this" bound when you call it manually, right? there aren't any other special rules?

15:39 rhickey: maybe, but both are implementation details, editor coloring clears up pretty well

15:39 cemerick: I've always liked the python convention of a double-underscore *shrug*

15:39 rhickey: Chouser: yes this, no, they are regular fns

15:39 cemerick: Lisp uses - instead --method would be ok too

15:39 Chouser: but you could test by creating an instace of the class and calling them as methods -- that would get "this" right, and follow any mangling.

15:40 python uses double-underscore surround the name, which makes it hard to say aloud: __foo__

15:40 cemerick: rhickey: yeah, I was just replying to Chouser's concern about a prefixed '-' appearing too similar to defn-

15:40 Chouser: I guess "dash dash foo dash dash" is a bit better.

15:40 rhickey: as methods they are less powerful than fns, not first-class

15:40 can't map etc

15:41 Chouser: we have to stay off the end, already used for types

15:41 Chouser: ah, right. ok, so dump def-gen-method, and we'll just finish this mangling detail discussion right now. :-)

15:41 cemerick: Chouser: actually, "private" names in python usually have double-underscore only in front of the name -- that's what triggers name mangling

15:41 Chouser: cemerick: oh! ok.

15:42 I'm fine with a -- prefix. *shrug*

15:42 or a .. prefix, or #! or whatever. ;-)

15:43 cemerick: yeah, I really don't think it matters, outside of not using '.'. :-)

15:45 actually, '-' sorts ahead of most other chars, which would be unfortunate for tools, etc.

15:46 rhickey: another potential issue with -- is it get munged to __, which is a name component I presume the Clojure implementation "owns"

15:46 Chouser: we don't really want anything starting with # since that triggers reader magic, right?

15:46 cemerick: pipes would work, and they sort after all other ascii chars; not so pretty, tho

15:46 rhickey: Chouser: right!

15:46 Chouser: * mean "global"

15:46 % is already taken

15:47 rhickey: I'm reserving all other special chars

15:47 Chouser: @ and ~ are already taken pretty globally as well, right?

15:47 oh. so it has to be -, ., or alphanumeric?

15:47 rhickey: this isn't worth a special character

15:48 Chouser: and since I think a prefix makes a lot of sense (compared to a postfix), it's really just alpha.

15:48 -- is apparently dangerous, so either just "-" or something like "method-" or "gen-"

15:49 cemerick: well, these names aren't going to be accessed with any kind of regularity, right?

15:49 Chouser: the only other requirement being that it is very unlikely for a Java class to use in a normal method name.

15:49 cemerick: (by non-generated code, I mean)

15:49 rhickey: I'm not sure sorting first is bad, when looking at a ns dedicated to a class implementation, the methods will sort first

15:53 Chouser: any kind of prefix will have them sorted together. Having them first seems a little nicer than having a bunch of "method-*" between your "loo" and your "noo" functions.

15:53 rhickey: cemerick: right, the names might only rarely be used

15:54 Chouser: "-m-" prefix

15:54 cemerick: Chouser: +1

15:54 Chouser: that would sort first, stand out more than just "-", suggests a method without being verbose

15:55 and if that gets mangled to "_m_" I think we've avoided better than 99.9% of Java method names.

15:56 rhickey: Chouser: the only conflict with - is if a class defined public foo and _foo, even then, one becomes _foo and the other __foo

15:57 alpha prefixes dramatically reduce readability imo, - disappears, but m doesn't

15:58 Chouser: I agree - is technically sufficient, I'm just not convinced the difference between (defn- foo) and (defn -foo) is unmistakable.

15:58 hm.

15:59 rhickey: in my editor defn- foo is all black and defn -foo is purple/blue

16:00 * rhickey prefers -

16:02 rhickey: ericthor: any thoughts if you are there? (enclojure might have more genclass than anyone)

16:07 or we could use _, to remind us we're in Java-land

16:07 (defn- foo (den _foo

16:08 (defn- foo (defn _foo

16:17 Chouser: works for me, but either is fine.

16:17 * rhickey now prefers _

16:18 rhickey: on an unrelated note: (derive java.util.Collection `aggregate) will work

16:19 i.e. superimpose your own taxonomy on existing classes

16:40 mebaran151__: is there a good way to get an arbitrary hash for an arbitrary object that would ensure uniqueness on value: I'd like to use this string representation for a primary key functionality in an app i'm writing

16:42 Chouser: sounds like you want sha1 or md5

16:51 mebaran151__: for like a whole map though?

16:52 like I'd like to be able to just take a random hashmap I created in clojure and run a function on it to return a string

16:52 that would be unique over the values of that hash

16:52 internally, that must be how clojure handles equality I would think

16:55 Chouser: whole maps have a hash value, but there's no guarantee they're unique -- when placed in a map or set a value comparison needs to be done to make sure you've really got the right item

16:55 I think. That's normal for hashes, though.

16:56 For equality you can use "identical?", but that'll give you false negatives. To be sure, I think the whole collection is compared.

16:58 mebaran151: yeah

16:58 Chouser: so if you want a guaranteed-unique hash, I think you'd have to use md5 or sha1 on the whole value.

16:59 mebaran151: it's a cool little project: trying to layer a fs db written in clojure

16:59 I might just go with my old idea of incrementing a string

16:59 Chouser: If the value is made up of just well-printable clojure objects, you could print to a string and run sha1 on it.

17:00 mebaran151: oh that's actually decent idea

17:00 yes

17:00 most of the objects will be well printable

17:00 I'm actually planning on internally bucketing the objects via their printed forms anyway

17:19 Chouser: woo! I've been stabbing in the dark, and finally hit my target. Now I just have to understand it...

17:20 rhickey: Chouser: what target?

17:20 Chouser: prepending a - on function names but not method names. ;-)

17:20 It's taken me, what, an hour? It would have taken you 15 seconds.

17:21 I'm trying to find where we discussed before which names you wanted mangled and which you wanted to leave alone.

17:21 rhickey: Chouser: ah, yeah, it's a bit thick in there

17:21 Chouser: heh. yeah. But I don't know a better way to learn it.

17:23 ah, here it is. "the names manually given to genclass would remain unmunged? :factory, :state, etc?"

17:25 rhickey: I don't know, seems like the same arguments might apply - these names are dictated by outside requirements and could just as easily bang into clojure names - prefixed with _ they never would

17:25 doing them all is probably way easier

17:26 Chouser: yeah. doing them all is (maybe?) done.

17:26 rhickey: cool!

17:26 Chouser: but not all the names are dictated -- init, state, etc.

17:26 rhickey: state is a field

17:27 Chouser: oh, "public". ok.

17:27 rhickey: I think it will be easiest for users too, to know the rule is clojure implementations of Java gen methods begin with _

17:28 ?

17:28 public?

17:28 Chouser: I knew :state was a field, but I didn't realize it was public.

17:28 rhickey: yes, public and final, so no getter/setter

17:30 Chouser: well, maybe I'm completely missing something (seems likely), but my change is to replace genclass line 276: (. gen push (str "_" v))

17:30 seems to work as expected.

17:31 perhaps I need to test ctors, factories, etc.

17:32 rhickey: what about the lookup side?

17:33 line 187?

17:35 blackdog: i'm trying to define a function defn as the body part of a macro

17:36 and then using that as part of gen-and-load-class

17:36 definition, but the function name has a _var appended

17:36 [['wootActionPerformed [ActionEvent] Object]]

17:37 Caused by: java.lang.ClassFormatError: Illegal field name "user/wootActionPerformed__var" in class igw/forms/Woot

17:37 is that just a dumb thjing for me to try?

17:38 rhickey: blackdog: want to paste your macroexpansion?

17:38 blackdog: oh, i'll try, haven't really used that

17:38 do i just stick macroexpand around the macro call?

17:39 rhickey: if you are having a macro problem, macroexpand is the first thing you should try, stick macroexpand around the *quoted* call

17:39 (macroexpand '(my-macro x y z))

17:39 blackdog: ok

17:40 rhickey: if your macro expands into another macro, try macroexpand-1 first

17:42 blackdog: is there a pretty print for a macro?

17:42 macroexpand?

17:42 rhickey: no pprint yet

17:42 blackdog: k

17:42 rhickey: emacs?

17:43 blackdog: no, i'm using jedit :(

17:44 lisppaste8: blackdog pasted "macroexpand" at http://paste.lisp.org/display/64223

17:45 blackdog: i don't see _var in the macroexpand

17:46 lisppaste8: blackdog pasted "stacktrace" at http://paste.lisp.org/display/64225

17:47 blackdog: the methods section in the macro itself is hard coded, would be replaced

17:48 rhickey: user/wootActionPerformed is not a valid method name, you have to generate an unqualified name

17:48 the __var is added by the implementation of gen-class, but is not the problem

17:50 blackdog: in the macro it tries to do (in-ns ~kls) to set the ns before doing the defn of wootActionPerformed

17:50 rhickey: that's not going to work

17:50 blackdog: ok,

17:52 because i;'m missing something fundamental or just that it's a daft thing to do?

17:54 rhickey: actually, I'm not sure what you are trying to do, but one trick is to fix your expansion by hand and see if it works before fixing the macro. Always start a macro with a by-hand implementation of the expansion that works, then tweak the macro until it expands to the same thing

17:55 blackdog: ok thanks for that,

17:55 rhickey: trying to get a macro and the expanded logic right at the same time is a recipe for pain

17:55 blackdog: ok

18:20 Chouser: rhickey: don't feel you need to walk me through this -- it'd probably be easier for you to just do it yourself. But if you want to answer my questions instead...

18:21 If I mangle line 187 my tests fail.

18:22 is it doing a lookup in the class there? I don't want to mangle that, of course.

18:48 rhickey: Chouser: I see - you are not changing the names of the static fields, just the var symbols - then you don't need line 187 changed

19:04 arohner: why can't I peek at a range?

19:04 user=> (peek (range 1 10))

19:04 (Peek (range 1 10))

19:04 java.lang.ClassCastException: clojure.lang.Range

19:04 java.lang.ClassCastException: clojure.lang.Range

19:04 at clojure.lang.RT.peek(RT.java:454)

19:04 at clojure.fns.clojure.peek__398.invoke(boot.clj:757)

19:04 at clojure.lang.AFn.applyToHelper(AFn.java:184)

19:06 user=> (peek '(1 2 3 4 5 6 7 8 9 10))

19:06 (peek '(1 2 3 4 5 6 7 8 9 10))

19:06 1

19:17 Chouser: peek is for lists, vectors, and queues. For generic seqs, you can just use first.

19:18 (first (range 1 10))

19:18 arohner: ok

19:18 what is the difference between a seq and a list?

19:19 Chouser: oh, apparently peek is defined on IPersistentStack, which is implemented by list, vector and queue.

19:19 arohner: that's a great question with a subtle answer.

19:20 arohner: yeah, I saw the IPersistentStack cast

19:20 that explained the stack trace, but didn't help me understand the issue :-)

19:20 Chouser: seq is an interface, specifically ISeq. Every ISeq provides "first" and "rest"

19:21 every collection in clojure can viewed through a seq. For example: (seq {:a 1, :b 2})

19:22 A list (PersistentList) is a concrete data structure, a singly-linked list. I happens to provide the ISeq interface itself directly, unlike most other collections.

19:23 user=> (def x (list 1 2 3))

19:23 user=> (identical? x (seq x))

19:23 true

19:23 user=> (def y {:a 1, :b 2})

19:23 user=> (identical? y (seq y))

19:23 false

19:24 arohner: ok, so the simple answer is that peek and pop are defined on things that have a stack interface

19:24 Chouser: right

19:28 arohner: thanks for the help

19:29 Chouser: np

19:51 mebaran151_: is it possible to join a lazy sequence to non-lazy sequence

19:53 I want to do something like join at the head of list (1 2 3) to an infinite sequence of 4's for instance

19:54 in the repl, lazy-cons produced the infinite sequence I didn't want it to do

19:55 Chouser: the repl will try to print all of a seq, lazy, infinite, or otherwise.

19:56 (take 10 (lazy-cat (list 1 2 3 4) (repeatedly #(identity 4))))

19:57 I'm not sure what the best way is to create an infinite seq of 4

19:57 (take 10 (lazy-cat (list 1 2 3 4) (cycle [4])))

19:58 ah!

19:58 (take 10 (lazy-cat (list 1 2 3 4) (repeat 4)))

20:26 arohner: is there a library call that gives me all of the permutations of two lists?

20:27 Chouser: aren't permutations usually figured from a single list?

20:27 arohner: I want to pass two lists (range 1 10) (range 1 10) and get a list of tuples (1 1) (1 2) ... (10 9) (10 10)

20:27 Chouser: ah. for

20:27 arohner: maybe I'm using the wrong term

20:27 slava: the cartesian product of two lists?

20:27 mebaran151_: thanks Chousefr

20:28 Chouser: (for [x (range 10) y (range 10)] [x y])

20:28 arohner: ah, thanks

20:28 mebaran151_: hey Chouser, how can I tell if my recursion is occurring in the tail position

20:28 arohner: if you use (recur) it will be in the tail position, or you get an exception

20:28 Chouser: if the compiler lets you use (recur), then it's tail position.

20:29 mebaran151_: I'm trying to call recur inside an if conditional but clojure continually complaines

20:29 Chouser: what he said.

20:29 slava: why is recur in non-tail position prihibted?

20:30 mebaran151_: (def next-id (fn this

20:30 ([id] this (this id *max*))

20:30 ([id max] (loop [i id m max]

20:30 (if (< (first i) (first m))

20:30 (conj (incr (first i)) (rest id))

20:30 (conj (base (first i))

20:30 (recur (rest i) (rest m))))))))

20:30 (sorry about the flood)

20:30 slava: mebaran151_: recr is not in tail position there because its result is passed to conj

20:30 mebaran151_: ah

20:30 slava: but i don't understand the limitation

20:30 arohner: because recur guarantees the stack size will not grow

20:30 mebaran151_: so how would I refactor this

20:31 slava: i'm not sure why you'd have recur at all

20:31 mebaran151_: well I'm recursively calling next-id

20:31 slava: so just call it explicitly i guess

20:31 mebaran151_: my id's are basically a seq of integers

20:31 that can be of arbitrary length

20:31 arohner: mebaran, you probably need a loop position inside your ([id max]) case

20:32 mebaran151_: it's there

20:32 arohner: oh, right

20:32 mebaran151_: maybe there's a better way about it using reduce in some fancy way

20:33 arohner: you can self-call without the recur as well, you just aren't guaranteed the stack size won't grow

20:33 mebaran151_: I'm trying to basically do carry addition

20:33 slava: so is recur just an assertion basically that has no effect on the compiled code?

20:33 how do you assert that a tail call to another function is a tail call?

20:33 arohner: no

20:34 the explanation I've heard is that the JVM doesn't have the opcodes to do a real tail call

20:34 recur only goes to designated places in your own function

20:34 a (loop), the top of the function, and a few other places

20:35 recur target is the term I'm looking for

20:35 slava: oh, right

20:35 the JVM can't tail call, I forgot about that

20:36 you can just do a goto within the current method

20:38 Chouser: slava: right, that's what recur does under the covers.

20:38 which is why it has to be in tail position.

20:39 arohner: so I have a for loop that looks like

20:39 (for [x (range 1000)

20:40 Chouser: "on lisp" has a section which is where I learned how to move recursion to tail position.

20:40 arohner: (for [x (range 1000)

20:40 y (range 1000)]

20:40 (if foo (print "foo") nil))

20:40 when I evaluate that, the screen is filled with prints to nil

20:41 is there a way to not print all the nils?

20:41 Chouser: mebaran151_: instead of returning your accumulating value, pass it forward to the next recursive call, and finally return the whole thing at the end.

20:42 mebaran151_: I'm doing something similar with reduce right now

20:42 slava: that's something that the compiler should do though, not hte programmer

20:42 mebaran151_: I agree with slava here

20:42 Chouser: arohner: you're trying to program for side-effects, which will be fighting uphill in clojure. What are you trying to return?

20:43 slava: if the result of the non-tail-recursive call is the input to an associative operation, then its pretty easy to convert it to use an accumulator

20:43 mebaran151_: oh I'm trying to transform an array of ints as follows

20:43 slava: if its the input to cons, you convert it to an accumulator and reverse the list at the end

20:43 pretty simple transformation to make

20:43 the problem with doing it by hand is that its error-prone and you get a proliferation of auxilliary functions

20:44 mebaran151_: no int can be greater than the max value, and I'm incrementing from the left

20:44 arohner: ah, figured it out

20:44 :while

20:46 ah, I should be using :when and :while

20:46 I'm not really programming for side effects, I was just being lazy because I only cared about the last value

20:46 doing project euler stuff, so I just needed to see the last value and type it in

20:49 Chouser: slava: I'd be interested to see a patch to Clojure that does that.

20:52 arohner: yeah, I just meant with "print". project euler is a great way to learn a new language.

21:03 mebaran151: my method didn't work: how would you transform my example?

21:09 Chouser: incr is the same as inc?

21:09 oh, incr and base are your own?

21:10 mebaran151: yeah

21:10 it's a string incrementer of my own devising

21:11 kind of like Ruby's

21:16 Chouser: what does next-id return? I'm guessing a list?

21:17 rhickey: Chouser: a patch to Clojure that does what?

21:17 Chouser: does tail-call optimization at compile time.

21:17 rhickey: on a self-call?

21:18 Chouser: no, I kinda like the tail-position assertion of "recur". For non-tail-position and mutual-recursion cases.

21:19 I think that's what slava was talking about, anyway.

21:19 rhickey: the JVM can't do mutual recursion TCO

21:20 Chouser: Yeah, I know. My understanding of what slava was saying is that the compiler could overcome the JVM's runtime weakness there.

21:20 rhickey: It can't

21:20 I think he was just talking about not needing recur on self-call

21:21 Chouser: self-call in a non-tail position?

21:21 rhickey: self-call in tail position

21:21 Chouser: yeah, that's not interesting. :-)

21:22 rhickey: the reason that I don't is because of the expectation it creates among Scheme programmers

21:24 this way it's easy to explain - there's no TCO, only recur is guaranteed non-stack-consuming

22:08 slava: Chouser: i was talking about an optimization that converts non-tail-calls into a tail call with an acculuator

22:08 eg, (defun (fac x) (if (< x 3) x (* (fac (- x 1)) x)))

22:08 this is not tail recursive

22:08 but its easy to turn it into a tail recursive function

22:12 people will expect a lisp compile to do this, so it will be surprising to many if clojure doens't

22:12 they'll write fnctions that blow the stack without realizing it

22:21 Chouser: slava: are you working on a patch?

22:23 Is it common for CL or Scheme to optimize non-tail calls? I haven't gotten that impression from the little reading I've done.

22:34 can you guarantee all self-calls would be converted to tail-call? If not, that could cause even more surprising behavior.

22:37 albino: I doubt he's working on a patch, he has his own language to contend with

22:38 Chouser: ah

22:42 slava: Chouser: you can't convert all calls into tail calls of course

22:42 its surprising inasmuch as any compiler optimization is

22:43 but that's not an argument for non-optimizing compilers :)

22:44 Chouser: well if the difference between optimizing and not is a bit of speed, that's one thing. If it's the difference between blowing the stack and crashing or not, that kinda matters...

22:45 slava: does java crash when you exceed a fixed-size call stack allocation or does it grow the stack?

22:46 i haven't done any java since 1.4 or so, i guess many things have changed

22:47 Chouser: if I do infinite recursion, it crashes

22:47 ((fn x [] (x)))

22:47 boom

22:47 slava: because it fills up the heap?

22:48 albino: slava: how could one tell the difference?

22:49 slava: if the stack has a fixed size, then converting list operations to tail recursion with a list accumulator will be a win

22:49 otherwise, not so much

22:50 in both cases converting arithmetic to tail recursive form is a win because you'll run in O(1) space and not O(n)

Logging service provided by n01se.net