2
class Object
  attr_reader :foo
  def initialize
    @foo = 'bar'
  end
end

Object.new.foo # => 'bar'
''.foo # => nil
//.foo # => nil
[].foo # => nil

I want them all to return 'bar'

Am aware that you can do this already:

class Object
  def foo
    'bar'
  end
end

But I specifically want to initialize a state variable. Also note that this doesn't work.

class String
  alias_method :old_init, :initialize
  def initialize(*args)
    super
    old_init(*args)
  end
end

class Object
  attr_reader :foo
  def initialize
    @foo = 'bar'
    super
  end
end

''.foo # => nil

Nor does this:

class String
  attr_reader :foo
  def initialize
    @foo = 'bar'
  end
end

''.instance_variables # => []

I'm beginning to think that this isn't actually possible.

1
  • 1
    The reason this isn't working for you is that all those other classes that inherit from object override initialize, and don't bother to invoke the superclass's version of it. Commented May 27, 2009 at 13:21

3 Answers 3

5

This is possible.

class Object
  class << self
    Kernel.send :define_method, :foo do #Object.send to be more restrictive
      @foo = 'bar'
    end
  end
end

.

irb(main):023:0> class Object
irb(main):024:1> class << self
irb(main):025:2> Kernel.send :define_method, :foo do 
irb(main):026:3* @foo = 'bar'
irb(main):027:3> end
irb(main):028:2> end
irb(main):029:1> end
=> #<Proc:0x00007f5ac89db168@(irb):25>
irb(main):030:0> x = Object.new
=> #<Object:0x7f5ac89d6348>
irb(main):031:0> x.foo
=> "bar"
irb(main):032:0> [].foo
=> "bar"
irb(main):033:0> //.foo
=> "bar"

It's important to understand eigenclasses. Every class is implemented mysteriously by the Ruby interpreter as a hidden class type:

irb(main):001:0> class Object
irb(main):002:1>   def eigenclass
irb(main):003:2>     class << self; self; end
irb(main):004:2>   end
irb(main):005:1> end
=> nil
irb(main):006:0> x = Object.new
=> #<Object:0x7fb6f285cd10>
irb(main):007:0> x.eigenclass
=> #<Class:#<Object:0x7fb6f285cd10>>
irb(main):008:0> Object.eigenclass
=> #<Class:Object>
irb(main):009:0> Object.class
=> Class

So, in your example, when you're trying to call foo on your objects, it's operating on the class #<Object:0x7fb6f285cd10>. However, what you want it to operate on is the secret class #<Class:#<Object:0x7fb6f285cd10>>

I hope this helps!

Sign up to request clarification or add additional context in comments.

Comments

4

If the thing you're trying to return (here, 'bar') requires much more setup cost than a small String, you could use the memoized version of HermanD's answer:

class Object
  def foo
    @foo ||= begin
      'bar' # something far more complicated than just "'bar'"
    end
  end
end

You could even use the memoization for cheap stuff like Strings if you really need the instance variable to be set (for some reason that I can't quite think of at them moment):

class Object
  def foo
    @foo ||= 'bar'
  end
end

2 Comments

+1, but this wont work if you invoke instance_variable_get before using the accessor, it's interesting that you can't rely on Object's #initialize.
boy, that's a pretty awkward case, but I have no doubt that some obscure library will call into this and it will blow up and you'll go, "WTF?"
0

It's not an instance variable, but will meet the requirements of your example

class Object
  def foo
    'bar'
  end
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.