Why can't we initialize TrueClass in Ruby? I get this:
TrueClass.new # => NoMethodError: undefined method `new' for TrueClass:Class
But, superclass of TrueClass is Object.
Similarly we are unable to initialize NilClass and FalseClass
I just wanted to know how that is possible even if that is the child class of Object. If we wanted to write a class similar to this how can we achieve it?
I just wanted to know how that is possible even if that is the child class of Object. If we wanted to write a class similar to this how can we achieve it?
You can undefine inherited methods using the undef keyword. Since new is a class method, you'll have to use undef inside the class's singleton class. That would look like this:
class <<MyClass
undef new
end
MyClass.new # NoMethodError: undefined method `new' for MyClass:Class
I just wanted to know how that is possible even if that is the child class of Object.
It works by undefining allocate and new. Here's the corresponding C code:
rb_undef_alloc_func(rb_cTrueClass);
rb_undef_method(CLASS_OF(rb_cTrueClass), "new");
You can achieve a similar result in Ruby via undef_method:
class FooClass
::FOO = new # <- this will be the only Foo instance
class << self
undef_method :allocate
undef_method :new
end
end
FooClass.new #=> NoMethodError: undefined method `new' for FooClass:Class
FooClass.allocate #=> NoMethodError: undefined method `allocate' for FooClass:Class
FOO #=> #<FooClass:0x007fddc284c478>
"similar", because TrueClass.allocate doesn't actually raise a NoMethodError, but a TypeError:
TrueClass.allocate #=> TypeError: allocator undefined for TrueClass
Unfortunately, rb_undef_alloc_func is not available from within Ruby. We could mimic the behavior by overriding allocate:
class FooClass
class << self
def allocate
raise TypeError, "allocator undefined for #{self}"
end
undef_method :new
end
end
FooClass.allocate #=> TypeError: allocator undefined for FooClass
Not sure, which approach is cleaner.
The above changes prevent you from creating an instance via new, but there are other ways:
FOO #=> #<FooClass:0x007fddc284c478>
FOO.dup #=> #<FooClass:0x007fad721122c8>
FOO.clone #=> #<FooClass:0x007f83bc157ba0>
Marshal.load(Marshal.dump(FOO)) #=> #<FooClass:0x007f83bc13e330>
To account for all these special cases, Ruby' stdlib provides the Singleton module:
require 'singleton'
class Foo
include Singleton
end
It works by making allocate and new private methods: (among other changes)
Foo.new #=> NoMethodError: private method `new' called for Foo:Class
Foo.allocate #=> NoMethodError: private method `new' called for
And it adds instance which returns an instance: (or the instance, there's only one)
Foo.instance #=> #<Foo:0x007fdca11117e8>
Related
Imagine I want to write my own math operators like "+"
The simple version would be:
def plus(a,b)
return a+b
end
But this is not what the real "+" does.
I want 3.add(4) # =>7
But how do I tell ruby to take the object that I used my method on?
I tried
def add(c)
return self+c
end
But I get the error message:
:in <main>': private methodadd' called for 3:Fixnum (NoMethodError)
The problem
You defined the method:
def add(c)
return self + c
end
and attempted to use it thus:
3.add(4) #=> NoMethodError: private method `add' called for 3:Fixnum
Understanding this error message
This error message tells you exactly what the problem is. I think your problem is simply that you don't understand how Ruby invokes methods on objects.
When Ruby sees 3.add(4) it first looks at the receiver, 3, and determines:
3.class #=> Fixnum
This tells it where the method add is defined: in the class Fixnum or in one of Fixnum's ancestor's classes or modules.
So it looks for it there, doesn't find it, and issues an error message. We can confirm it's not there:
Fixnum.instance_methods.include?(:add)
#=> false
So where is add defined?
You did define it, though, so where is it? Let's find out:
method(:add).owner
#=> Object
Object.instance_methods.include?(:add)
#=> false
Object.instance_methods returns an array of all of public instance methods defined on Object and Object's ancestors. add is not among those, so we conclude add is a protected or private method:
Object.protected_instance_methods.include?(:add)
#=> false
Object.private_instance_methods.include?(:add)
#=> true
Let's try invoking that method on an instance of Object:
Object.new.add(4)
#=> NoMethodError:
# private method `add' called for #<Object:0x007fdb6a27fa68>
That makes sense, considering that Object#add is private. We can, however invoke private methods with Object#send:
Object.new.send(:add,4)
#NoMethodError: undefined method `+' for #<Object:0x007fdb6a28e068>
As an exercise, make sure you understand the steps Ruby took that led to her raising this exception (that the instance method + is not defined on Object, or equivalently, that the instance of Object does not have a method +).
By the way, where did you define add? By that, I mean what what was the value of self when you defined it? Let's see:
self #=> main
self.class #=> Object
We see that add must be defined on the class for which its receiver is an instance. (A mouthful, yes, but it's important, so make sure you understand that).
Why is Object#add private rather than public?
Consider:
def greet
puts 'hi'
end
class A
end
A.private_instance_methods.include?(:add)
#=> true
A.new.send(:greet)
#=> 'hi'
The is because A inherits greet from Object:
A.ancestors.include?(Object) #=> true
If Object#greet were public, every built-in class and every class you define would have a public instance method greet. That would result in a great deal of misery. (Suppose you had a method great and mistyped it greet!) Even the private greet could cause trouble.)
Where should add be defined?
Since add.class => Fixnum, we define it thus:
class Fixnum
def add(other)
self + other
end
end
Fixnum.instance_methods.include?(:add) #=> true
3.add(4) #=> 7
Had I included the line puts "self#{self}" after class Fixnum it would have printed "Fixnum". Salting your code with puts statements that show the value of self often helps in understanding what's going on.
One last thing:
method(:add).owner
#=> NameError: undefined method `add' for class `Object'
Why did this not return Fixnum? Since method has no explicit receiver (i.e., no xx.method), Ruby assumes the receiver to be self, which here is:
self #=> main
so she looks for the method method in self.class => Object, and you know what she finds (or, I should say, doesn't find). Instead, we need to write:
Fixnum.instance_method(:add).owner #=> Fixnum
or
3.method(:add).owner #=> Fixnum
Here 3 can of course be replaced by any instance of Fixnum.
Note I've simplified this explanation somewhat. In searching for a method, Ruby also looks in the receiver's singleton class. This is not an issue for immediate objects (numbers, symbols, true, false and nil), however, as they do not have singleton classes:
3.singleton_class #=> TypeError: can't define singleton
By contrast, for example:
[1,2].singleton_class #=> #<Class:#<Array:0x007fbcf18c01a8>>
The plus-sign (+) in ruby can be overridden pretty much like any other method (you can look for operator-overloading):
class MyOperator
attr_accessor :text
def initialize(text)
#text = text
end
def +(operand)
"#{self.text} #{operand.text}"
end
def to_s
self.text
end
end
a = MyOperator.new "Hello"
b = MyOperator.new "World"
puts (a+b)
So there is not much magic to it. But you have to be careful if the overloading the operators make sense in your context.
Newbie question.
I assumed that "inheritance" is the basic feature of Ruby. And every class inherits methods from both its .class and .superclass.
Since NilClass has Class and Object as its .class and .superclass, you'd assume NilClass to have all their methods.
Then my brain exploded when I saw this:
>> NilClass.class
=> Class
>> NilClass.class.methods - NilClass.methods
=> [:nesting, :new]
>> NilClass.superclass
=> Object
>> NilClass.superclass.methods - NilClass.methods
=> [:new]
What is going on?
Can anyone explain what's really going on underlying the whole inheritance mechanism in Ruby?
What does inheritance really mean in Ruby?
I assumed that "inheritance" is the basic feature of Ruby. And every class inherits methods from both its .class and .superclass.
That's correct. Every class inherits methods from its superclass, which is Object by default.
class Foo
end
Foo.superclass #=> Object
Foo responds to Object's class methods and Foo instances respond to Object's instance methods.
Furthermore, every class is an instance of Class and therefore responds to Class' instance methods (just like Foo instances respond to Foo's instance methods):
Foo.class #=> Class
Foo.method(:new)
#=> #<Method: Class#new>
Calling Foo.new simply invokes Class#new.
Since NilClass has Class and Object as its .class and .superclass, you'd assume NilClass to have all their methods.
It would, but nil is a singleton, i.e. there's only one nil instance and you can't create any other instances. This is achieved (among other things) by undefining new. From Ruby's source code:
rb_undef_method(CLASS_OF(rb_cNilClass), "new");
You could do the same in plain Ruby:
Foo.singleton_class.send(:undef_method, :new)
Foo.new
#=> NoMethodError: undefined method `new' for Foo:Class
I have this Ruby code where I try to implement the Singleton pattern manually:
class A
#a = A.new
def self.instance
p 'initialized'
#a
end
private_class_method :new
end
A.instance #=> prints 'initialized'
Unfortunately, the object will be created before A.instance is even called. To avoid this, I thought of changing the code:
class A
#a = nil
def self.instance
p 'initialized'
#a ||= A.new
end
private_class_method :new
end
A.instance
I get "private method `new' called for A:Class (NoMethodError)" error though. This is very puzzling, why do I get this error in the second example and not in the first? The only difference is that in the second example .new is called in a class method definition. I deliberately put private_class_method on the bottom so this kind of error is prevented (putting it on the top will give the error for both examples). Btw, I'm aware this will work if I change #a from being a class instance variable to a class variable (to start with ##). I don't understand why this would work, since I know instance variables are relative to SELF and SELF is the class, both where I initialize #a to nil and where I lazy instantiate it in self.instance.
Here is a strange thing.
A.new doesn't work because you should call private method only directly, so you should use explicit new call.
In the other hand new call is something like implicit self.new but self.new will raise an exception like A.new. And this is the strange part I don't understand
class A
def self.instance
p 'initialized'
# ok
new
# should be ok but it is not
self.new rescue p("error self.new: #{$!}")
# should fail
A.new rescue p("error A.new: #{$!}")
end
private_class_method :new
end
A.instance
# "initialized"
# "error self.new: private method `new' called for A:Class"
# "error A.new: private method `new' called for A:Class"
PS: http://weblog.jamisbuck.org/2007/2/23/method-visibility-in-ruby
You can't use explicit receiver with private methods
SO: Understanding private methods in Ruby
When I tried fixnum.new is giving undefined method error.
Fixnum.new # undefined method `new' for Fixnum:Class (NoMethodError)
Why its give undefined method. What mechanism behind the fixnum class. please explain.
If I want to make some class like fixnum (A class without new method) then what should I do?
I am going with below code but I am feeling its bad code.
class TestClass < Fixnum
end
When I tried to create new object like below:
TestClass.new #undefined method `new' for TestClass:Class
is this correct way? or if you have another way please explain here.
As I explained in this answer, Fixnum doesn't provide a .new method. That's because you expect to create a new Fixnum (or a descendant such as Integer or Float) in the following way
1.3
1
and because, despite they are objects, there are no multiple instances of a Fixnum. In the same answer I also explained how you can use a proxy class around objects that doesn't offer such initialization.
Here's a code example
class MyFixnum < BasicObject
def initialize(value)
#fixnum = value
end
def inc
#fixnum + 1
end
def method_missing(name, *args, &block)
#fixnum.send(name, *args, &block)
end
end
m = MyFixnum.new(1.3)
m.to_i
# => 1
If I got your question right, you are trying to write a class that is not instantiatable using the new method. You could borrow the idea from the Singleton module and make the new (and allocate) method private:
class Whatever
private_class_method :new, :allocate
end
Whatever.new
# NoMethodError: private method `new' called for Whatever:Class
Because there are Fixnum objects for every (and only) integer value. No other objects should be created. Therefore inheriting from Fixnum is, probably, not a good idea.
You may want to use composition instead:
class TestClass
attr_reader :num # fixnum
end
Was planning on using factory method to get singleton instance of a ruby class, but I'm not sure if its going to work with Ruby garbage collection.
EG if I have something like:
class Foo
def self.getInstance
##instance = Foo.new if #instance.nil?
return ##instance
end
def counter
#counter
end
def increment
#counter++
end
private
def initialize
#counter = 0
end
end
So the way this works in other languages I'm familiar with that the #instance survives garbage collection indefinitely, so that you Foo.getInstance.increment could be relied to have a continuiously ascending counter for the lifetime of the program.
However, I'm not sure what might be holding on to a reference to the the class's instance variable ##instance so will it get garbage collected?
##instance is a class var, not an instance var. The class holds a references to its class vars which prevents their garbage collection until the class itself is undefined.
Please don't roll your own singleton pattern. The stdlib has a module Singleton which you can mixin to your class to make it a singleton. The stdlib mixin looks after details you've forgotten, such as the thread safety of initialization and undefining new.
Make an instance method 'foo' and an instance variable with the same name as the method '#foo' use the singleton operator ||= to assign or fetch an instance of Foo, If you do this from a class method you have produced a memory leak
def foo
#foo ||= Foo.new
end
The Singleton class is where object methods go when they're specific to that object, and each object may hold or holds such a class.
1.9.3p374 :315 > Jd = class<<self;self;end
=> #<Class:#<Object:0x007ff304078d08>>
1.9.3p374 :316 > jd = Jd.new
TypeError: can't create instance of singleton class
from (irb):316:in `new'
from (irb):316
from /Users/rfatahi/.rvm/rubies/ruby-1.9.3-p374/bin/irb:16:in `<main>'
1.9.3p374 :317 > Jd.class
=> Class
Adding method to Singleton class:
1.9.3p374 :318 > class MyClass
1.9.3p374 :319?> end
=> nil
1.9.3p374 :320 > a = MyClass.new
=> #<MyClass:0x007ff30605b530>
1.9.3p374 :321 > def a.method1
1.9.3p374 :322?> end
=> nil