On Tue, Jan 02, 2007 at 12:04:35AM +0900, Trans wrote:
} Dave T. wrote:
} > I wonder: is it a mistake to think of it as a class at all? Sure, it
} > had a ‘class’ somewhere in its background, but is potentially moved
} > on a lot since then. In a way, it’s move analogous to a
meta-binding,
} > as it’s the execution environment of an object. So, just to get the
} > creative juices flowing, and in the spirit of brainstorming, how
about
[…]
The only way in which a class and a module differ is that you can create
an
instance of a class. Current Ruby 1.8.5 will not let you call #new on a
singleton class, so one could argue that it’s more a module than a
class,
remembering that Class subclasses Module. It is,
however, at least a module. It is very important that it can be treated
as
a module, i.e. responds to various methods defined in Module. I’d claim
that #include and #define_method are the two most important of those.
} Seems to me that 80% of the time we want to use the “singleton class”
} with class_eval. Expressions like “singleton_class.class_eval” are
} rather redundant and long winded (IMHO). So maybe another single term
} for this, along the lines of what you’re saying, would be better.
} Looking at Phrogz’ wiki page of names I came up with:
}
} customize do
} …
} end
}
} Then the class could be called the ‘customization’. Ie. the above
being
} equvalent to:
}
} customization.class_eval do
} …
} end
If I hadn’t had occasion to do significant metaprogramming and was
looking
at this, I’d agree with you that this is nice. As it is, there are
really
only four things I do to interact with the singleton class, in order of
frequency of use:
- include a module
- define a method
- alias a method
- remove a method
Now, #1 is served by Object#extend and doesn’t require explicit access
to
the singleton class at all. With #2, 99% of the time I use
#define_method,
and the only time I don’t is when I need to define a block-accepting
method. (Actually, I use send(:define_method, …) because
#define_method
is private. Could we make #define_method public for all singleton
classes,
please? How about a SingletonClass subclass of Class, or possibly
module,
that makes it public?) I actually need #3 and #4 vanishingly rarely, and
most of the time it makes more sense to do it in a module anyway which
can
be included with extend.
I just realized I forgot attr_accessor and friends, but I’d be inclined
to
use #send (or #funcall) with that as well. What I’m saying, though, is
that
if I had #customize and #customization (and #define_method were public
for
singleton classes), I’d still do something like this (note: contrived
example):
def setup_hashed_attributes(obj, hash)
if attrs = obj.instance_variable_get(:@hashed_attributes)
attrs.merge(hash)
else
obj.instance_variable_set(:@hashed_attributes, hash.dup)
end
singleton = obj.customization
singleton.send(:attr_reader, :hashed_attributes)
hash.keys.each { |k|
singleton.define_method(k) { @hashed_attributes[k] }
singleton.define_method("#{k}=") { |v| @hashed_attributes[k] = v }
}
end
…rather than the equivalent…
def setup_hashed_attributes(obj, hash)
if attrs = obj.instance_variable_get(:@hashed_attributes)
attrs.merge(hash)
else
obj.instance_variable_set(:@hashed_attributes, hash.dup)
end
obj.customize {
attr_reader :hashed_attributes
hash.keys.each { |k|
define_method(k) { @hashed_attributes[k] }
define_method("#{k}=") { |v| @hashed_attributes[k] = v }
}
}
end
I just like how the first one reads. The first one says, “I am messing
with
an object’s capabilities by poking at its instance variables and adding
methods to it.” The second one says, “I am reopening a class and adding
methods to it after poking at an instance variable.”
} T.
–Greg