Ruby Behaviors
August 16, 2001
Ruby Behaviors, v. 0.0.2 (alpha), is now available for
download.
Changes and enhancements include:
- A bit of refactoring and renaming at the behavior-defining level.
Nothing you can't handle :-)
- Smart(er) handling of aliases, so you can override methods like
"[]" and either specify an alias or use a default one (other than
"old[]", which blows up). The defaults are listed in the docs.
- Addition of an ensure clause so that if you 'return' from inside
an adoption block, 'desist' will be run (which includes a call to your
'stop' method).
Feedback is always welcome; send email to me, David Alan Black.
[Note: As an introduction to Ruby Behaviors, here is the increasingly
out-of-date, but still sort of philosophically relevant, thing I
posted before there were any actual releases.]
What follows is a top-level, somewhat wishful description of something I am
working on. Updates will be forthcoming. Feedback is welcome.
Your host,
David Alan Black
Introduction
Ruby Behaviors are locally-scoped changes to the Ruby core language.
They are managed through facilities provided by class Behavior.
The goal of Ruby Behaviors is to make it very easy to make temporary changes to
Ruby, without interfering with other code and without having to convince anyone
else of the merits of the change. This will, I hope, take the burden off the
RCR process, and open up a way for people with similar tastes in Ruby tweaking
to share modifications to their programming environments.
Sketch of the Ruby Behaviors system
The overall structure will be:
- You write a Behavior, which is a package (format yet to be determined;
written in Ruby) containing one or more modifications to core Ruby
functionality.
- You put this package somewhere in the (yet to be designed) Behavior area or
path.
- You use the facilities of class Behavior to switch the behavior on and
off. (See below.)
Also, there will be facilities for sharing and centralizing Behaviors.
Examples of using Ruby Behaviors
For these examples, we assume that a set of Behaviors called
"DavidsWay" has been created and made accessible to the Behavior
management facilities of class Behavior.
"DavidsWay" adds a #to_h method to Enumerable, and a #byte_sort method to
String.
# Style 1 (explicit adopt/desist)
require behavior
b = Behavior.new(:DavidsWay)
b.adopt
a = [1,2,3,4]
h = a.to_h(true) # => { 1 => true, 2 => true, ... }
b.desist
# Style 2 (block)
require behavior
b = Behavior.new(:DavidsWay)
b.adopt do
puts "hello".byte_sort # => ehllo
end
Writing a Behavior
The process of writing a new Ruby Behavior will be very close to
simply writing or rewriting one or more methods for one or more core
class or module.
It will also have hooks into the Behavior system. The form of these
is yet to be determined, but roughly speaking there will be "start"
and "stop" hooks.
The problem area addressed by class Behavior
(adapted from
ruby-talk:14556)
We've got two basic mechanisms for publically extending Ruby: language
change (RCR) and module/software archive (RAA). However, it seems to me that
Ruby happens to excel in generating, or inspiring, a type of code which
unfortunately falls right into the void between RCR and RAA.
I'm thinking of things like the by-products of RCR discussions. Say we talk
about Array#insert, or Array#to_h, or whatever. Often, several suggested
versions are perfectly respectable and useful in their own way. Of course if
the method is going to be part of the language then one version has to prevail.
But then the other ideas more or less vanish, at least from the communal radar.
The language-change/RCR process inevitably (and understandably) has this
winner-take-all aspect to it. On the other side -- as a possible first answer
to the question of what to do with miscellaneous good code -- is RAA. But the
problem is that RAA lies too far in the other direction. A five-line
Array#insert implementation isn't going to end up on RAA.
I wonder whether there's some more systematic way to leverage the (to me)
sometimes startlingly powerful little language enhancements and extensions that
get thrown around.
Miscellaneous comments
- Behaviors are very different from "require"s. They are more
high-level, and they do not correspond to specific files. The
Behavior mechanism will know what to do, in terms of file retrieval
and method execution and dependency checking. The programmer will
not have to know the underlying storage system.
- Behaviors are localized (see sample usage possibilities, above).
Since they are for the programmer's benefit, they should not intrude
on other code. The mechanism for this will involve (re)defining and
un(re)defining methods.
- The entire Behavior mechanism must be layered strictly on top of Ruby.
You can use it if you want, or you can ignore it. The Behavior
system is not intended to split the Ruby world, but rather to make
it more flexible and efficient.
- If your program uses behaviors and
you share your program, everyone running your program will have to
have the Behavior package. This is no more or less unreasonable
than any other library dependency, though if there's a way to embed
or piggyback
behaviors without robbing the whole thing of its conciseness and
abstractness, that might be OK.
- Shop-specific behaviors can be created, but then they will have to
be shipped with the software that uses them. Automation of this
kind of thing will be part of the system. It has to be done in
such a way that the programmer doesn't have to maintain multiple
versions of the program (one behavior-aware and one not).
- Most of the really thorny problems that have been identified (thanks
to Dave Thomas and Guy Hurst for some irc feedback) involve behavior of
variables and/or closures that are governed by a given Behavior but are used
outside of its scope.
Copyright (c) David Alan Black, 2001.