# Class design issues

**URL:** <https://rubytalk.org/t/class-design-issues/35425>\
**Category:** ruby-talk\
**Created:** [16 February 2007 12:55 UTC](https://rubytalk.org/t/class-design-issues/35425 "2007-02-16T12:55:05Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![Spitfire](https://avatars.discourse-cdn.com/v4/letter/s/a5b964/32.png) [@Spitfire](https://rubytalk.org/u/Spitfire)\
**Post date:** [16 February 2007 12:55 UTC](https://rubytalk.org/t/class-design-issues/35425/1 "2007-02-16T12:55:05Z")

</div>

I have a class which takes an input and produces an object. Let's say, it takes inputs about specifications of a life-form, and then creates it (instantiates say an object, 'LifeForm'). Let's call this factory class 'Creator'. Now, my problem is how do I ensure that once 'Creator' returns a 'LifeForm', any external/requestor class can only view the properties of LifeForm, that were set during creation, and not be able to modify them???  
&nbsp;&nbsp;&nbsp;How do I design these imaginary classes 'Creator' and 'LifeForm'?

> **···**
>
> --  
> \_ \_ \_]{5pitph!r3}[\_ \_ \_  
> \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> “I'm smart enough to know that I'm dumb.”  
> &nbsp;&nbsp;&nbsp;- Richard P Feynman

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [16 February 2007 13:00 UTC](https://rubytalk.org/t/class-design-issues/35425/2 "2007-02-16T13:00:06Z")

</div>

> &nbsp;&nbsp;I have a class which takes an input and produces an object. Let's say, it takes inputs about specifications of a life-form, and then creates it (instantiates say an object, 'LifeForm'). Let's call this factory class 'Creator'. Now, my problem is how do I ensure that once 'Creator' returns a 'LifeForm', any external/requestor class can only view the properties of LifeForm, that were set during creation, and not be able to modify them???  
> &nbsp;&nbsp;How do I design these imaginary classes 'Creator' and 'LifeForm'?

First, it is very hard to actually prevent changes of instance variables (if it is possible at all). For your purposes it is probably sufficient to define attribute readers only. Second, you do not necessarily need a second class - basically LifeForm is the factory for LifeForm instances. So you could do

class LifeForm  
&nbsp;&nbsp;&nbsp;attr\_reader :age, :name, :foo

&nbsp;&nbsp;&nbsp;def initialize(age,name,foo)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@age = age  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@name = name  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@foo = foo  
&nbsp;&nbsp;&nbsp;end  
end

irb(main):010:0\> lf1 = LifeForm.new 10, "bla", "buzz"  
=\> #\<LifeForm:0x7ef6f5e4 @name="bla", @foo="buzz", @age=10\>  
irb(main):011:0\> lf1.name  
=\> "bla"  
irb(main):012:0\> lf1.name = "ddd"  
NoMethodError: undefined method `name=' for #\<LifeForm:0x7ef6f5e4 @name="bla", @foo="buzz", @age=10\>  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):12

HTH

&nbsp;&nbsp;robert

> **···**
>
> On 16.02.2007 13:51, Spitfire wrote:  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from :0

---

<div class="post-metadata">

**Author:** ![Forum](https://avatars.discourse-cdn.com/v4/letter/f/43a26b/32.png) [@Forum](https://rubytalk.org/u/Forum)\
**Post date:** [16 February 2007 13:08 UTC](https://rubytalk.org/t/class-design-issues/35425/3 "2007-02-16T13:08:42Z")

</div>

> \> I have a class which takes an input and produces an object. Let's say,  
> \> it takes inputs about specifications of a life-form, and then creates it  
> \> (instantiates say an object, 'LifeForm'). Let's call this factory class  
> \> 'Creator'. Now, my problem is how do I ensure that once 'Creator'  
> \> returns a 'LifeForm', any external/requestor class can only view the  
> \> properties of LifeForm, that were set during creation, and not be able  
> \> to modify them???  
> \> How do I design these imaginary classes 'Creator' and 'LifeForm'?
> 
> First, it is very hard to actually prevent changes of instance variables  
> (if it is possible at all). For your purposes it is probably sufficient  
> to define attribute readers only. Second, you do not necessarily need a  
> second class - basically LifeForm is the factory for LifeForm instances.  
> &nbsp;&nbsp;So you could do
> 
> class LifeForm  
> &nbsp;&nbsp;&nbsp;attr\_reader :age, :name, :foo
> 
> &nbsp;&nbsp;&nbsp;def initialize(age,name,foo)  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@age = age  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@name = name  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@foo = foo

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;freeze

and you might add freeze here, now it becomes quite tough to change  
the LifeForm object.  
Personally I do not know any way to modify it now, but someone will  
show us soon, I am quite sure 😉

HTH  
Robert

> **···**
>
> On 2/16/07, Robert Klemme \<shortcutter@googlemail.com\> wrote:
> 
> > On 16.02.2007 13:51, Spitfire wrote:  
> > &nbsp;&nbsp;&nbsp;end  
> > end
> > 
> > irb(main):010:0\> lf1 = LifeForm.new 10, "bla", "buzz"  
> > =\> #\<LifeForm:0x7ef6f5e4 @name="bla", @foo="buzz", @age=10\>  
> > irb(main):011:0\> lf1.name  
> > =\> "bla"  
> > irb(main):012:0\> lf1.name = "ddd"  
> > NoMethodError: undefined method `name=' for #\<LifeForm:0x7ef6f5e4  
> > @name="bla", @foo="buzz", @age=10\>  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):12  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from :0
> > 
> > HTH
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;robert
> 
> --  
> We have not succeeded in answering all of our questions.  
> In fact, in some ways, we are more confused than ever.  
> But we feel we are confused on a higher level and about more important things.  
> -Anonymous

---

<div class="post-metadata">

**Author:** ![Sur](https://avatars.discourse-cdn.com/v4/letter/s/c57346/32.png) [@Sur](https://rubytalk.org/u/Sur)\
**Post date:** [16 February 2007 13:09 UTC](https://rubytalk.org/t/class-design-issues/35425/4 "2007-02-16T13:09:04Z")

</div>

I think just declaring it as attr\_accessor is not that much a protection !!

its fine that

lf1.name # =\> error, undefined method `name=' f

BUT, it can easily be broken as....

lf1.instance\_variable\_set("@name", "new broken name")

lf1.name # =\> "new broken name"

> **···**
>
> On 2/16/07, Robert Klemme \<shortcutter@googlemail.com\> wrote:
> 
> > On 16.02.2007 13:51, Spitfire wrote:  
> > \> I have a class which takes an input and produces an object. Let's say,  
> > \> it takes inputs about specifications of a life-form, and then creates it  
> > \> (instantiates say an object, 'LifeForm'). Let's call this factory class  
> > \> 'Creator'. Now, my problem is how do I ensure that once 'Creator'  
> > \> returns a 'LifeForm', any external/requestor class can only view the  
> > \> properties of LifeForm, that were set during creation, and not be able  
> > \> to modify them???  
> > \> How do I design these imaginary classes 'Creator' and 'LifeForm'?
> > 
> > First, it is very hard to actually prevent changes of instance variables  
> > (if it is possible at all). For your purposes it is probably sufficient  
> > to define attribute readers only. Second, you do not necessarily need a  
> > second class - basically LifeForm is the factory for LifeForm instances.  
> > &nbsp;&nbsp;So you could do
> > 
> > class LifeForm  
> > &nbsp;&nbsp;&nbsp;attr\_reader :age, :name, :foo
> > 
> > &nbsp;&nbsp;&nbsp;def initialize(age,name,foo)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@age = age  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@name = name  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@foo = foo  
> > &nbsp;&nbsp;&nbsp;end  
> > end
> > 
> > irb(main):010:0\> lf1 = LifeForm.new 10, "bla", "buzz"  
> > =\> #\<LifeForm:0x7ef6f5e4 @name="bla", @foo="buzz", @age=10\>  
> > irb(main):011:0\> lf1.name  
> > =\> "bla"  
> > irb(main):012:0\> lf1.name = "ddd"  
> > NoMethodError: undefined method `name=' for #\<LifeForm:0x7ef6f5e4  
> > @name="bla", @foo="buzz", @age=10\>  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):12  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from :0
> > 
> > HTH
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;robert
> 
> --  
> sur  
> [http://expressica.com](http://expressica.com)

---

<div class="post-metadata">

**Author:** ![David\_A\_Black3](https://avatars.discourse-cdn.com/v4/letter/d/6a8cbe/32.png) [@David\_A\_Black3](https://rubytalk.org/u/David_A_Black3)\
**Post date:** [16 February 2007 13:11 UTC](https://rubytalk.org/t/class-design-issues/35425/5 "2007-02-16T13:11:57Z")

</div>

Hi --

> **···**
>
> On Fri, 16 Feb 2007, Robert Klemme wrote:
> 
> > On 16.02.2007 13:51, Spitfire wrote:
> > 
> > > &nbsp;&nbsp;I have a class which takes an input and produces an object. Let's say, it takes inputs about specifications of a life-form, and then creates it (instantiates say an object, 'LifeForm'). Let's call this factory class 'Creator'. Now, my problem is how do I ensure that once 'Creator' returns a 'LifeForm', any external/requestor class can only view the properties of LifeForm, that were set during creation, and not be able to modify them???  
> > > &nbsp;&nbsp;How do I design these imaginary classes 'Creator' and 'LifeForm'?
> > 
> > First, it is very hard to actually prevent changes of instance variables (if it is possible at all). For your purposes it is probably sufficient to define attribute readers only. Second, you do not necessarily need a second class - basically LifeForm is the factory for LifeForm instances. So you could do
> > 
> > class LifeForm  
> > attr\_reader :age, :name, :foo
> > 
> > def initialize(age,name,foo)  
> > &nbsp;&nbsp;&nbsp;@age = age  
> > &nbsp;&nbsp;&nbsp;@name = name  
> > &nbsp;&nbsp;&nbsp;@foo = foo  
> > end  
> > end
> > 
> > irb(main):010:0\> lf1 = LifeForm.new 10, "bla", "buzz"  
> > =\> #\<LifeForm:0x7ef6f5e4 @name="bla", @foo="buzz", @age=10\>  
> > irb(main):011:0\> lf1.name  
> > =\> "bla"  
> > irb(main):012:0\> lf1.name = "ddd"  
> > NoMethodError: undefined method `name=' for #\<LifeForm:0x7ef6f5e4 @name="bla", @foo="buzz", @age=10\>  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):12  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from :0
> 
> It does raise the danger of:
> 
> &nbsp;&nbsp;&nbsp;lf1.name \<\< "more stuff"
> 
> so it might be good to dup or freeze the mutable ones (though of  
> course someone who really wants to can always pry in with  
> instance\_eval).
> 
> David
> 
> --  
> Q. What is THE Ruby book for Rails developers?  
> A. RUBY FOR RAILS by David A. Black ([http://www.manning.com/black\](http://www.manning.com/black%5C))  
> &nbsp;&nbsp;&nbsp;&nbsp;(See what readers are saying! [http://www.rubypal.com/r4rrevs.pdf\](http://www.rubypal.com/r4rrevs.pdf%5C))  
> Q. Where can I get Ruby/Rails on-site training, consulting, coaching?  
> A. Ruby Power and Light, LLC ([http://www.rubypal.com](http://www.rubypal.com))

---

<div class="post-metadata">

**Author:** ![Sur](https://avatars.discourse-cdn.com/v4/letter/s/c57346/32.png) [@Sur](https://rubytalk.org/u/Sur)\
**Post date:** [16 February 2007 13:09 UTC](https://rubytalk.org/t/class-design-issues/35425/6 "2007-02-16T13:09:29Z")

</div>

attr\_reader i mean !!

> **···**
>
> On 2/16/07, sur max \<sur.max@gmail.com\> wrote:
> 
> > I think just declaring it as attr\_accessor is not that much a protection  
> > !!
> > 
> > its fine that
> > 
> > lf1.name # =\> error, undefined method `name=' f
> > 
> > BUT, it can easily be broken as....
> > 
> > lf1.instance\_variable\_set("@name", "new broken name")
> > 
> > lf1.name # =\> "new broken name"
> > 
> > On 2/16/07, Robert Klemme \<shortcutter@googlemail.com\> wrote:  
> > \>  
> > \> On 16.02.2007 13:51, Spitfire wrote:  
> > \> \> I have a class which takes an input and produces an object. Let's  
> > \> say,  
> > \> \> it takes inputs about specifications of a life-form, and then creates  
> > \> it  
> > \> \> (instantiates say an object, 'LifeForm'). Let's call this factory  
> > \> class  
> > \> \> 'Creator'. Now, my problem is how do I ensure that once 'Creator'  
> > \> \> returns a 'LifeForm', any external/requestor class can only view the  
> > \> \> properties of LifeForm, that were set during creation, and not be able  
> > \>  
> > \> \> to modify them???  
> > \> \> How do I design these imaginary classes 'Creator' and 'LifeForm'?  
> > \>  
> > \> First, it is very hard to actually prevent changes of instance variables  
> > \> (if it is possible at all). For your purposes it is probably sufficient  
> > \>  
> > \> to define attribute readers only. Second, you do not necessarily need a  
> > \> second class - basically LifeForm is the factory for LifeForm instances.  
> > \> So you could do  
> > \>  
> > \> class LifeForm  
> > \> attr\_reader :age, :name, :foo  
> > \>  
> > \> def initialize(age,name,foo)  
> > \> @age = age  
> > \> @name = name  
> > \> @foo = foo  
> > \> end  
> > \> end  
> > \>  
> > \> irb(main):010:0\> lf1 = LifeForm.new 10, "bla", "buzz"  
> > \> =\> #\<LifeForm:0x7ef6f5e4 @name="bla", @foo="buzz", @age=10\>  
> > \> irb(main):011:0\> lf1.name  
> > \> =\> "bla"  
> > \> irb(main):012:0\> lf1.name = "ddd"  
> > \> NoMethodError: undefined method `name=' for #\<LifeForm:0x7ef6f5e4  
> > \> @name="bla", @foo="buzz", @age=10\>  
> > \> from (irb):12  
> > \> from :0  
> > \>  
> > \> HTH  
> > \>  
> > \> robert  
> > \>
> > 
> > --  
> > sur  
> > [http://expressica.com](http://expressica.com)
> 
> --  
> sur  
> [http://expressica.com](http://expressica.com)

---

<div class="post-metadata">

**Author:** ![Sur](https://avatars.discourse-cdn.com/v4/letter/s/c57346/32.png) [@Sur](https://rubytalk.org/u/Sur)\
**Post date:** [16 February 2007 13:22 UTC](https://rubytalk.org/t/class-design-issues/35425/7 "2007-02-16T13:22:35Z")

</div>

Hi David,

Now this should not be available !!

lf1.name \<\< "more stuffs"  
this should generate error !! ... (i agree it is working)

but is name is an attr\_reader then the manipulations with "\<\<" should not be  
supported, as the case of "="  
or it should be ?

> **···**
>
> On 2/16/07, dblack@wobblini.net \<dblack@wobblini.net\> wrote:
> 
> > Hi --
> > 
> > On Fri, 16 Feb 2007, Robert Klemme wrote:
> > 
> > \> On 16.02.2007 13:51, Spitfire wrote:  
> > \>\> I have a class which takes an input and produces an object. Let's  
> > say, it  
> > \>\> takes inputs about specifications of a life-form, and then creates it  
> > \>\> (instantiates say an object, 'LifeForm'). Let's call this factory class  
> > \>\> 'Creator'. Now, my problem is how do I ensure that once 'Creator'  
> > returns a  
> > \>\> 'LifeForm', any external/requestor class can only view the properties  
> > of  
> > \>\> LifeForm, that were set during creation, and not be able to modify  
> > them???  
> > \>\> How do I design these imaginary classes 'Creator' and 'LifeForm'?  
> > \>  
> > \> First, it is very hard to actually prevent changes of instance variables  
> > (if  
> > \> it is possible at all). For your purposes it is probably sufficient to  
> > \> define attribute readers only. Second, you do not necessarily need a  
> > second  
> > \> class - basically LifeForm is the factory for LifeForm instances. So  
> > you  
> > \> could do  
> > \>  
> > \> class LifeForm  
> > \> attr\_reader :age, :name, :foo  
> > \>  
> > \> def initialize(age,name,foo)  
> > \> @age = age  
> > \> @name = name  
> > \> @foo = foo  
> > \> end  
> > \> end  
> > \>  
> > \> irb(main):010:0\> lf1 = LifeForm.new 10, "bla", "buzz"  
> > \> =\> #\<LifeForm:0x7ef6f5e4 @name="bla", @foo="buzz", @age=10\>  
> > \> irb(main):011:0\> lf1.name  
> > \> =\> "bla"  
> > \> irb(main):012:0\> lf1.name = "ddd"  
> > \> NoMethodError: undefined method `name=' for #\<LifeForm:0x7ef6f5e4  
> > \> @name="bla", @foo="buzz", @age=10\>  
> > \> from (irb):12  
> > \> from :0
> > 
> > It does raise the danger of:
> > 
> > &nbsp;&nbsp;&nbsp;lf1.name \<\< "more stuff"
> > 
> > so it might be good to dup or freeze the mutable ones (though of  
> > course someone who really wants to can always pry in with  
> > instance\_eval).
> > 
> > David
> > 
> > --  
> > Q. What is THE Ruby book for Rails developers?  
> > A. RUBY FOR RAILS by David A. Black ([http://www.manning.com/black\](http://www.manning.com/black%5C))  
> > &nbsp;&nbsp;&nbsp;&nbsp;(See what readers are saying! [http://www.rubypal.com/r4rrevs.pdf\](http://www.rubypal.com/r4rrevs.pdf%5C))  
> > Q. Where can I get Ruby/Rails on-site training, consulting, coaching?  
> > A. Ruby Power and Light, LLC ([http://www.rubypal.com](http://www.rubypal.com))
> 
> --  
> sur  
> [http://expressica.com](http://expressica.com)

---

<div class="post-metadata">

**Author:** ![Spitfire](https://avatars.discourse-cdn.com/v4/letter/s/a5b964/32.png) [@Spitfire](https://rubytalk.org/u/Spitfire)\
**Post date:** [16 February 2007 13:40 UTC](https://rubytalk.org/t/class-design-issues/35425/8 "2007-02-16T13:40:09Z")

</div>

Robert Dober wrote:

> > class LifeForm  
> > &nbsp;&nbsp;&nbsp;attr\_reader :age, :name, :foo
> > 
> > &nbsp;&nbsp;&nbsp;def initialize(age,name,foo)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@age = age  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@name = name  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@foo = foo
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;freeze
> 
> and you might add freeze here, now it becomes quite tough to change  
> the LifeForm object.  
> Personally I do not know any way to modify it now, but someone will  
> show us soon, I am quite sure 😉

&nbsp;&nbsp;&nbsp;Sorry, I'm no expert in Ruby. So you have to explain what 'freeze' does???

&nbsp;&nbsp;&nbsp;Let me add more hypothetical requirements to my problem (sorry for not stating these initially!)

&nbsp;&nbsp;&nbsp;Lets consider that LifeForm has a property called 'Rank'. Now, this is a very critical property that I must make sure to retain consistent. LifeForm can also have offsprings, which are tied to it, say by a instance variable that points any LifeForm to its list of offspring LifeForm objects.

&nbsp;&nbsp;&nbsp;Now, the rank of a LifeForm is its distance from all its ancestors. I want a functionality such that whenever you create a LifeForm, the rank is set to '0'. Next, I want to make sure that when I add offsprings to an existing LifeForm, its depth gets updated automagically, without my intervention. More specifically, I want to have a feature by which LifeForm has a mechanism in the class, which allows to it set by itself the 'rank' of its instances. And, when I add a child, say through a method 'add\_Child' (don't know if this is the ideal solution, but this is what I can think of!), it does something like this,

&nbsp;&nbsp;&nbsp;for each child in new\_children\_added  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;child.depth = child.depth + current.depth  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# current refers to parent or current object  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;actually I want this to be carried out to all children newly added, their children and so on. So that the ranks of a LifeForm is always consistent! Hope I've conveyed exactly what I want.

&nbsp;&nbsp;&nbsp;Now I want to be able to only 'read' this rank, not modify it from outside the LifeForm class. Is this possible? If so, how do you design it?

> **···**
>
> --  
> \_ \_ \_]{5pitph!r3}[\_ \_ \_  
> \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> “I'm smart enough to know that I'm dumb.”  
> &nbsp;&nbsp;&nbsp;- Richard P Feynman

---

<div class="post-metadata">

**Author:** ![David\_A\_Black3](https://avatars.discourse-cdn.com/v4/letter/d/6a8cbe/32.png) [@David\_A\_Black3](https://rubytalk.org/u/David_A_Black3)\
**Post date:** [16 February 2007 13:28 UTC](https://rubytalk.org/t/class-design-issues/35425/9 "2007-02-16T13:28:43Z")

</div>

Hi --

> Hi David,
> 
> Now this should not be available !!
> 
> lf1.name \<\< "more stuffs"  
> this should generate error !! ... (i agree it is working)

Strings response to "\<\<", so assuming lf1.name returns a string,  
there's no error of any kind here.

> but is name is an attr\_reader then the manipulations with "\<\<" should not be  
> supported, as the case of "="  
> or it should be ?

It's not really that = is or is not supported; it's all a matter of  
what methods you define. If you define a method that returns a  
string, then you get a string, which is mutable, from that method.  
The notion of an "attribute" is really in the mind of the programmer.  
Objects don't know whether they're attributes or not; they just exist,  
and do what they're told.

David

> **···**
>
> On Fri, 16 Feb 2007, sur max wrote:
> 
> --  
> Q. What is THE Ruby book for Rails developers?  
> A. RUBY FOR RAILS by David A. Black ([http://www.manning.com/black\](http://www.manning.com/black%5C))  
> &nbsp;&nbsp;&nbsp;&nbsp;(See what readers are saying! [http://www.rubypal.com/r4rrevs.pdf\](http://www.rubypal.com/r4rrevs.pdf%5C))  
> Q. Where can I get Ruby/Rails on-site training, consulting, coaching?  
> A. Ruby Power and Light, LLC ([http://www.rubypal.com](http://www.rubypal.com))

---

<div class="post-metadata">

**Author:** ![Forum](https://avatars.discourse-cdn.com/v4/letter/f/43a26b/32.png) [@Forum](https://rubytalk.org/u/Forum)\
**Post date:** [16 February 2007 14:52 UTC](https://rubytalk.org/t/class-design-issues/35425/10 "2007-02-16T14:52:23Z")

</div>

> Robert Dober wrote:  
> \>\> class LifeForm  
> \>\> attr\_reader :age, :name, :foo  
> \>\>  
> \>\> def initialize(age,name,foo)  
> \>\> @age = age  
> \>\> @name = name  
> \>\> @foo = foo  
> \>  
> \> freeze  
> \>  
> \> and you might add freeze here, now it becomes quite tough to change  
> \> the LifeForm object.  
> \> Personally I do not know any way to modify it now, but someone will  
> \> show us soon, I am quite sure 😉  
> \>  
> &nbsp;&nbsp;&nbsp;Sorry, I'm no expert in Ruby. So you have to explain what 'freeze'  
> does???

Sure should have been clearer

freeze basically does not allow modification of the object anymore  
I will demonstrate in irb  
923/425 \> irb  
irb(main):001:0\> class A  
irb(main):002:1\> attr\_reader :a  
irb(main):003:1\> def initialize  
irb(main):004:2\> @a=42  
irb(main):005:2\> end  
irb(main):006:1\> def change  
irb(main):007:2\> @a = rand(43)  
irb(main):008:2\> end  
irb(main):009:1\> end  
=\> nil  
irb(main):010:0\> a=A.new  
=\> #\<A:0xb7d829dc @a=42\>  
irb(main):011:0\> a.change  
=\> 30  
irb(main):012:0\> a.instance\_variable\_set("@a", 1764)  
=\> 1764  
irb(main):013:0\> a  
=\> #\<A:0xb7d829dc @a=1764\>  
irb(main):014:0\> a.freeze  
=\> #\<A:0xb7d829dc @a=1764\>  
irb(main):015:0\> a.change  
TypeError: can't modify frozen object  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):7:in `change'  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):15

> **···**
>
> On 2/16/07, Spitfire \<timid.gentoo@gmail.com\> wrote:  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from :0  
> irb(main):016:0\> a.instance\_variable\_set("@a", 1764)  
> TypeError: can't modify frozen object  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):16:in `instance\_variable\_set'  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):16  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from :0
> 
> David stated that this can be overcome with instance eval, I do not  
> know how though  
> irb(main):017:0\> a.instance\_eval do  
> irb(main):018:1\* @a=1  
> irb(main):019:1\> end  
> TypeError: can't modify frozen object  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):18  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):17:in `instance\_eval'  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):17  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from :0  
> Documentation states that a frozen object cannot be unfrozen.  
> Unfortunately you cannot freeze your whole object so maybe it would be  
> good to expose a ProxyObject
> 
> class Intern  
> &nbsp;&nbsp;attr\_accessor :a  
> &nbsp;&nbsp;def initialize  
> &nbsp;&nbsp;&nbsp;&nbsp;@a = 42  
> &nbsp;&nbsp;end  
> end
> 
> class Proxy  
> &nbsp;&nbsp;def initialize protect  
> &nbsp;&nbsp;&nbsp;&nbsp;@protect = protect  
> &nbsp;&nbsp;&nbsp;&nbsp;freeze  
> &nbsp;&nbsp;end  
> &nbsp;&nbsp;def a \*args, &blk  
> &nbsp;&nbsp;&nbsp;&nbsp;@protect.a \*args, &blk  
> &nbsp;&nbsp;end  
> &nbsp;&nbsp;freeze  
> end
> 
> i = Intern.new  
> p = Proxy.new( i )  
> puts p.a
> 
> begin  
> &nbsp;&nbsp;p.a = 42  
> rescue  
> &nbsp;&nbsp;puts "good"  
> end
> 
> begin  
> &nbsp;&nbsp;class Proxy  
> &nbsp;&nbsp;&nbsp;&nbsp;def p; @protect; end  
> &nbsp;&nbsp;end  
> rescue  
> &nbsp;&nbsp;puts "very good"  
> end
> 
> begin  
> &nbsp;&nbsp;Proxy.send(:define\_method, :p){  
> &nbsp;&nbsp;&nbsp;&nbsp;@protect  
> &nbsp;&nbsp;}  
> rescue  
> &nbsp;&nbsp;puts "better"  
> end
> 
> begin  
> &nbsp;&nbsp;class \<\< Proxy  
> &nbsp;&nbsp;&nbsp;&nbsp;define\_method(:p){  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@protect  
> &nbsp;&nbsp;&nbsp;&nbsp;}  
> &nbsp;&nbsp;end  
> rescue  
> &nbsp;&nbsp;puts "even better"  
> end
> 
> begin  
> &nbsp;&nbsp;p.a = 42  
> rescue  
> &nbsp;&nbsp;puts "still good"  
> end
> 
> now you have pretty much sealed your Intern objects as long as all  
> access you allow is by Proxy.  
> That might give an APi which is pretty much clear about access 🙂
> 
> > &nbsp;&nbsp;&nbsp;Let me add more hypothetical requirements to my problem (sorry for  
> > not stating these initially!)
> > 
> > &nbsp;&nbsp;&nbsp;Lets consider that LifeForm has a property called 'Rank'. Now, this  
> > is a very critical property that I must make sure to retain consistent.  
> > LifeForm can also have offsprings, which are tied to it, say by a  
> > instance variable that points any LifeForm to its list of offspring  
> > LifeForm objects.
> > 
> > &nbsp;&nbsp;&nbsp;Now, the rank of a LifeForm is its distance from all its ancestors. I  
> > want a functionality such that whenever you create a LifeForm, the rank  
> > is set to '0'. Next, I want to make sure that when I add offsprings to  
> > an existing LifeForm, its depth gets updated automagically, without my  
> > intervention. More specifically, I want to have a feature by which  
> > LifeForm has a mechanism in the class, which allows to it set by itself  
> > the 'rank' of its instances. And, when I add a child, say through a  
> > method 'add\_Child' (don't know if this is the ideal solution, but this  
> > is what I can think of!), it does something like this,
> 
> Of course you cannot freeze the whole object anymore but only some parts.
> 
> > &nbsp;&nbsp;&nbsp;for each child in new\_children\_added  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;child.depth = child.depth + current.depth  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# current refers to parent or current object  
> > &nbsp;&nbsp;&nbsp;end
> > 
> > &nbsp;&nbsp;&nbsp;actually I want this to be carried out to all children newly added,  
> > their children and so on. So that the ranks of a LifeForm is always  
> > consistent! Hope I've conveyed exactly what I want.
> > 
> > &nbsp;&nbsp;&nbsp;Now I want to be able to only 'read' this rank, not modify it from  
> > outside the LifeForm class. Is this possible? If so, how do you design it?  
> > --  
> > \_ \_ \_]{5pitph!r3}[\_ \_ \_  
> > \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > "I'm smart enough to know that I'm dumb."  
> > &nbsp;&nbsp;&nbsp;- Richard P Feynman
> 
> --  
> We have not succeeded in answering all of our questions.  
> In fact, in some ways, we are more confused than ever.  
> But we feel we are confused on a higher level and about more important things.  
> -Anonymous

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [16 February 2007 15:45 UTC](https://rubytalk.org/t/class-design-issues/35425/11 "2007-02-16T15:45:17Z")

</div>

> Robert Dober wrote:
> 
> > > class LifeForm  
> > > &nbsp;&nbsp;&nbsp;attr\_reader :age, :name, :foo
> > > 
> > > &nbsp;&nbsp;&nbsp;def initialize(age,name,foo)  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@age = age  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@name = name  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@foo = foo
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;freeze
> > 
> > and you might add freeze here, now it becomes quite tough to change  
> > the LifeForm object.  
> > Personally I do not know any way to modify it now, but someone will  
> > show us soon, I am quite sure 😉
> 
> &nbsp;&nbsp;Sorry, I'm no expert in Ruby. So you have to explain what 'freeze' does???

It prevents further manipulation of an instance:

irb(main):001:0\> %w{foo bar bx}.shift  
=\> "foo"  
irb(main):002:0\> x=Struct.new(:name).new("foo")  
=\> #\<struct #\<Class:0x7ef96ce8\> name="foo"\>  
irb(main):003:0\> x.name = "bar"  
=\> "bar"  
irb(main):004:0\> x.freeze  
=\> #\<struct #\<Class:0x7ef96ce8\> name="bar"\>  
irb(main):005:0\> x.name = "foo"  
TypeError: can't modify frozen Struct  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):5:in `name='  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):5

> **···**
>
> On 16.02.2007 14:35, Spitfire wrote:  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from :0  
> irb(main):006:0\> x  
> =\> #\<struct #\<Class:0x7ef96ce8\> name="bar"\>  
> irb(main):007:0\> s="foo"  
> =\> "foo"  
> irb(main):008:0\> s \<\< "bar"  
> =\> "foobar"  
> irb(main):009:0\> s  
> =\> "foobar"  
> irb(main):010:0\> s.freeze  
> =\> "foobar"  
> irb(main):011:0\> s \<\< "xxx"  
> TypeError: can't modify frozen string  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):11:in `\<\<'  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):11  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from :0
> 
> > &nbsp;&nbsp;Let me add more hypothetical requirements to my problem (sorry for not stating these initially!)
> 
> Right. Your new set of requirements rules out "freeze" as that won't allow for adding of children etc.
> 
> > &nbsp;&nbsp;Lets consider that LifeForm has a property called 'Rank'. Now, this is a very critical property that I must make sure to retain consistent. LifeForm can also have offsprings, which are tied to it, say by a instance variable that points any LifeForm to its list of offspring LifeForm objects.
> > 
> > &nbsp;&nbsp;Now, the rank of a LifeForm is its distance from all its ancestors. I want a functionality such that whenever you create a LifeForm, the rank is set to '0'. Next, I want to make sure that when I add offsprings to an existing LifeForm, its depth gets updated automagically, without my intervention. More specifically, I want to have a feature by which LifeForm has a mechanism in the class, which allows to it set by itself the 'rank' of its instances. And, when I add a child, say through a method 'add\_Child' (don't know if this is the ideal solution, but this is what I can think of!), it does something like this,
> > 
> > &nbsp;&nbsp;for each child in new\_children\_added  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;child.depth = child.depth + current.depth  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# current refers to parent or current object  
> > &nbsp;&nbsp;end
> 
> You have a tree data structure here (if you have multiple roots it's called a "forest"). This is one of the well researched and understood structures. You'll find plenty of implementations and information on the web.
> 
> Actually when adding a child, I would go up recursively to the root of the tree and update the rank. Kind of:
> 
> def add\_child(ch)  
> &nbsp;&nbsp;&nbsp;delta = rank + 1
> 
> &nbsp;&nbsp;&nbsp;# BFS because Ruby is not good at recursion  
> &nbsp;&nbsp;&nbsp;q = [ch]
> 
> &nbsp;&nbsp;&nbsp;until q.empty?  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj = q.shift  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj.rank += delta  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;q.concat obj.children  
> &nbsp;&nbsp;&nbsp;end  
> end
> 
> You could make method rank= protected to prevent accidental invocation from the outside.
> 
> > &nbsp;&nbsp;actually I want this to be carried out to all children newly added, their children and so on. So that the ranks of a LifeForm is always consistent! Hope I've conveyed exactly what I want.
> 
> Yes. One solution is to calculate the rank on demand and only optimize this to a local variable if you have performance issues. That solution is much easier because then you can simply do
> 
> def rank  
> &nbsp;&nbsp;&nbsp;obj, r = self, 0  
> &nbsp;&nbsp;&nbsp;while obj  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r += 1  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj = obj.parent  
> &nbsp;&nbsp;&nbsp;end  
> &nbsp;&nbsp;&nbsp;r  
> end
> 
> This is slow but always consistent.
> 
> > &nbsp;&nbsp;Now I want to be able to only 'read' this rank, not modify it from outside the LifeForm class. Is this possible? If so, how do you design it?
> 
> See above for ideas. Although I would probably not spend too much efforts in making it impossible to change the value from the outside. There is always a way.
> 
> Kind regards
> 
> &nbsp;&nbsp;robert

---

<div class="post-metadata">

**Author:** ![Sur](https://avatars.discourse-cdn.com/v4/letter/s/c57346/32.png) [@Sur](https://rubytalk.org/u/Sur)\
**Post date:** [16 February 2007 13:35 UTC](https://rubytalk.org/t/class-design-issues/35425/12 "2007-02-16T13:35:48Z")

</div>

It means even need not to go for lf1.instance\_variable\_set

it is pretty working as

lf1.name.gsub!(/.\*/,"")

lf1.name \<\< "new broken name"

> **···**
>
> On 2/16/07, dblack@wobblini.net \<dblack@wobblini.net\> wrote:
> 
> > Hi --
> > 
> > On Fri, 16 Feb 2007, sur max wrote:
> > 
> > \> Hi David,  
> > \>  
> > \> Now this should not be available !!  
> > \>  
> > \> lf1.name \<\< "more stuffs"  
> > \> this should generate error !! ... (i agree it is working)
> > 
> > Strings response to "\<\<", so assuming lf1.name returns a string,  
> > there's no error of any kind here.
> > 
> > \> but is name is an attr\_reader then the manipulations with "\<\<" should  
> > not be  
> > \> supported, as the case of "="  
> > \> or it should be ?
> > 
> > It's not really that = is or is not supported; it's all a matter of  
> > what methods you define. If you define a method that returns a  
> > string, then you get a string, which is mutable, from that method.  
> > The notion of an "attribute" is really in the mind of the programmer.  
> > Objects don't know whether they're attributes or not; they just exist,  
> > and do what they're told.
> > 
> > David
> > 
> > --  
> > Q. What is THE Ruby book for Rails developers?  
> > A. RUBY FOR RAILS by David A. Black ([http://www.manning.com/black\](http://www.manning.com/black%5C))  
> > &nbsp;&nbsp;&nbsp;&nbsp;(See what readers are saying! [http://www.rubypal.com/r4rrevs.pdf\](http://www.rubypal.com/r4rrevs.pdf%5C))  
> > Q. Where can I get Ruby/Rails on-site training, consulting, coaching?  
> > A. Ruby Power and Light, LLC ([http://www.rubypal.com](http://www.rubypal.com))
> 
> --  
> sur  
> [http://expressica.com](http://expressica.com)

---

<div class="post-metadata">

**Author:** ![Sur](https://avatars.discourse-cdn.com/v4/letter/s/c57346/32.png) [@Sur](https://rubytalk.org/u/Sur)\
**Post date:** [16 February 2007 13:40 UTC](https://rubytalk.org/t/class-design-issues/35425/13 "2007-02-16T13:40:32Z")

</div>

But i think there is a point to discuss here...

as lf1.name is simply an instance method which is(should be) only capable of  
returning the instance variable "@name"

so by defining :name as attr\_reader should block everything which is trying  
to write the instance variable "@name"

> **···**
>
> On 2/16/07, sur max \<sur.max@gmail.com\> wrote:
> 
> > It means even need not to go for lf1.instance\_variable\_set
> > 
> > it is pretty working as
> > 
> > lf1.name.gsub!(/.\*/,"")
> > 
> > lf1.name \<\< "new broken name"
> > 
> > On 2/16/07, dblack@wobblini.net \<dblack@wobblini.net\> wrote:  
> > \>  
> > \> Hi --  
> > \>  
> > \> On Fri, 16 Feb 2007, sur max wrote:  
> > \>  
> > \> \> Hi David,  
> > \> \>  
> > \> \> Now this should not be available !!  
> > \> \>  
> > \> \> lf1.name \<\< "more stuffs"  
> > \> \> this should generate error !! ... (i agree it is working)  
> > \>  
> > \> Strings response to "\<\<", so assuming lf1.name returns a string,  
> > \> there's no error of any kind here.  
> > \>  
> > \> \> but is name is an attr\_reader then the manipulations with "\<\<" should  
> > \> not be  
> > \> \> supported, as the case of "="  
> > \> \> or it should be ?  
> > \>  
> > \> It's not really that = is or is not supported; it's all a matter of  
> > \> what methods you define. If you define a method that returns a  
> > \> string, then you get a string, which is mutable, from that method.  
> > \> The notion of an "attribute" is really in the mind of the programmer.  
> > \> Objects don't know whether they're attributes or not; they just exist,  
> > \> and do what they're told.  
> > \>  
> > \> David  
> > \>  
> > \> --  
> > \> Q. What is THE Ruby book for Rails developers?  
> > \> A. RUBY FOR RAILS by David A. Black ([Ruby for Rails](http://www.manning.com/black) )  
> > \> (See what readers are saying! [http://www.rubypal.com/r4rrevs.pdf\](http://www.rubypal.com/r4rrevs.pdf%5C))  
> > \> Q. Where can I get Ruby/Rails on-site training, consulting, coaching?  
> > \> A. Ruby Power and Light, LLC ( [http://www.rubypal.com](http://www.rubypal.com))  
> > \>
> > 
> > --  
> > sur  
> > [http://expressica.com](http://expressica.com)
> 
> --  
> sur  
> [http://expressica.com](http://expressica.com)

---

<div class="post-metadata">

**Author:** ![Alex\_Young](https://avatars.discourse-cdn.com/v4/letter/a/ee7513/32.png) [@Alex\_Young](https://rubytalk.org/u/Alex_Young)\
**Post date:** [16 February 2007 14:38 UTC](https://rubytalk.org/t/class-design-issues/35425/14 "2007-02-16T14:38:23Z")

</div>

sur max wrote:

> But i think there is a point to discuss here...
> 
> as lf1.name is simply an instance method which is(should be) only capable of  
> returning the instance variable "@name"
> 
> so by defining :name as attr\_reader should block everything which is trying  
> to write the instance variable "@name"

Nothing is trying to write to @name - what's happening is that @name modifies its own data via the method call '\<\<' (or gsub!, or...).

Watch:

irb(main):001:0\> class A; attr\_reader :foo; def initialize; @foo=''; end; end  
=\> nil  
irb(main):002:0\> a = A.new  
=\> #\<A:0xb7ca0280 @foo=""\>  
irb(main):003:0\> a.foo.object\_id  
=\> -605748948  
irb(main):004:0\> a.foo = "Foo!"  
NoMethodError: undefined method `foo=' for #\<A:0xb7ca0280 @foo=""\>  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):4  
irb(main):005:0\> a.foo \<\< "Foo!"  
=\> "Foo!"  
irb(main):006:0\> a.foo  
=\> "Foo!"  
irb(main):007:0\> a.foo.object\_id  
=\> -605748948

See how despite the method call, a.foo.object\_id returns the same value each time? That's what attr\_reader protects. It's not within the scope of what attr\_reader should be doing to define what methods you're allowed to call on what it returns, because it's got no way to know which methods can change that object's state.

Hope this helps,

> **···**
>
> from :0  
> --  
> Alex
> 
> > On 2/16/07, sur max \<sur.max@gmail.com\> wrote:
> > 
> > > It means even need not to go for lf1.instance\_variable\_set
> > > 
> > > it is pretty working as
> > > 
> > > lf1.name.gsub!(/.\*/,"")
> > > 
> > > lf1.name \<\< "new broken name"
> > > 
> > > On 2/16/07, dblack@wobblini.net \<dblack@wobblini.net\> wrote:  
> > > \>  
> > > \> Hi --  
> > > \>  
> > > \> On Fri, 16 Feb 2007, sur max wrote:  
> > > \>  
> > > \> \> Hi David,  
> > > \> \>  
> > > \> \> Now this should not be available !!  
> > > \> \>  
> > > \> \> lf1.name \<\< "more stuffs"  
> > > \> \> this should generate error !! ... (i agree it is working)  
> > > \>  
> > > \> Strings response to "\<\<", so assuming lf1.name returns a string,  
> > > \> there's no error of any kind here.  
> > > \>  
> > > \> \> but is name is an attr\_reader then the manipulations with "\<\<" should  
> > > \> not be  
> > > \> \> supported, as the case of "="  
> > > \> \> or it should be ?  
> > > \>  
> > > \> It's not really that = is or is not supported; it's all a matter of  
> > > \> what methods you define. If you define a method that returns a  
> > > \> string, then you get a string, which is mutable, from that method.  
> > > \> The notion of an "attribute" is really in the mind of the programmer.  
> > > \> Objects don't know whether they're attributes or not; they just exist,  
> > > \> and do what they're told.  
> > > \>  
> > > \> David  
> > > \>  
> > > \> --  
> > > \> Q. What is THE Ruby book for Rails developers?  
> > > \> A. RUBY FOR RAILS by David A. Black ([Ruby for Rails](http://www.manning.com/black) )  
> > > \> (See what readers are saying! [http://www.rubypal.com/r4rrevs.pdf\](http://www.rubypal.com/r4rrevs.pdf%5C))  
> > > \> Q. Where can I get Ruby/Rails on-site training, consulting, coaching?  
> > > \> A. Ruby Power and Light, LLC ( [http://www.rubypal.com](http://www.rubypal.com))  
> > > \>
> > > 
> > > --  
> > > sur  
> > > [http://expressica.com](http://expressica.com)

---

<div class="post-metadata">

**Author:** ![David\_A\_Black3](https://avatars.discourse-cdn.com/v4/letter/d/6a8cbe/32.png) [@David\_A\_Black3](https://rubytalk.org/u/David_A_Black3)\
**Post date:** [16 February 2007 15:32 UTC](https://rubytalk.org/t/class-design-issues/35425/15 "2007-02-16T15:32:17Z")

</div>

Hi --

> But i think there is a point to discuss here...
> 
> as lf1.name is simply an instance method which is(should be) only capable of  
> returning the instance variable "@name"
> 
> so by defining :name as attr\_reader should block everything which is trying  
> to write the instance variable "@name"

attr\_reader just writes a wrapper method for you. If the default  
wrapper method doesn't do what you want, you can write a different  
one:

&nbsp;&nbsp;&nbsp;def x  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@x.dup  
&nbsp;&nbsp;&nbsp;end

If you want to do that a lot, you could write a new attr\_\* method:

&nbsp;&nbsp;&nbsp;class Module  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def attr\_reader\_dup(\*attrs)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;attrs.each do |attr|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;define\_method(attr) { instance\_variable\_get("@#{attr}").dup }  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;class C  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;attr\_reader\_dup(:x)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def initialize  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@x = "don't change me"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;c = C.new  
&nbsp;&nbsp;&nbsp;c.x \<\< "trying to change"  
&nbsp;&nbsp;&nbsp;p c.x # don't change me

David

P.S. Please don't top-post. Just quote what you're responding to and  
add your response.

> **···**
>
> On Fri, 16 Feb 2007, sur max wrote:
> 
> --  
> Q. What is THE Ruby book for Rails developers?  
> A. RUBY FOR RAILS by David A. Black ([http://www.manning.com/black\](http://www.manning.com/black%5C))  
> &nbsp;&nbsp;&nbsp;&nbsp;(See what readers are saying! [http://www.rubypal.com/r4rrevs.pdf\](http://www.rubypal.com/r4rrevs.pdf%5C))  
> Q. Where can I get Ruby/Rails on-site training, consulting, coaching?  
> A. Ruby Power and Light, LLC ([http://www.rubypal.com](http://www.rubypal.com))
