> -----Original Message----- > From: Josh Cheek [mailto:josh.cheek / gmail.com] > Sent: 07 November 2009 02:43 > To: ruby-talk ML > Subject: Re: encapsulation issue > > On Fri, Nov 6, 2009 at 7:50 AM, James French > <James.French / naturalmotion.com > > wrote: > > > Hi, > > > > Is there any way of providing read only access to an array? (problem > shown > > by code below). > > > > class A > > > > def initialize > > @dependencies = [] > > end > > > > # intended to be read only access > > def dependencies > > @dependencies > > end > > > > def addDependency(d) > > @dependencies << d > > puts "adding #{d}" > > end > > end > > > > > > a = A.new > > a.addDependency("foo") > > a.dependencies << "bar" # encapsulation subverted > > > > puts a.dependencies # foo and bar both in array > > > > > > Any suggestions appreciated, > > James > > > > > Ruby is a dynamic language, as David pointed out, you can always get > around > whatever someone does. I think the point isn't so much to make it > impossible > for them to do something, but rather to make it clear how it was > anticipated > that it would be used. If they want to go so far as to override the > methods, > or perform instance_eval to get at the variable, then I'd take that as > a > very deliberate effort, so due to their determination to get around > your > design, I would just assume that they had a legitimate reason to do so, > or > at least if it blows up, they'll have no cause to be upset with you for > it. > > I don't know how you are trying to use the class, that you feel the > need to > return an array that cannot be altered, but you could define methods > which > give this functionality without ever exposing the array itself, > something > like this: > > > # consider defining methods to give the functionality you might want > # without exposing the guts of your class to the world > class Configuration > def initialize() @dependencies = [] end > def add_dependency(d) @dependencies << d end > > def each_dependency > @dependencies.each { |dep| yield dep } > end > end > > config = Configuration.new > config.add_dependency :dependency1 > config.add_dependency :dependency2 > config.add_dependency :dependency3 > > config.each_dependency do |dependency| > puts "I am accessing #{dependency}, " \ > "without ever seeing the array." > end > > > > # Of course, they can always get around whatever you have done, > # in the above, there is no way to get at @dependencies from the > # outside world, but in their code they could just add the code below > class Configuration > attr_accessor :dependencies > end > > p config.dependencies > > __END__ > Ruby is not about strict rigid code, or forcing people to use it > a certain way, it is dynamic. You have made your intentions clear, > at this point, if the user is not satisfied with your intentions, > then you must trust them to know what is best for their needs. > Something like this will not occur by accident, they have quite > deliberately decided that they need to break the encapsulation. Thanks for the answer - appreciate it, and have taken it on board.