Confusing behaviour between class and object - ruby

Since we know that class is also an object of class Class. I have a doubt here.
I have a class defined here Foo and a method which prints the object.
class Foo
def bar
puts self
end
puts self
end
When I do Foo.new.bar o/p will be # <Foo:0x935c740>
which represents an object of class Foo.
Why not the self outside the method prints #<Class: 0x..> as its an object of class Class?
Sorry if my question is wrong but please clarify it.

Here is a little different way to define a classes/objects:
klass = Class.new {
puts self
def bar
puts self
end
}
# #<Class:0x3fbdbb8>
As you can see, it outputs #<Class:0x3fbdbb8>. So its class is Class. You can check it via class method:
klass.class
# => Class
When you name your class with uppercase letter (for example Example) for the first time, it use it as output instead of cryptic name like: #<Class:0x3fbdbb8>.
Foo = Class.new {
puts self
def bar
puts self
end
}
Still outputs cryptic name because Foo ='s part hasn't been evaluated yet.
puts Foo
Outputs correct name - Foo
What if I name it again?
Qux = Foo
# => Foo
Nothing. Foo will be Foo forever.

Names of classes and modules are constant in ruby. So when you are defining a class you are creating an object of class Class and providing it with a constant name and hence when you do a puts self in a class context, it gives a class name instead of something like #<Class: 0x..>

Related

ruby .extend help needed

given
module Foo
def bar
puts "foobar"
end
end
I can do
String.extend(Foo)
and as a consequence do
String.bar # => "foobar"
Why doesnt this work?:
a = String.new
a.bar # => NoMethodError: undefined method `bar' for "":String
Is it because 'a' is now and instance and .extend only works against class methods? Why does it lose the 'new' functionality I have given String via .extend?
Ruby allows you to add methods from a Module to a Class in two ways: extend and include.
Using the module you gave:
module Foo
def bar
puts "foobar"
end
end
With extend the methods are added as class methods, and can be called directly on the class object itself:
class Bar
extend Foo
end
Bar.bar # => "foobar"
Alternatively, you can call it outside of the class scope:
class Bar
end
Bar.extend Foo
Bar.bar # => "foobar"
include is slightly different. It will add the methods as instance methods. They are only callable on an instance of the class:
class Bar
include Foo
end
Bar.bar # NoMethodError
a = Bar.new
a.bar # => "foobar"
The key difference was that we first had to make an instance a, before we could call the instance method.
As sepp2k noted, extend is can be called on any Object, not just Class objects. For example, you can go:
class Bar
end
a = Bar.new
a.extend Foo
a.bar # => "foobar"
However, bar will only be added to the single instance a. If we create a new instance, it you will not be able to call it.
b = Bar.new
b.bar # => MethodNotFoundError
In Ruby, class String is an object, and by doing String.extend(Foo), you create a singleton class for the String class object and include the module Foo in it (that means that you are adding class methods to the String class object, and so can call String.bar). Full stop.
a.bar doesn't work because there's no instance method bar.
No, you haven't given new to String via extend.
The Object#extend method adds to the receiver the methods defined by the argument module.
You have to remember that the String class is itself an object (of type Class) and so when you call "extend" with it as the receiver, that class object (String) itself gets the new method.
So in your first example, String.extend(Foo), adds to the String class instance the function "bar". That is, "bar" is now an instance method of the shadow class (aka Singleton class), so the object String (which is a class) now has the method "bar". This has roughly the same effect as adding a class method to the String class (e.g. def String.bar; puts 'foobar'; end), so it has no effect on instances of type String.

# used inside a self method is doing what exactly?

I saw this in some code today.
class Foo
def self.bar
#myvar = 'x'
end
end
What exactly is this accessing? As far as I can tell, this isn't accessible form instance methods. What's this called (something google-able) as I cant seem to find examples of this anywhere else.
The #myvar syntax identifies myvar as an instance variable so the real question is this:
What is self inside a class method?
And the answer is "self is the class object". So, #myvar is an instance variable of the Foo class object. If you add another class method:
class Foo
def self.pancakes_house
#myvar
end
end
And then do this:
Foo.bar
puts Foo.pancakes_house
You'll see x on the standard output.
A class is also an object, so you are setting a instance variable in class Foo.
>> Foo.bar
>> Foo.instance_variable_get("#myvar")
=> 'x'
Now, for a typical use, add class << self; attr_accessor :myvar; end to your class and you can write:
>> Foo.bar
>> Foo.myvar
=> 'x'
For googling, this is sometimes called a "class instance variable". That is, an instance variable of an object that just happens to be a class.

Class Method to 'Know' Class Name in Ruby?

I want an inherited ruby class to 'know' its class name via a class method. This is best illustrated by a contrived example:
class Parent
def self.whoami
??
end
end
class Child < Parent
#No code should be needed.
end
So I should be able to call:
Parent.whomai
and expect a return of "Parent" I should then be able to call:
Child.whoami
and expect a return of "Child" I have a feeling that in conventional languages this might not be possible. But Ruby's metaprogramming model has amazed me before. Any thoughts? Thanks in advance.
A Class Method is a method where the CLASS is the receiver, so to find the object upon which the method is invoked (what you appear to be trying to do here) simply inspect the value of self.
class Parent
def self.whoami
self
end
end
class Child < Parent
end
puts Parent.whoami #=> Parent
puts Child.whoami #=> Child
The method to get the name of a class (module, actually) is just Module#name. There's no need to write your own:
Parent.name # => 'Parent'
Child.name # => 'Child'
However, in Ruby, there really is no such thing as a "class name" as there is in some other languages. In Ruby, a class is simply an object like any other object which gets assigned to a variable like any other variable.
All the Module#name method does is loop through all the constants in the system and check whether the module has been assigned to any one of them, and return that constant's name or nil if it cannot find any.
So, just like any other object, the "name" of a class is really nothing but whatever variable you use to refer to it.
Example:
foo = Class.new
foo.name # => nil
Now, the "name" of the class is foo. However, Module#name returns nil, because foo is not a constant.
bar = foo
bar.name # => nil
Now, the "name" of the class is both foo and bar, but Module#name obviously still returns nil.
BAZ = foo
foo.name # => 'BAZ'
Now, since the class has been assigned to a constant, that constant's name will be considered that class's name …
BAZ = nil
foo.name # => 'BAZ'
… even after the constant has been assigned to something different and …
QUX = foo
QUX.name # => 'BAZ'
… even after the class has been assigned to a different constant.
Module#to_s uses Module#name if it is not nil, so, to print the name of a class, you simply do
puts Parent
There's really absolutely no need for all the complex fluff in the other answers.
Isn't that what Parent.class will tell you?
class Parent
def self.whoami
self.to_s
end
end
class Child < Parent
end
> Parent.whoami
=> "Parent"
> Child.whoami
=> "Child"
Suppose you class:
class ABC
def self.some_method
self.name #it will return 'ABC'
self.name.constantize #it will return ABC
end
end

How do I access the string name of the parent class from a class method in a extended class or included module

My problem basically looks like this:
module Foo
class Bar
def self.who
self.class.to_s
end
end
end
class World < Foo::Bar
end
When I call World.who I don't get "World" as a result, I get "Class". Some quick Googling didn't yield anything useful, so hence I'm here hoping someone will know how to get the correct class name :)
If you're calling foo.bar then inside the bar method the value of self will be foo. So when you call World.who the value of self inside who is World. Since World is a class, World.class will return Class, so that's what you get.
To get back "World" just call self.to_s or self.name (or just to_s or name).
You get that because World is a Class. In ruby, AClass.class != AClass. So, you could use this:
module Foo
class Bar
def self.who
to_s
end
end
end
class World < Foo::Bar
end

In Ruby are there any related applications of the syntax: class << self ... end

class << self
attr_accessor :n, :totalX, :totalY
end
The syntax above is used for defining class instance variables. But when I think about what syntax implies, it doesn't make any sense to me, so I'm wondering if this type of syntax is used for any other types of definitions. My point of confusion here is this:
class << self
The append operator normally means "add what's on the right to the object on the left". But in the context of this block, how does that add up to "put the contents of this block into the definition of the class instance rather than the instance"?
For the same reason I'm confused as to why in one context class << self can define class instance variables while in another it seems to create class variables such as here:
class Point
# Instance methods go here
class << self
# Class methods go here
end
end
in Ruby you can reopen existing classes and add methods. That is, you can say:
class Foo
def bob
return "hello from bob"
end
end
these methods get stored somewhere in an internal dictionary (maybe an instance variable) of the Foo-class (which is just an instance of the Class-class and therefore has instance variables)
But the suprising thing is, that you can also add methods to instances of existing objects
foo = Foo.new
foo2 = Foo.new
def foo.fred
return "I am fred"
end
foo.fred #=> "I am fred"
foo2.fred #=> NoMethodError
but Where is this method actually stored?
Turns out Ruby creates a new class behind the scenes (sometimes called singleton class, metaclass or eigenclass) which gets inserted in the inheritance heirarchy between the Foo-class and its instance.
So the inheritance relationship looks like that:
foo < (eigenclass of foo) < Foo < Class
(if you say foo.superclass you will not see the singleton class)
the class << X-syntax is a way to get to this special class, so that you can manipulate it directly. The following code blocks are exactly equivalent:
def foo.bar
return "xy"
end
# is exactly the same as
class << foo
def bar
return "xy"
end
end
So the similarity between class Foo < Bar and class << Foo is not accidental, there is inheritance going on in both.
Think of class << X as "open up the metaclass of X"
The thing to remember in Ruby is that classes themselves are just objects. (Instances of the class Class) so if you say:
class Foo
class << self
def k
return "x"
end
end
end
(self is bound to Foo in this code block) so k is an instance method of the eigenclass of Foo, which makes it a class method for Foo
all this is explained more clearly in the chapter about classes of the Pickaxe (the web version does not contain the diagrams, unfortunately) and _whys Seeing Metaclasses Clearly
Think of the class as containing a dictionary of members including all the accessors and instance variables. When you tell the class to "append" to "itself", you're saying "add these to the dictionary of class members."
I'll grant the notation is a little hinky, though.
it's actually confusing to think of it in terms of an "append" operator. a better way to look at it is that just as class Foo opens up class Foo, that is, it sets 'self' to the class object Foo, creating it if necessary, so class << self opens up the eigenclass of the current 'self' object. note that it is not limited to self - for any object bar, you can say class << bar to open up the eigenclass of that object.
class A
def hello
print "hello world"
end
end
a = A.new
b = A.new
class << a
def goodbye
print "goodbye cruel world"
end
end
a.hello
b.hello
a.goodbye
b.goodbye

Resources