8 ms·
Eric Kidd: Why Ruby is an Acceptable Lisp
- emmett 17y agoHaving 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.
- Tichy 17y agoWhat confuses me in Ruby is that functions and executable blocks (or what they are called) seem to be different things. So def my_fun(a,b,c) is different from {|a,b,c|...} I find it very confusing and as a matter of fact, I can not remember what I have to instantiate when to pass around (there is a Proc object, but does it refer to a fn or a block? And what would be the name for the other thing?). Just a reminder that shortness is not the only criterion - it also has to be intuitive/logical.
- jfarmer 17y agoProcs, blocks, and methods are actually all different from each other. Of those three, Procs are the only ones that are actually objects (i.e., can be assigned to variables and can receive messages).
- sjs 17y agoputs_method = method(:puts) def get_block(&block) block end my_block = get_block { puts_method.call('hello!') } my_block.call #=> hello!
- tesseract 17y agoputs puts_method.class #=> Method puts my_block.class #=> Proc Method and Proc are types; blocks are a syntactic construct.
- sjs 17y agoYou're right, captured blocks are instances of Proc. However I still claim that methods are objects that can be passed around, assigned to variables, and sent messages. Method and UnboundMethod are both classes that inherit from Object. It's right there in proc.c with the Proc class. Method.ancestors #=> [Method, Object, Kernel]
- tesseract 17y agoI don't disagree with you there.
- lispm 17y ago'Recursive Functions of Symbolic Expressions and Their Computation by Machine', McCarthy, 1960 http://www-formal.stanford.edu/jmc/recursive/recursive.html http://www-formal.stanford.edu/jmc/recursive/recursive.html Does that sound like 'Ruby'? I don't think so.