m_x m_x - 4 months ago 14
Ruby Question

Ruby : how to prevent modification of an array instance variable through an attribute reader

sorry for this noob question... let's say we have :

class TestMe
attr_reader :array

def initialize
@array = (1..10).to_a
end


end

it is then possible to do :

>> a = TestMe.new
=> #<TestMe:0x00000005567228 @x=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]>
>> a.array.map! &:to_s
=> ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
>> a.array
=> ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]



  • this clearly goes against encapsulation, doesn'it ?

  • is there any way to quickly protect the array variable from being changed ?

  • ... or do i need to implement a deep-copy reader every time my instance variable has "destructive" methods ?



EDIT i read somewhere it is "bad OO" to expose an array instance variable. If it's true, why ?

Answer

You cannot do much with attr_reader, because attr_reader :array generates the following code:

def array; @array; end

If you don't want to expose array instance, you can return Enumerator of this array (external iterator). Enumerator is a good iterator abstraction and does not allow you to modify original array.

def array; @array.to_enum; end

What good for encapsulation and what not depends on the abstraction your class presents. Generally this is not good for encapsulation to expose internal state of an object, including internal array. You may want to expose some methods that operate on the @array instead of exposing @array (or even its iterator) itself. Sometimes this is fine to expose array - always look at the abstraction your class presents.