(There’s also a subtle difference between these two approaches to
defining a singleton method, involving the scope of constants, but that’s an
arcane point. For the most part, you can treat them as equivalent.)
The subject of singleton methods and constants has recently gotten me
into trouble. Here is a simplified example:
module ExtendMeFirst
BAR = 3
end
module ExtendMeSecond
def print_bar
puts BAR
end
end
class A
extend ExtendMeFirst
extend ExtendMeSecond
end
Now, I somewhat understand why this doesn’t work - the constants are in
different scopes. The challenge is to get around this problem and use
the constant BAR from ExtendMeFirst in module ExtendMeSecond. We
discovered that what we needed to was access the singleton class’s
constants, but there is basically no easy way to do this, since there
is no “singleton_class” method in Object/Kernel (which has been
discussed a long time ago on this list). We eventually added one:
class Object
def singleton_class
class << self; self; end
end
end
And then doing this allowed us to get to the constant:
module ExtendMeSecond
def print_bar
puts singleton_class::BAR
end
end
Is there a better way to do this? What is the “arcane point” about
singleton methods and constants?
(There’s also a subtle difference between these two approaches to
defining a singleton method, involving the scope of constants, but that’s an
arcane point. For the most part, you can treat them as equivalent.)
For the answer to your last question:
What is the “arcane point” about singleton methods and constants?
see the recent thread on ‘“def self.method” vs “class << self; def
method”’. (It’s the example with the top-level vs. class-specific
contants.)
end
different scopes. The challenge is to get around this problem and use
end
And then doing this allowed us to get to the constant:
module ExtendMeSecond
def print_bar
puts singleton_class::BAR
end
end
Is there a better way to do this?
I don’t think there’s any way that doesn’t involve some kind of
coupling, since you’re basically printing one module’s constant from
another module (using “module” as class-or-module). The way you’ve
done it presupposes that ExtendMeSecond will indeed be mixed in to a
singleton class subsequent to the mixing in of ExtendMeFirst. You
could, instead, cut out one leg of the journey and just say:
def print_bar
puts ExtendMeFirst::BAR
end
which is a different kind of coupling, but really isn’t inherently
worse than calling Math::PI or any other constant from another module.
which is a different kind of coupling, but really isn’t inherently
worse than calling Math::PI or any other constant from another module.
David
This problem originally arose from trying to extend/alter some
functionality of Rails in a plugin, and needing access to some
constants defined in a ClassMethods module that uses the:
def self.append_features(base) # :nodoc:
super
base.extend ClassMethods
...
idiom that is used frequently in rails. To me, the “mixin” concept
creates some weird decisions to make with repsect to coupling. In some
other OOP languages, extending the functionality might be done by
creating a new class that derives from ActiveRecord, and then
overriding the functions in question to provide new behavior.
In Ruby/Rails however, especially with plugins, it seems to be much
more common to use the include and extend functionality to bring new
functions into an existing class, or override them. When you do this,
you’re frequently going to want to make assumptions about your context
in the new mixin since you know where it’s going, however, conceptually
a mixin should be somewhat context ignorant, should it not?
singleton_class{
attr ‘a’
alias_method ‘b’, ‘a’
}
end
I prefer it without that, since that makes it deviate from the #class
method, which it’s otherwise precisely parallel to. I’d rather that
singleton_class work like class than that it work like class_eval.
Otherwise you’ve got a situation where all classes except singleton
classes have to call class_eval, and I don’t see any grounds for
granting that privilege.
(I know we’ve hashed through this before, and don’t agree; I just
wanted to summarize the dissident position
I prefer it without that, since that makes it deviate from the #class
method, which it’s otherwise precisely parallel to. I’d rather that
singleton_class work like class than that it work like class_eval.
Otherwise you’ve got a situation where all classes except singleton
classes have to call class_eval, and I don’t see any grounds for
granting that privilege.
I agree with David’s point about the discrepancy but couldn’t that
be also resolved by changing the standard #class method to behave like
Ara’s proposed #singleton_class ?
be also resolved by changing the standard #class method to behave like
Ara’s proposed #singleton_class ?
Yes, but that seems awfully magic and hidden. I don’t see what there
is about querying an object for its class that suggests a context for
an implied class_eval.
def foobar
class.class_eval{ attr ‘added_a_class_attr’ }
end
one word, i realize, but open{} only saves a close too - they add up!
Well… it has to be self.class But in any case, though I’m a big
fan of Ruby’s expressive power, I don’t think it’s rooted in pruning
away method calls as an end in itself. open is an operation with
extent in time, and a block is good at meshing with that. class_eval
is also such an operation – but just retrieving the name of a class
isn’t.
(I’m not saying that “extent in time” is the only block-worthy thing,
but I just can’t see how obj.class suggests any kind of segue to a
blockwise operation.)
I prefer it without that, since that makes it deviate from the #class
method, which it’s otherwise precisely parallel to. I’d rather that
singleton_class work like class than that it work like class_eval.
Otherwise you’ve got a situation where all classes except singleton
classes have to call class_eval, and I don’t see any grounds for
granting that privilege.
(I know we’ve hashed through this before, and don’t agree; I just
wanted to summarize the dissident position
hmm. i don’t disagree completely - i would just say that those other
methods,
‘class’ for example, should take blocks. blocks are 25% of the reason
ruby is
so beautiful and clean looking. compare
def foobar
class{ attr ‘added_a_class_attr’ }
end
with
def foobar
class.class_eval{ attr ‘added_a_class_attr’ }
end
one word, i realize, but open{} only saves a close too - they add up!
Yes, but that seems awfully magic and hidden. I don’t see what there
is about querying an object for its class that suggests a context for
an implied class_eval.
the same thing that implies one for class creation
Class.new{
}
we could easily just do
Class.new.class_eval{
}
i might add that any of them is less esoteric than
class << self
:wtf
end
implying ducking into an object’s singleton class
for that matter, why should
class PreExistingClass
:at_least_this_makes_sense
end
do a class_eval, rather than clobber a class?
it also seems POLS - when has anyone every wanted a singleton_class except
to evaluated code it in. plus, what other meaningful semantic would
passing a
block to a class do?
I agree with David’s point about the discrepancy but couldn’t that
}
we could easily just do
Class.new.class_eval{
}
I’ve actually always thought that new-with-block was a bit of a
stretch
i might add that any of them is less esoteric than
class << self
:wtf
end
implying ducking into an object’s singleton class
I don’t think that’s esoteric; it’s just the way the class keyword
works: it takes either a constant, or a “<< object” expression (which
might be verbalized as “from this object” or something like that).
for that matter, why should
class PreExistingClass
:at_least_this_makes_sense
end
do a class_eval, rather than clobber a class?
It doesn’t exactly do a class_eval, from the scoping perspective. But
in any case it’s a bit far afield. Let’s say (argumentum ex concessis
that class PreExistingClass not clobbering a class made no
sense. How would it follow that it’s a good idea for #class to take a
block?
it also seems POLS - when has anyone every wanted a singleton_class except to evaluated code it in. plus, what other meaningful
semantic would passing a block to a class do?
POLS is so 2002 But anyway – you’re not passing the block to a
class, exactly; you’re supplying the block to a method that returns a
class. The question is how the block pertains to the work of the
method. That’s where I don’t see the relevance.
i love being devil’s advocate
NOW you tell me?! I have to say, as much as I don’t see the logic
of obj.class taking a block, I’d certainly rather have #class and [the
hopefully future] #singleton_class behave the same as each other in
that respect, whatever the behavior is.
NOW you tell me?! I have to say, as much as I don’t see the logic
of obj.class taking a block, I’d certainly rather have #class and [the
hopefully future] #singleton_class behave the same as each other in
that respect, whatever the behavior is.
we’ll miss you at rubyconf david - only beer would solve this!
-a
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.