# Accessing private member by subclassing

**URL:** <https://www.ruby-forum.com/t/accessing-private-member-by-subclassing/85251>\
**Category:** Rails\
**Created:** [February 12, 2007, 12:29am UTC](https://www.ruby-forum.com/t/accessing-private-member-by-subclassing/85251 "2007-02-12T00:29:59Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![richard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/f0a364/32.png) [@richard](https://www.ruby-forum.com/u/richard)\
**Post date:** [February 12, 2007, 12:29am UTC](https://www.ruby-forum.com/t/accessing-private-member-by-subclassing/85251/1 "2007-02-12T00:29:59Z")

</div>

Hi All,

SCENARIO: I took an example from Ruby Cookbook which had a private  
method ‘secret’.  
‘secret’ returned the value of @secret initialized to a random value.

I created a subclass whose initializer called super and accessed  
secret to save its returned-value in a instance variable, which I then  
displayed. It matched the value I dumped when the parent class was  
initialized. Success!

However, I tried a alternative approach, which failed — which is my  
reason for posting this.

I created a public method ‘spy’ in the parent class and returned the  
value @secret, just like the private method ‘secret’ did. I then  
invoked spy from a subclass instance, but it returned nil.

QUESTION: Why does subclass.spy return nil?

Code follows.

Thanks in Advance,  
Richard

=========== SecretNumber.rb ====================

# Source: Ruby Cookbook, p. 371-373

class SecretNum  
def initialize  
@secret=rand(20)  
puts “@secret \<= #{@secret}”  
end

def hint  
puts "The number is #{“not " if secret\<10}greater than 10”  
end

private  
def secret  
@secret  
end

public  
def spy  
@secret  
end  
attr\_reader :spy  
end

=========== SecretNumber\_AccessInSubclass.rb ===================

# SecretNumber\_AccessInSubclass.rb

require ‘SecretNumber.rb’

class NotSoSecretNum \< SecretNum  
def initialize  
super  
@theNum = secret  
end

attr\_reader :theNum

end

s = NotSoSecretNum.new  
puts "theNum reveals “secret” = " + s.theNum.to\_s  
puts "secret reveals “secret” = " + ““s.secret” not accessible”  
puts "spy reveals “secret” = " + s.spy.inspect.to\_s

========= Results ==============  
@secret \<= 3  
theNum reveals “secret” = 3  
secret reveals “secret” = “s.secret” not accessible  
spy reveals “secret” = nil

---

<div class="post-metadata">

**Author:** ![richard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/f0a364/32.png) [@richard](https://www.ruby-forum.com/u/richard)\
**Post date:** [February 12, 2007, 1:14am UTC](https://www.ruby-forum.com/t/accessing-private-member-by-subclassing/85251/2 "2007-02-12T01:14:12Z")

</div>

Richard wrote:

> def spy  
> @secret  
> end  
> attr\_reader :spy
> 
> puts "spy reveals “secret” = " + s.spy.inspect.to\_s  
> #=\> nil

The problem looks like its with attr\_reader. attr\_reader creates that  
accesses an instance variable. The instance variable and the method  
have the same name. So basically, what you are doing is this:

#the method you wrote  
def spy  
@secret  
end

#what attr\_reader does for you  
def spy  
@spy  
end

Now you have 2 methods named “spy”. When the second method called “spy”  
is declared, the first one is overriden, it’s gone. And since @spy has  
not been set to anything it just returns nil.

So get rid of:

attr\_reader :spy

and it should work fine.

---

<div class="post-metadata">

**Author:** ![richard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/f0a364/32.png) [@richard](https://www.ruby-forum.com/u/richard)\
**Post date:** [February 12, 2007, 2:35pm UTC](https://www.ruby-forum.com/t/accessing-private-member-by-subclassing/85251/3 "2007-02-12T14:35:04Z")

</div>

Hi Alex,

Fantastic reply!

You not only told me what action to take to get my intended result,  
but more importantly WHY my code failed. I never really gave much  
thought to what attr\_reader REALLY meant.

Thank you very much.

Best wishes,  
Richard

On Feb 11, 7:14 pm, Alex W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![richard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/f0a364/32.png) [@richard](https://www.ruby-forum.com/u/richard)\
**Post date:** [February 12, 2007, 3:06pm UTC](https://www.ruby-forum.com/t/accessing-private-member-by-subclassing/85251/4 "2007-02-12T15:06:09Z")

</div>

Hi again Alex,

After thinking further about my mistaken use of attr\_reader, I  
wondered why I had never learned the details about it before. So I  
perused Hal F.'s “The Ruby Way, Second Edition” and found, on page  
391, precisely the explanation you gave me. Clearly, I have not done  
my homework 🙂

I mention this primarily for the benefit of anybody else who might  
read this thread.

Best wishes,  
Richard

On Feb 11, 7:14 pm, Alex W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![richard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/f0a364/32.png) [@richard](https://www.ruby-forum.com/u/richard)\
**Post date:** [February 12, 2007, 4:00pm UTC](https://www.ruby-forum.com/t/accessing-private-member-by-subclassing/85251/5 "2007-02-12T16:00:19Z")

</div>

Hi Alex,

Just one more question, if I may:

Hal F. say “attr\_reader theNum” creates theNum [an instance  
method, right?] and @theNum [an instance variable, right?].

However, the initialize method creates and initializes @theNum.

So, which of the following occurs?

(1) the initialize method creates/initializes @theNum first and  
attr\_reader acknowledges @theNum’s existence and restricts its  
creation to theNum method; or

(2) the initialize method gets scanned but not executed, so  
attr\_reader does both creations and then the initialize method  
initializes the existing @theNum instance variable.

The closest thing I’ve found on this issue is “compile” in Pickaxe 2nd  
Edition, which applied to Regexp’s, not compiling/interpreting Ruby  
source code.

Thanks in advance for any documentation you can point me to or any  
ideas you have on this question.

Yours truly,  
Richard

On Feb 11, 7:14 pm, Alex W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![richard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/f0a364/32.png) [@richard](https://www.ruby-forum.com/u/richard)\
**Post date:** [February 12, 2007, 6:32pm UTC](https://www.ruby-forum.com/t/accessing-private-member-by-subclassing/85251/6 "2007-02-12T18:32:06Z")

</div>

Richard wrote:

> Hi Alex,
> 
> Just one more question, if I may:
> 
> Hal F. say “attr\_reader theNum” creates theNum [an instance  
> method, right?] and @theNum [an instance variable, right?].

I assume you mean:

attr\_reader :theNum

> However, the initialize method creates and initializes @theNum.
> 
> So, which of the following occurs?
> 
> (1) the initialize method creates/initializes @theNum first and  
> attr\_reader acknowledges @theNum’s existence and restricts its  
> creation to theNum method; or

attr\_reader reads only, not creates.

> (2) the initialize method gets scanned but not executed, so  
> attr\_reader does both creations and then the initialize method  
> initializes the existing @theNum instance variable.

You’re getting hung up on who creates what and has access to who and  
it’s much simpler than that. Take this class:

class Foo  
attr\_reader :bar

```
def initialize(value)
  @bar = value
end

```

end

foo = Foo.new(‘abc’)  
foo.bar #=\> “abc”

When you call “Foo.new(‘abc’)” you are invoking the initialize method,  
this sets the @bar variable. When you call “bar” you just retrieve  
whatever the valid of @bar is at that moment.

And attr\_reader gives you an instance method, meaning it’s only on  
instances of class Foo created with: Foo.new(‘abc’). And in this  
example you cannot instantiate the Foo class without running the  
initialize method that sets up @bar.

So the “bar” method doesn’t acknowledge or restrict anything. It simply  
fetches whats in @bar whether it’s there or not. As a result it doesn’t  
care what else is going in your class at all. you can have a class like  
this and it will work fine, except always return nil.

class Bar  
attr\_reader :foo  
end

bar = Bar.new  
bar.foo #=\> nil

The final thing to keep in mind is that instance variable like @bar are  
the only kind of variable that will never give you undefined or  
uninitialized errors. So if it’s not initialized it will just give you  
nil, unlike class of or local variables that will raise an exception:

irb(main):001:0\> foo  
NameError: undefined local variable or method `foo’ for main:Object  
from (irb):1  
from :0  
irb(main):002:0\> @foo  
=\> nil  
irb(main):003:0\> @@foo  
NameError: uninitialized class variable @@foo in Object  
from (irb):3  
from :0

One last example:

class Bam  
attr\_reader :foo

```
def set_foo
  @foo = 'abc123'
end

```

end

bam = Bam.new  
bam.foo #=\> nil  
bam.set\_foo  
bam.foo #=\> “abc123”

I think all that answers your question.

---

<div class="post-metadata">

**Author:** ![richard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/f0a364/32.png) [@richard](https://www.ruby-forum.com/u/richard)\
**Post date:** [February 13, 2007, 1:47am UTC](https://www.ruby-forum.com/t/accessing-private-member-by-subclassing/85251/7 "2007-02-13T01:47:43Z")

</div>

Hi Alex,

I responded earlier to your last post, but my response got lost in  
cyber-space. Here is a new response, which hopefully is better  
written than the lost one.

> I assume you mean:
> 
> attr\_reader :theNum

Yes, I omitted the colon ☹ You’ve got eagle-eyes 🙂

> I think all that answers your question.

It sure does. Thanks a lot. I really like to nail down these kinds  
of details.

I put together my list of examples based on the your ideas, which I  
provided below. They satisfy me that:

1. “attr\_reader :foo” is equivalent to “def foo; @foo; end” (as you  
said originally)

I think examples 2a and b (and 4, 5 and 6, as well) demonstrate that.

1. “@foo” yields nil when it’s undefined. Occam’s razor suggests that  
a method returning @foo’s value:  
a) returns nil when @foo is undefined (as you also said); rather  
than  
b) creates @foo with an initial nil value when @foo is undefined, and  
then returns @foo’s nil value.

In short, I signed onto your ideas, and now proclaim them as mine,  
too :-).

Best wishes,  
Richard

===== My humble examples ====  
class FooBar1  
end

class FooBar2a  
attr\_reader :foo  
end

class FooBar2b  
def foo  
@foo  
end  
end

class FooBar3  
attr\_reader :foo

def set\_foo(parm)  
@foo = parm  
end  
end

class FooBar4  
def set\_foo(parm)  
@foo = parm  
end

attr\_reader :foo  
end

class FooBar5  
def set\_foo(parm)  
@foo = parm  
end

def foo  
@foo  
end  
end

class FooBar6  
def set\_foo(parm)  
@foo = parm  
end

def foo; @foo; end  
end

fb1 = FooBar1.new

# puts fb1.foo # ==\> undefined method `foo’ for #\<FooBar1: …

fb2a = FooBar2a.new  
puts "fb2a.foo = " + fb2a.foo.inspect # ==\> nil

fb2b = FooBar2b.new  
puts "fb2b.foo = " + fb2b.foo.inspect # ==\> nil

fb3 = FooBar3.new  
puts "fb3.foo = " + fb3.foo.inspect # ==\> nil  
fb3.set\_foo “some-value”  
puts "fb3.foo = " + fb3.foo # ==\> some-value

fb4 = FooBar4.new  
fb4.set\_foo “another-value”  
puts "fb4.foo = " + fb4.foo # ==\> another-value

fb5 = FooBar5.new  
fb5.set\_foo “a third value”  
puts "fb5.foo = " + fb5.foo # ==\> a third value

fb6 = FooBar6.new  
fb6.set\_foo “a fourth value”  
puts "fb6.foo = " + fb6.foo # ==\> a fourth value

On Feb 12, 12:32 pm, Alex W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![richard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/f0a364/32.png) [@richard](https://www.ruby-forum.com/u/richard)\
**Post date:** [February 13, 2007, 2:20am UTC](https://www.ruby-forum.com/t/accessing-private-member-by-subclassing/85251/8 "2007-02-13T02:20:24Z")

</div>

Richard wrote:

> In short, I signed onto your ideas, and now proclaim them as mine,  
> too :-).

As long as we are being thorough, one last example that proves nil and  
undefined are not the same thing when it comes to instance variables.

class Foo  
attr\_reader :bar

```
def set_bar(value)
  @bar = value
end

def bar_exists?
  defined? @bar
end

```

end

foo = Foo.new

foo.bar #=\> nil  
foo.bar\_exists? #=\> nil  
foo.set\_bar(“abc”)

foo.bar #=\> “abc”  
foo.bar\_exists? #=\> “instance-variable”

foo.set\_bar(nil)  
foo.bar #=\> nil  
foo.bar\_exists? #=\> “instance-variable”

This way you can tell if variable has been not been initialized, or if  
has been initialized and was specifically set to nil.

---

<div class="post-metadata">

**Author:** ![richard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/f0a364/32.png) [@richard](https://www.ruby-forum.com/u/richard)\
**Post date:** [February 17, 2007, 4:30pm UTC](https://www.ruby-forum.com/t/accessing-private-member-by-subclassing/85251/9 "2007-02-17T16:30:40Z")

</div>

Hi Alex,

I got distracted by our snow-storm for a few days.

> This way you can tell if variable has been not been initialized, or if  
> has been initialized and was specifically set to nil.

That’s excellent!!

Thank you very much for educating me in Ruby.

Yours very truly,  
Richard

On Feb 12, 8:20 pm, Alex W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)
