| Okay, so, as I was working on PyArc, I hit upon a troublesome function in arc.arc. As near as I can see, Arc evaluates optional arguments every time the function is called, as opposed to Python where it only evaluates it once. What do I mean by that? (def foo ((= a (uniq))) a)
(foo) -> gs722
(foo) -> gs722
(foo) -> gs722
As you can see, it evaluated `uniq` and then assigned it to `a`. It only did this once, when the function was created. By contrast, Arc behaves like this: (def foo ((= a (uniq))) a)
(foo) -> gs722
(foo) -> gs723
(foo) -> gs724
It evaluates the optional argument every time the function is run. I don't see a clear winner here: both behaviors are useful in different situations. Okay, so, here's a comparison. If you're in Arc, and you want it eval'd once, you can use a `let`: (let b (uniq)
(def foo ((= a b))
a))
Which isn't too bad, except for the whole (= a b) thing.--- On the other hand, if it evaluates once (like in Python), but you want it to evaluate every time, you could do this in PyArc: (def foo (a)
(if (no a) (= a (uniq)))
a)
It avoids the silly (= a b) thing, but it's still pretty darn clunky. You could also use this, which is nicer, but less efficient: (def foo (a)
(= a (or a (uniq)))
a)
Or slightly more efficiently: (def foo (a)
(or a (= a (uniq)))
a)
Also, unlike with a let block, it's possible to easily wrap it up in a macro: (def foo (a)
(default a (uniq))
a)
Which I think is a bit more pleasant than using `let`. On the other hand, I don't see a clear or obvious way to make the `let` version better.So what do you think? Should optional arguments evaluate when the function is created, or every time the function is called? Got any ideas for better ways to support both behaviors? P.S. PyArc can now parse and evaluate arc.arc! I had to disable read-time macro expansion to get it working, though. As a side note, does anybody want to try PyArc? It's far from finished, and is missing major functionality (IO, networking, using = on tables, etc.) but really basic stuff should work. |