I’ve come across a number of occasions where methods like #class_attr_accessor, or #module_alias_method are defined. It’s nice
to have those, but it seems to me this isn’t very DRY since the
methods for these things already exist in the class domain (ie.
singleton class). So what do others think of this instead:
module Kernel
# Provides access to an object's metaclass (singleton class)
# by-passing access provisions. So for example:
#
# class X
# meta.attr_accesser :a
# end
#
# X.a = 1
# X.a #=> 1
def meta
@_meta_functor ||= Functor.new do |op,*args|
(class << self; self; end).__send__(op,*args)
end
end
end
Personally, I’ve wished I could name the method #class and/or #module,
but obviously that’s not doable. In any case, do you think this is a
better approach? Are there any serious disadvantages to it? Or do you
prefer a myriad of special class level methods? If so why?
If you are not familiar with Facets Functor, it’s your basic higher
order message:
class Functor
# Privatize all methods except vital methods and #binding.
private(*instance_methods.select { |m| m !~ /(^__|^binding$)/ })
def initialize(&function)
@function = function
end
def to_proc
@function
end
# Any action against the functor is processesd by the function.
def method_missing(op, *args, &blk)
@function.call(op, *args, &blk)
end
method invocations to the singleton class. Why not directly use /
return it?
Try it:
class X
meta.attr_accessor
end
NoMethodError: private method `attr_accessor’ called for #Class:X
from (irb):7
class Some
meta do
attr_accessor :foo
def incr
self.foo += 1
end
end
end
There’s no need for meta at all, you could just use “class << self”
directly,
class Some
class << self
attr_accessor :foo
def incr
self.foo += 1
end
end
end
But just as some people prefer to use “def self.foo”, it’s nice to use
module level methods like #class_attr_accessor. That’s were #meta
comes in as generalized form rather than defining class level
equivalents for all possible methods.
Your approach mentarbates less, so trans doesn’t like it as much.
Along these lines, note Stu Halloway’s blog post about the definition
of Object#metaclass in facets vs. other places and the ensuing
commentary:
I’d seen lots of examples of metaclass being defined the same way as
Robert’s proposed meta method above, and had never seen the more
complex implementation in facets until Stu bumped into problems
because use was using facets ‘feature’ of taking a block.
I totally agree with the consensus in the comments that the simpler
definition is better. I also side with Jim W. about the
distinction between metaclass and singleton class or eigenclass or
whatever you want to call them.
I’d seen lots of examples of metaclass being defined the same way as
Robert’s proposed meta method above, and had never seen the more
complex implementation in facets until Stu bumped into problems
because use was using facets ‘feature’ of taking a block.
I totally agree with the consensus in the comments that the simpler
definition is better.
Actually in Facets, #singelton_class is defined witht the simpler
definition. #meta_class is not. However, I don’t agree that the
simplier case is somehow better. The issue is that Ruby will no-op a
block regardless. For example:
def x; “1”; end
x{“whatever”} #=> 1
So it has nothing per se to do with the definition of #meta_class.
It’s an aspect of Ruby, and the fact that there are two definitions of
this floating around out there. So between the two, I tend toward not
wasting name space. If supporting the block takes nothing away from
the regular usage, and it reads better, then whats the issue exactly?
I also side with Jim W. about the
distinction between metaclass and singleton class or eigenclass or
whatever you want to call them.
That’s Smalltalk not Ruby. I understand the distinction people want to
draw, but in Ruby they are the same construct.
That’s Smalltalk not Ruby. I understand the distinction people want to
draw, but in Ruby they are the same construct.
Thats why I think that overloading the expression “singleton class” is
somehow confusing.
Just my 2cents.
R.
I agree with that. But nothing else seems to stick. Even today I
thought of “domain class”, but I’m not sure that has all the right
connotations either.
I also side with Jim W. about the
distinction between metaclass and singleton class or eigenclass or
whatever you want to call them.
That’s Smalltalk not Ruby. I understand the distinction people want to
draw, but in Ruby they are the same construct.
I respectfully disgree.
Singleton classes in Ruby are an implementation construct which is
used for two distinct purposes:
To provide a place to put instance behavior. For example
a = “abc”
def a.foo
:foo
end
To provide a class for a class, i.e. a metaclass.
One difference is that the first can’t have subclasses, while
singleton classes used as metaclasses can and must since the
inheritance chain of metaclasses parallels the inheritance chain of
their instances. The otehr is that metaclasses is the class of a
class, not an arbitrary object. For all practical purposes, the second
kind acts exactly as metaclasses do in Smalltalk, and Matz was quoted
as such in the 2nd ed of the Pickaxe. Unfortunately many in the Ruby
community misunderstood that page as equating metaclass with singleton
class rather than seeing that although singleton classes are used to
implement metaclasses in Ruby, all singleton classes are NOT
metaclasses, a term which has a meaning even beyond Smalltalk of being
the class of a class.
Indeed - I’m using almost identical code in doodle[1] but using the
name #singleton_class instead of #meta
def singleton_class(&block)
sc = (class << self; self; end)
sc.module_eval(&block) if block_given?
sc
end
@Trans - doesn’t #meta clash with an openuri attribute? I’ve just
removed it as an alias to #singleton_class in doodle for that reason.
FWIW, I’m considering renaming #singleton_class to avoid clashing with
someone else’s definition. Perhaps, something like #the_method_formerly_and_variously_known_as_singleton_eigen_or_meta_class
? As far as I can see your functor in this case simply delegates all
method invocations to the singleton class. Why not directly use /
return it?
Try it:
class X
meta.attr_accessor
end
NoMethodError: private method `attr_accessor’ called for #Class:X
from (irb):7
So then the only (?) advantage of your proposal is that you can use
private methods like ordinary methods.
There’s no need for meta at all, you could just use “class << self”
directly,
True enough. And “class << self … end” is not as ugly as “class
<<self;self;end” for getting at the instance itself.
But just as some people prefer to use “def self.foo”, it’s nice to use
module level methods like #class_attr_accessor. That’s were #meta
comes in as generalized form rather than defining class level
equivalents for all possible methods.
That’s Smalltalk not Ruby. I understand the distinction people want to
draw, but in Ruby they are the same construct.
Thats why I think that overloading the expression “singleton class” is
somehow confusing.
Just my 2cents.
R.
On Sat, Mar 22, 2008 at 11:28 PM, Rick DeNatale [email protected] wrote:
I respectfully disgree.
To provide a class for a class, i.e. a metaclass.
One difference is that the first can’t have subclasses, while
singleton classes used as metaclasses can and must since the
inheritance chain of metaclasses parallels the inheritance chain of
their instances.
Hmm, this indeed would make me think about the possibility to use
metaclass as a special case of a singleton class of a
module.
(1) class << Object.new; self end is a singleton class but not a
metaclass
(2) class << Module::new; self end is a metaclass and a singleton class
by (1)
I never really noticed if this is used consistently as such, my bad
AAMOF.
But just as some people prefer to use “def self.foo”, it’s nice to use
module level methods like #class_attr_accessor. That’s were #meta
comes in as generalized form rather than defining class level
equivalents for all possible methods.
I see. Thanks for the enlightenment.
Honestly, I’m not all that keen about the method. I’m not sure what it
is about it that bothers me --I can’t quite put my finger on it. Which
is why I’ve brought this topic up. But then I consider the
alternative, defining a set of convenience methods:
Wait a minute… could we set the methods we’re interested in here to
=> Module
Looks good!!! Not sure why this never occurred to me before. See
anything wrong with this approach?
At the moment the only thing that bothers me is to change the visibility
of some methods of the core lib. I mean, they must be restricted for a
reason…
So then the only (?) advantage of your proposal is that you can use
private methods like ordinary methods.
There’s no need for meta at all, you could just use “class << self”
directly,
Well, yea.
Wait a minute… could we set the methods we’re interested in here to
protected instead of private? And, as you suggest, just use the
singleton class?
def singleton
class<<self;self;end
end
=> nil
class Module
protected :attr_accessor
end
=> Module
class X
singleton.attr_accessor :x
end
=> nil
X.x
=> nil
X.attr_accessor :y
NoMethodError: protected method `attr_accessor’ called for X:Class
from (irb):11
Looks good!!! Not sure why this never occurred to me before. See
anything wrong with this approach?
T.
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.