Arc Forumnew | comments | leaders | submitlogin
4 points by waterhouse 3368 days ago | link | parent

The first (and only) reason that comes to my mind is: efficiency. Calling a function that takes rest args means allocating a list at runtime; the usual expansion for "do" is a direct call to a lambda, which the Racket compiler seems able to handle with no runtime cost. Thus:

  arc> (def do-func args last.args)
  #<procedure: do-func>
  arc> (mac do-macro args `((fn () ,@args)))
  #(tagged mac #<procedure: do-macro>)
  arc> (time:repeat 1000000 (do-func 1 2 3))
  time: 270 cpu: 270 gc: 6 mem: -4392856
  nil
  arc> (time:repeat 1000000 (do-macro 1 2 3))
  time: 69 cpu: 70 gc: 0 mem: 928
  nil
  arc> (time:repeat 1000000 1 2 3)
  time: 67 cpu: 68 gc: 0 mem: 128
  nil
It is not too far-fetched an idea for a compiler to eliminate the runtime overhead of the calls to "do-func". Basically this would require assuming that "do-func" will not be redefined at runtime--which is permitted in Arc, so it would require the compiler to make optimistic assumptions and be prepared to invalidate the code when they are violated (i.e. if someone actually does redefine "do-func" at runtime). I've heard the best Javascript engines do this, but Racket does not.

In your use case, having a "do" that works at all is better than none, and I don't think there is any logical problem with doing so. (Strictly speaking, it makes it possible to "do" [!] more things, since you can't apply a macro.)



2 points by Pauan 3367 days ago | link

That's a good point. In Nulan, you can't redefine things (all variables are constant). I'm not so worried about performance right now. My main concern is simplicity, since implementing "do" as a macro introduces a lot of extra complexity (because Nulan compiles to JavaScript).

-----