|
View:
New views
13 Messages
—
Rating Filter:
Alert me
|
|
|
encapsulation issueHi,
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 |
|
|
Re: encapsulation issueHi --
On Fri, 6 Nov 2009, James French 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 You can freeze the array: a = [].freeze a << 1 # TypeError: can't modify frozen array David -- The Ruby training with D. Black, G. Brown, J.McAnally Compleat Jan 22-23, 2010, Tampa, FL Rubyist http://www.thecompleatrubyist.com David A. Black/Ruby Power and Light, LLC (http://www.rubypal.com) |
|
|
Re: encapsulation issue2009/11/6 David A. Black <dblack@...>:
> Hi -- > > On Fri, 6 Nov 2009, James French 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 > > You can freeze the array: > > a = [].freeze > a << 1 # TypeError: can't modify frozen array > > You could also dup it: class A def dependencies @dependencies.dup end end a = A.new a.addDependency "foo" a.dependencies << "bar" puts a.dependencies # => ["foo"] |
|
|
Re: encapsulation issueJames French wrote:
> Hi, > > Is there any way of providing read only access to an array? > I was going to suggest attr_reader :dependencies but a quick test showed that there's more there than meets the eye.. Oddly. -- Posted via http://www.ruby-forum.com/. |
|
|
Re: encapsulation issueJames,
It appears, also, that changing @dependencies to a constant also does not help. Strange. Ralph Friday, November 6, 2009, 6:50:30 AM, you wrote: JF> Hi, JF> Is there any way of providing read only access to an array? (problem shown by code below). JF> class A JF> def initialize JF> @dependencies = [] JF> end JF> # intended to be read only access JF> def dependencies JF> @dependencies JF> end JF> def addDependency(d) JF> @dependencies << d JF> puts "adding #{d}" JF> end JF> end JF> a = A.new JF> a.addDependency("foo") JF> a.dependencies << "bar" # encapsulation subverted JF> puts a.dependencies # foo and bar both in array JF> Any suggestions appreciated, JF> James -- Best regards, Ralph mailto:ralphs@... |
|
|
Re: encapsulation issue> -----Original Message----- > From: David A. Black [mailto:dblack@...] > Sent: 06 November 2009 14:01 > To: ruby-talk ML > Subject: Re: encapsulation issue > > Hi -- > > On Fri, 6 Nov 2009, James French 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 > > You can freeze the array: > > a = [].freeze > a << 1 # TypeError: can't modify frozen array > > > David > > -- > The Ruby training with D. Black, G. Brown, J.McAnally > Compleat Jan 22-23, 2010, Tampa, FL > Rubyist http://www.thecompleatrubyist.com > > David A. Black/Ruby Power and Light, LLC (http://www.rubypal.com) But then I can't legitimately push to it in addDependency... |
|
|
Re: encapsulation issue> -----Original Message----- > From: Tom Stuart [mailto:tom@...] > Sent: 06 November 2009 14:06 > To: ruby-talk ML > Subject: Re: encapsulation issue > > 2009/11/6 David A. Black <dblack@...>: > > Hi -- > > > > On Fri, 6 Nov 2009, James French 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 > > > > You can freeze the array: > > > > a = [].freeze > > a << 1 # TypeError: can't modify frozen array > > > > > > You could also dup it: > > class A > def dependencies > @dependencies.dup > end > end > > a = A.new > a.addDependency "foo" > a.dependencies << "bar" > puts a.dependencies # => ["foo"] I don't think it solves it that nicely because as well as duplicating data which doesn't feel good, you've then got a line that looks as though it does something but doesn't. I guess it could raise an error somehow. |
|
|
Re: encapsulation issueOn 2009-11-06, James French <James.French@...> wrote:
> But then I can't legitimately push to it in addDependency... No, but you could dup-and-append when you hit that. I think you pretty much have to dup the object in this case. Hmm. Okay, imagine this. Define a new Array-like class, which has an Array as an internal member, but overrides all the things which modify that array, then return one wrapped around the object. At least you're then limiting the amount of duplication you do. A question naturally arises: What do you want to happen if I try to send a modify-yourself message to a member of the array? -s -- Copyright 2009, all wrongs reversed. Peter Seebach / usenet-nospam@... http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated! |
|
|
Re: encapsulation issueHi --
On Sat, 7 Nov 2009, James French wrote: > > >> -----Original Message----- >> From: David A. Black [mailto:dblack@...] >> Sent: 06 November 2009 14:01 >> To: ruby-talk ML >> Subject: Re: encapsulation issue >> >> Hi -- >> >> On Fri, 6 Nov 2009, James French 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 >> >> You can freeze the array: >> >> a = [].freeze >> a << 1 # TypeError: can't modify frozen array >> >> >> David >> >> -- >> The Ruby training with D. Black, G. Brown, J.McAnally >> Compleat Jan 22-23, 2010, Tampa, FL >> Rubyist http://www.thecompleatrubyist.com >> >> David A. Black/Ruby Power and Light, LLC (http://www.rubypal.com) > > But then I can't legitimately push to it in addDependency... Whoops. I had a nagging feeling I wasn't giving the question enough attention when I answered :-) I would probably favor the dup approach for the reader. In the end, someone can get around it: a.instance_eval { @dependencies << "bar" } But it would at least keep away casual and accidental appenders. David -- The Ruby training with D. Black, G. Brown, J.McAnally Compleat Jan 22-23, 2010, Tampa, FL Rubyist http://www.thecompleatrubyist.com David A. Black/Ruby Power and Light, LLC (http://www.rubypal.com) |
|
|
Re: encapsulation issueOn Nov 7, 12:50 am, James French <James.Fre...@...>
wrote: > > Is there any way of providing read only access to an array? [...] > > > a = A.new > a.addDependency("foo") > a.dependencies << "bar" # encapsulation subverted Ask yourself if it's really necessary to implement #dependencies. (The answer may be 'yes'; I'm just saying don't assume it is.) For instance, you could provide access to the dependencies like this class A # initialise and add_dependency as before include Enumerable def each(&block); @dependencies.each(&block); end def [](n) @dependencies[n] # possibly .dup this end end a = A.new a.add_dependency "foo" a.each do ... end a.map { ... } a.grep(...) a[5] I've often found, when wrapping a basic data type, that I don't need access to the 'guts' of that type; I only need to do a certain set of things, so I implement them and leave it at that. -- Gavin Sinclair |
|
|
Re: encapsulation issueOn Fri, Nov 6, 2009 at 7:50 AM, James French <James.French@...
> 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 > > 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. |
|
|
Re: encapsulation issue> -----Original Message----- > From: Gavin Sinclair [mailto:gsinclair@...] > Sent: 06 November 2009 23:56 > To: ruby-talk ML > Subject: Re: encapsulation issue > > On Nov 7, 12:50 am, James French <James.Fre...@...> > wrote: > > > > Is there any way of providing read only access to an array? [...] > > > > > > a = A.new > > a.addDependency("foo") > > a.dependencies << "bar" # encapsulation subverted > > Ask yourself if it's really necessary to implement #dependencies. > (The answer may be 'yes'; I'm just saying don't assume it is.) > > For instance, you could provide access to the dependencies like this > > class A > # initialise and add_dependency as before > > include Enumerable > def each(&block); @dependencies.each(&block); end > > def [](n) > @dependencies[n] # possibly .dup this > end > end > > a = A.new > a.add_dependency "foo" > a.each do ... end > a.map { ... } > a.grep(...) > a[5] > > I've often found, when wrapping a basic data type, that I don't need > access to the 'guts' of that type; I only need to do a certain set of > things, so I implement them and leave it at that. > > -- > Gavin Sinclair Thanks for that. I think I may go that way. |
|
|
Re: encapsulation issue> -----Original Message----- > From: Josh Cheek [mailto:josh.cheek@...] > 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@... > > 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. |
| Free embeddable forum powered by Nabble | Forum Help |