} Dave Thomas 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:
1) include a module
2) define a method
3) alias a method
4) 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
···
On Tue, Jan 02, 2007 at 12:04:35AM +0900, Trans wrote: