4 ms·
Having hacked a (poorly implemented, bug riddled) macro system into Ruby because I needed it, I can say with certainty that Ruby is not an acceptable Lisp. It j
by emmett 17y ago
Having hacked a (poorly implemented, bug riddled) macro system into Ruby because I needed it, I can say with certainty that Ruby is not an acceptable Lisp. It just turns out that some of the (easiest) things you can use macros for can be faked with a combination of closures and fully executable class code (both good ideas, both present in Ruby and in Python). Try to do any of the most interesting/great things with macros and you'll run into a brick wall.
Of course this can be overcome - he mentions two projects which could turn Ruby from most of a Lisp into 100% of a Lisp with direct access to the parse tree. But those are not used right now in every day Ruby programming.
- raganwald 17y agoWhat are "the most interesting/great things with macros" that you would like to do?
- emmett 17y agoI want to be able to write: cache(key_name, :ttl => 30.seconds, :dependent => ModelClass) do model.expensive_operation end and have that cache expire whenever any instance of ModelClass is updated. With macros, every call to cache() can be expanded into: ModelClass.register_expiration_callback(keyname) do_cache(...) Without macros, there's no way to catch deeply nested cache calls. I fake this by scanning the source for calls to cache() on startup right now.
- avibryant 17y agoI'm not following. Why does "ModelClass.register_expiration_callback(keyname)" have to be in a macro expansion, rather than just the first statement of the cache() method? It doesn't appear to use local scope at all. Can you flesh out the example a bit more? FWIW, I believe that Ruby or (especially) Smalltalk-style syntax for method calls and closures covers such a large set of the things macros are used for that their complexity cost (esp when building tools) outweighs their benefit.
- emmett 17y agoSorry, re-reading that it wasn't totally clear. The ModelClass.register_expiration_callback(keyname) has to be run at parse time, because there's no guarantee that the cache statement will ever be executed before a ModelClass instance is updated. You can't run things at parse time in Ruby (without exotic extensions); that's the whole point of macros. I completely agree that there are a large number of uses for macros that "SmallTalk style" syntax completely replace. It turns out that a lot of things don't really require you to run code at parse time. Take anaphoric-if for example, which is classically implemented as a macro; all you really need is the ability to manipulate the local variables of a closure from the outside. Parse-time execution is not required.