On 8/29/06, dblack / wobblini.net <dblack / wobblini.net> wrote: > Hi -- > > On Wed, 30 Aug 2006, Rick DeNatale wrote: > > > If a singleton class is a class which is tied to one and only one > > object, then a singleton method should be a method tied to one and > > only one object as well, but check this out: > > > > class X > > def foo;end > > end > > > > X.singleton_methods => ["foo"] > > > > class Y < X; end > > > > Y.singleton_methods => ["foo"] > > > > Does anyone beside me find that surprising? > > It's always struck me as an anomaly. It's redeemed somewhat by the > superclass thing, whereby class << X is the superclass of class << Y. > (At least, in 1.8.2 and > 1.8.5 it is; I'm not sure why that got > derailed by 1.8.4, since it still behaves that way.) So was there a change in 1.8.3 which got backed out in 1.8.5? What was it? > > Now the rdoc of Object#singleton_methods says that it takes an > > optional boolean argument which if false will include methods in > > modules included in obj. > > > > Y.singleton_methods(false) => [] > > > > So does Y include X? > > > > Y.include? X > > TypeError: wrong argument type Class (expected Module) > > from (irb):29:in `include?' > > from (irb):29 > > I'm not sure what you're getting at here. Are you thinking of whether > Y's ancestors include X? No, I was getting to the actual vs. stated behavior of singleton_methods(true). The Rdoc says that if the argument is true (the default now) then methods from included MODULES will also be reported, but X is not an included module. It's a class and classes can't be included, instead X's singleton class is a superclass of Y's singleton class. And by the way, I'm surprised that neither you nor anyone else caught my typo in the initial definition of X which should have been: class X;def X.foo;end;end In order to make foo a singleton/class method. > > So the operational definition of a singleton methods seems to be a > > method of an object which appears in a singleton class or a module > > mixed directly INTO a singleton class, or comes from a singleton class > > which is in the superclass chain of the objects class BEFORE a non > > singleton class, or a module directly mixed into one of those > > singleton classes. Whew. > > It's not too hard if you draw it :-) It's basically just a bunch of > classes and modules, with the object walking through them looking for > a method. I didn't say it was hard, just that I ran out of breath typing that sentence. It also seems to me that some of these anomalies in the results of some of the reflection methods show too much of the cogs (like FL_SINGLETON and T_ICLASS) which Matz seems to be trying to hide. > [...] > > > It appears that a lot of the reason for FL_SINGLETON and T_ICLASS is > > to hide a slightly tricky implementation from showing through some of > > the reflection methods. Perhaps Ruby would be a little cleaner if it > > just called a metaclass a metaclass, and a singleton class a singleton > > class, and reserved the later for a class providing behavior for a > > single instance. But that's just my opinion and it's not the way > > things are. > > I tend to call the singleton classes of classes singleton classes (did > you follow that? :-) in part because the term "metaclass" doesn't do > much for me. But the singleton-ness of them is definitely in > question. And that's my observation/question. Just what does the singleton-ness of a class really means. There doesn't seem to be enough to go on here in formal documentation. We're left pondering what it means as the result of experiments to a large extent, and/or trying to suss it out by reading implementation code to infer the intent. And the code might just be a little cleaner if the classes which provide behavior to sub-classes of Class were implemented with a separate internal type instead of being cooked up using a combination of FL_SINGLETON and special cases in the code. As for the term metaclass, personally I think that things would be more understandable if Ruby used an official term for the object which holds the behavior of a class object. Metaclass seems like it fits that concept quite well. The pickaxe quotes Matz as saying that although those things are singleton classes of classes, that they behave just like Smalltalk metaclasses. I can understand the tension between the implementation buying off on an official metaclass concept and how that might affect implementing some of Matz' wild ideas in the future, since it would somehow dictate parts of future implementations, but on the other hand the way it is now, with the implementation observable "through a glass darkly," protection of the freedom to pursue new implementations seems to be through a form of "security through obscurity." > > > I just realized that there's no class_methods family of methods in > > Ruby. I can't say: > > > > Array.class_methods > > > > instead I have to say: > > Array.singleton_methods > > Now that's the cool part :-) I love the fact that there's no > language-level notion of a "class method". In general, Ruby has this > way of providing a remarkably featureless (I use the word advisedly) > landscape, out of the featurelessness of which one can mold features. > So if you feel like there should be class methods, you can tap into > the fact that class objects can have singleton(ish) methods. But as > far as Ruby is concerned, there's no special case. Well Module does have methods private_class_method, and public_class method, to "make existing class methods" private or public respectively, so there does seem to be some notion of "class method." > Frequently, the special cases and constructs in Ruby are in the eye of > the beholder, so to speak. I put "attributes" in that category too, > even though the presence of the attr_* methods makes that a somewhat > more language-supported thing. > > It's also why I dislike class variables so much. They're a > language-level feature that I think can be done better using a blend > of other features. > > > While I can say > > Array.private_instance_methods > > > > How do I get the private_class_methods? > > class << Array; private_instance_methods(false); end > > or something along those lines. Well, you'd think, but not quite: class <<Array;private_instance_methods(false);end => ["inherited", "initialize", "initialize_copy"] Which are the private instance methods of the class Object?! At least that's what Object says: class << Object;private_instance_methods(false);end => ["inherited", "initialize", "initialize_copy"] Now perhaps it's because Array doesn't HAVE any private class methods, so lets' make some test classes: class A; def A.foo;end; private_class_method :foo;end class <<A; private_instance_methods(false);end => ["inherited", "foo", "initialize", "initialize_copy"] class B < A;end class <<B;private_instance_methods(false);end => ["inherited", "foo", "initialize", "initialize_copy"] So for singleton classes of classes, private_instance_methods(false) is finding the inherited methods, contrary to the specification. I haven't sussed out enough of the implementation to figure out why this is. This is on 1.8.4 perhaps it's changed on 1.8.5 but if so it doesn't show up in the change log as far as I can tell. -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/