$WORK
. The event started at a pretty high tempo, with Dave Thomas’ talk on Metaprogramming Ruby. It’s a common topic in the Ruby community, and hyper-relevant at any Rails event, since Rails is all about metaprogramming.Ruby provides a small but complete set of tools for metaprogramming: blocks (closures),
lambda
, define_method
, and various forms of eval
. However, Dave was quick to mention that eval
is generally considered to be bad form, and should be used sparingly, when no alternative exists. Ruby also has a few nifty features that simplify metaprogramming, like an extensive set of hook methods and open classes.Perhaps the biggest example of Ruby metaprogramming in action is the Rails ActiveRecord class. ActiveRecord works though inheritance, where the base class intuits the name of the table it models (based on the database used in the current project’s environment), and figures out the rest as needed.
Here’s a rudimentary ActiveRecord model:
class User < ActiveRecord::Base
end
If there are additional relationships in the database, those relationships can be added by invoking (inherited) class methods on the model, in a rather declarative fashion:
class User < ActiveRecord::Base
has_many :purchases
belongs_to :group
end
All the details are filled in through inheritance,
method_missing
, and/or direct modification of the subclass. Only through a strict discipline of metaprogramming is this magic possible.But that’s not the big insight. The big insight is that all of this deep magic can be done without
eval
.The big win here is metaprogramming, and Ruby and Rails demonstrate together that you don’t (always) need
eval
or macros to do sophisticated metaprogramming. Ruby’s tools boil down to various kinds of closures: blocks and lambda
produce proc
-flavored closures, while define_method
creates a closure that is explicitly attached to a receiver that will provide a self
reference when invoked.It wasn’t until this point that I realized that Haskell’s support for metaprogramming was as complete and full featured as Ruby’s, and that
eval
isn’t strictly necessary for doing complex code generation. Even though Haskell doesn’t have eval
, it does have lambdas, type classes, higher order functions, combinators, sections, partial application, and many more primitive operations that support metaprogramming. Not only do these features make metaprogramming possible, they make it pervasive all the way down to the prelude.And for those times when Haskell’s various flavors of closures don’t do the trick, there’s always Template Haskell (which, I have to admit, I’ve never needed to use).
1 comment:
And
haskell has a library that provides eval:
"Thirdly, a combination of runtime compilation and dynamic loading provides a set of eval functions- a form of runtime metaprogramming."
Post a Comment