Accessing a child's constant from the parent's class - ruby

If a child inherits from the parent, it inherits the parents methods as well.
So how come an inherited method can't access the child's constants?
Example -
class Parent
def my_method
puts "Value of FOO is #{FOO}"
end
end
class Child < Parent
FOO = "bar"
end
Child.new.my_method #=> NameError: uninitialized constant Parent::FOO
Doesn't the inherited method run "inside" the child class?
How can I get around this?

No it doesn't. When you call Child.new.my_method it looks for the FOO constant in Parent and upwards.
I'm not going to question your approach and just provide you with a way to do what you want:
class Parent
def self.inherited(other)
other.define_singleton_method(:my_method) do
puts "Value of FOO is #{other.const_get(:FOO)}"
end
end
end
Now whenever you inherit from Parent the inherited hook will define a method my_method on the subclass. Notice that the scope of the block in the inherited method is still the class level scope of Parent. That's why I'm directly referencing the subclass (other) to get the constant.
A way around this would be to use other.instance_exec { ... }.
Update
#maxpleaner pointed out (with the explanation provided by #CarySwoveland) that you could also retrieve the class via self and then retrieve the constant from it.
I.e., just do
class Parent
def my_method
puts "Values of FOO is #{self.class.const_get(:FOO)}"
end
end
That works because when calling child = Child.new; child.my_method the value of self within my_method will be child. And the class of child is obviously Child which knows the constant FOO.

Related

Can I call a subclass' private method from its parent class?

After reading about Ruby's access controls, I understand that a private method may only be called, implicitly, from within a class and within that class' subclasses. I have an example, though, where a class seems to be calling a private method default_chain on its subclasses, and it still works. Check out the following code (adapted from Sandi Metz' Practical Object-Oriented Design in Ruby):
class Bicycle
attr_reader :chain
def initialize(args={})
#chain = args[:chain] || default_chain
end
def parts
{
chain: chain
}
end
end
class RoadBike < Bicycle
def parts
super.merge(
handlebar_tape_color: "red"
)
end
private
def default_chain
"21-speed"
end
end
class MountainBike < Bicycle
def parts
super.merge(
suspension: "Manitou Mezzer Pro"
)
end
private
def default_chain
"10-speed"
end
end
RoadBike.new.parts # {:chain=>"21-speed", :handlebar_tape_color=>"red"}
MountainBike.new.parts # {:chain=>"10-speed", :suspension=>"Manitou Mezzer Pro"}
What's going on?
You're getting it wrong - in your example, there is no such a thing as the parent class calling children methods.
Methods/constants name lookup in Ruby always works "bottom up": first we check if the method is defined in object's class, then in object's class's superclass and so on (this is a huge simplification because Ruby's object model is more complicated, more on this later). So, in your example things happen in roughly the following order:
When you call RoadBike.new runtime checks if there is an initialize methods defined for the class RoadBike. There is no, so we use the implementation defined for its parent class - Bycicle (but the execution context stays the same - it is still RoadBike instance)
When executing Bycicle#initialize runtime encounters another method call - default_chain. At this moment we start method name resolving in the very same manner - starting from the RoadBike context. Does RoadBike have its own implementation of default_chain? Yes, it does, so we simply call it.
The following baby example makes it crystal clear, hopefully:
class Parent
def initialize
puts "Parent Initializer is called"
a
b
end
def a
puts "Parent a is called"
end
def b
puts "Parent b is called"
end
end
class Child < Parent
def b
puts "Child b is called"
end
end
pry(main)> Child.new
Parent Initializer is called
Parent a is called
Child b is called
In reality the methods/constants resolution machinery is more complicated(includes so-called singleton classes). This is a bigger topic that will not fit nicely in SO answer, so I strongly recommend reading "Metaprogramming Ruby 2" by Paolo Perotta where this model is wery well explained in great details from the very practical point of view.

Calling Singleton Class Methods Inside Open Singleton Class

I'm trying to understand why I can't call methods defined on the singleton class from within the open class but I can from the actual class.
Can someone explain why the first example fails and the second one doesn't?
class One
class << self
def one; end
one
end
end
NameError (undefined local variable or method 'one' for #<Class:One>)
class Two
class << self
def one; end
end
self.one
end
=> nil
Your example is more confusing than it needs to be. It doesn't require a singleton class at all:
class Foo
def bar; end
bar # NameError
end
Foo.new.bar
Here, we have a class Foo with an instance method bar. A singleton class is still just a class, so this is actually the exact same example as yours.
def without an explicit definee defines an instance method of the closest lexically enclosing class definition, in this case Foo. A message send without an explicit receiver like bar sends the message to self. Inside the class definition body, self is the class itself.
So, def bar defines an instance method in Foo, i.e. a method you can call on instances of Foo.
bar inside the class definition body sends a message to self, which is Foo. Since Foo is not an instance of itself, it does not have a method named bar, ergo, the method call fails.
This works exactly the same with a singleton class, since it is still just a class.
You made the wrong assumption about where the method belongs to, in the first place. The call to the instance method one from inside class context should not succeed. In your first snippet, you try to call method one from the singleton class of the singleton class of One (because it’s called from singleton_class context).
Example with normal class / instance methods to clarify:
class One
def self.one()
puts :class
end
def one
puts :instance
end
one()
end
#⇒ class
So, the expected behavior would be to raise NameError. Now the answer is simple: it raises NameError because this method does not exist.

Namespace collision with top-level methods

I have the following Ruby namespace problem:
I have a number of top-level methods in a "library", among these I have a get_name(param) method.
The problem is that I want to use this get_name(param) method inside a class that has its own get_name() method (without param!).
Of course this results in a problem as the 2 methods are different and the new one in the class overrides the top-level one.
Is there a way to do something like this:
def get_name(param)
puts param
end
class Foo
def get_name()
puts "name"
end
def bar()
self.get_name() #should work and print name, i.e. it uses the get_name method of Foo
get_name("abc") #should work and print abc, i.e. it uses the top-level method
end
end
I would like to know if there is an easy way to achieve this without having to alter the name or scope of the top-level methods. (The goal is to have those available without modification as global methods, but still be able to call instance methods of Foo without errors.
If the library methods are really top-level methods and are not part of any class or module, then, they will get defined as private methods of Object class.
You can do following to invoke it:
def bar()
self.get_name()
Object.send(:get_name, "abc") # Will print "abc" to console
end
The so called "top level method" is only a method of main object, which is only an Object. If you want that method to be able to be called (almost) anywhere, you should make it a kernel method.
module Kernel
def get_name(param)
puts param
end
end
Note that Kernel is almost at the tail of any classes ancestors chain (before BasicObject), which means almost all the objects are a Kernel. So in your Foo class, you can override it like this:
class Foo
def get_name(*args)
return super if args.any?
puts 'name'
end
end
Edit
If you can't make those top level methods kernel methods, you can store the main object in a constant or a global variable, and call those top level methods on it.
$main = self
class Foo
def get_name(*args)
return $main.send(:get_name, *args) if args.any?
puts 'name'
end
end
First off: there is no such thing as a "top-level method". There is exactly one kind of method in Ruby: instance methods.
The method you are referring to is a private instance method of Object. Since Object is a superclass of almost any other class (excluding Object and its superclasses), if you are sure that there are no other methods with the same name somewhere else in the inheritance hierarchy, you could use Method#super_method to get access to the method and then call it:
def get_name(param)
puts param
end
class Foo
def get_name
puts 'name'
end
def bar
get_name #should work and print name, i.e. it uses the get_name method of Foo
method(:get_name).super_method.('abc') #should work and print abc, i.e. it uses the top-level method
end
end
Foo.new.bar
# name
# abc
Alternatively, if you don't know whether there are any other methods by the same name within the inheritance hierarchy, you could grab a reference to the UnboundMethod directly from Object and then bind and call it:
class Foo
def bar
get_name #should work and print name, i.e. it uses the get_name method of Foo
Object.instance_method(:get_name).bind(self).('abc') #should work and print abc, i.e. it uses the top-level method
end
end
Foo.new.bar
# name
# abc

How does 'defining a method' work semantically?

Background:
Here is what I understand about the object model (relative to my question below):
self always references the receiver in the current stack frame.
When you are in the top level and you say def someMethod the implicit receiver is self and you are creating a method which sits in the anonymous class associated with self. This anonymous class happens to sit just under Object (self is an instance of the Object class) so when you call someMethod, Ruby "takes a step to the right", and it lands in the anonymous class, thus finding and invoking your method.
This is similar to what goes on when you define methods inside of class definitions. If, when inside a class definition, you say: def self.classMethod you are creating a method in an anonymous class that sits just underneath the Class class. Methods of this class, existing "to the right" of the class currently being defined will not be visible to instances of the new class.
My Question:
How does "defining a method in a class" happen in the first place? (semantically)
Class objects aren't supposed to be different from normal objects, right?
From what I understand about message handling, Class objects have a table as a part of their state, presumable meaning it is an instance variable, that has the names of all of its instance methods. This is how the method look up works. (If Ruby doesn't find it , it goes up one and again, presumably the directions to the next link up the chain are a part of the state of the current Class object.)
Since Ruby doesn't really care about object type, I presume it doesn't care that it's looking in Class objects specifically when doing method look up. Rather, it's just following references and looking for bits of state with certain names. So, could I create my own "class objects" without using the class keyword that don't inherit from the Class class?
If that question doesn't make any sense, then I apologize. I just want to know what happens when the interpreter encounters the def keyword.
When you write 'def something' in ruby you are adding a method to a module. Sometimes that module is a 'class' (a type of module). It all depends on what 'self' is at the time:
class Foo
# right now self is 'Foo'
class << self
# right now self is 'Class:Foo'
end
def self.bar
# right now self is 'Foo'
end
end
def Foo.buz
# right now self is 'Foo'
end
obj = Foo.new
def obj.baz
# right now self is 'Foo:0x007fe8a632fa78' (an instance)
end
A class is just a type of module. Subclassing is one way of creating a pointer from One module up to another:
class Foo
end
class Bar < Foo
end
> Bar.ancestors
=> [Bar, Foo, Object, Kernel, BasicObject]
Another way is including mixins:
module Mixin
end
class Foo
include Mixin
end
> Foo.ancestors
=> [Foo, Mixin, Object, Kernel, BasicObject]
Method dispatch works on what exists in the inheritance chain. It's a list (not a tree) of parent modules and is ordered based on when the inheritance was created:
# bar.rb
module MixinA
def something
puts "MixinA"
super
end
end
module MixinB
def something
puts "MixinB"
end
end
class Base
def something
puts "Base"
super
end
end
class Sub < Base
include MixinB
include MixinA
def something
puts "Sub"
super
end
end
obj = Sub.new
obj.something
Run:
$ ruby bar.rb
Sub
MixinA
MixinB
Inspecting the chain:
> Sub.ancestors
=> [Sub, MixinA, MixinB, Base, Object, Kernel, BasicObject]
When a method call happens in walks this list looking for the method in question. If none of the modules in the chain have the method then the search starts over at the top but instead calls method_missing. In either case, the first resolution found wins.
Yehuda Katz wrote a good article on this stuff in 2009:
http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/

Get child constant in parent method - Ruby

In Ruby, is it possible to go about getting a child's constant when I've called a parent's method through the child?
Example:
class Tester
class Parent
def go
EWOCK
end
end
class Child < Parent
EWOCK = "EWOCKS rule"
end
end
Then call Tester::Child.new.go and desire "EWOCKS rule" to come back?
[Edit 3/31]
Wow I'm REALLY sorry guys. I completely screwed up the explanation.
Parent should have been Child and Child should have inherited from base.
The call should have been to Child and not Parent
Again, many apologies and thanks to those who replied attempting to understand my horrid writeup.
It is fixed now.
EDIT: this answer is correct, although Wayne's is the more ruby-ish way to approach the problem.
Yes it is.
Your implementation will not work, because the parent tries to resolve EWOK locally. Parent doesn't have EWOK defined. However, you can tell Ruby to look specifically at the class of the actual instance the method was called on, to get EWOK.
this will work:
class Parent
def go
self.class::EWOK
end
end
class Child < Parent
EWOK = "Ewoks Rule"
end
class Child2 < Parent
EWOK = "Ewoks are ok, I guess"
end
bob = Child.new
bob.go # => "Ewoks Rule"
joe = Child2.new
joe.go # => "Ewoks are ok, I guess"
what's going on here:
in Parent's 'go', "self" will refer to the instance of the object that 'go' is actually being called on. i.e., bob (a Child), or joe (a Child2). self.class gets the actual class of that instance - Child in the case of bob, or Child2 in the case of joe.
then, self.class::EWOK will retrieve EWOK from the correct class.
For a parent class to have access to a constant defined in a child class, wrap that constant in a method. Then the normal inheritance rules apply:
class Parent
def ewok
"Ewoks are lame"
end
end
class Child < Parent
def ewok
"Ewoks rule"
end
end
p Parent.new.ewok # Ewoks are lame
p Child.new.ewok # Ewoks rule
If the constant is expensive to initialize (a large hash, for example), the define it in a constant, but access it via a method:
class Parent
EWOK = {
# Enormous hash...
}
def ewok
EWOK
end
end

Resources