Professional Web Applications Themes

Read-Only Array Access - Ruby

While I understand the (very valid) reasons that my RCR [see: http://rcrchive.net/rcr/RCR/RCR201] got shot down, an underlying problem still remains for me. I want to provide access to a full collection of elements (returned as an array, or iterated through an arbitrary .each{} block), but not let the objects be modified. Is this possible? For example, assume that a House has Furniture and ArtObjects inside it. I need to be able to modify those collections independently; at any time give external objects access to read the full collection; and (the hard part) prevent the objects in the collections from being ...

  1. #1

    Default Read-Only Array Access

    While I understand the (very valid) reasons that my RCR [see:
    http://rcrchive.net/rcr/RCR/RCR201] got shot down, an underlying problem
    still remains for me.

    I want to provide access to a full collection of elements (returned as
    an array, or iterated through an arbitrary .each{} block), but not let
    the objects be modified.

    Is this possible?

    For example, assume that a House has Furniture and ArtObjects inside it.
    I need to be able to modify those collections independently; at any time
    give external objects access to read the full collection; and (the hard
    part) prevent the objects in the collections from being changed.


    class House
    attr_reader(:furniture,:jewelry,:furnitureValue,:j ewelryValue)
    def initialize
    furniture,jewelry=[],[]
    furnitureValue,jewelryValue=0,0
    end
    def addFurniture (*newPieces)
    furniture.push(*newPieces)
    newPieces.each{ |p| furnitureValue+=p.value }
    end
    def addJewelry (*newPieces)
    jewelry.push(*newPieces)
    newPieces.each{ |p| jewelryValue+=p.value }
    end
    end
    class Obj
    attr_accessor(:name,:value)
    def initialize(name,value)
    name,value=name,value
    end
    end

    myHouse = House.new
    myHouse.addFurniture( Obj.new('Chair',100), Obj.new('Table',200) )
    myHouse.furniture.each{ |p| puts p.name } #fine
    myHouse.furniture.each{ |p| p.value*=2 }
    #uh-oh! myHouse.furnitureValue is now out of sync



    The problem cannot be solved by freezing furniture, since I want to be
    able to modify it at any time. The problem could be sort of solved by...

    def furniture
    return furniture.dup
    end

    ....except that (a) this provides 'silent' protection (the code can
    modify the values, it just doesn't do what was expected) and (b) the
    returned array is no longer synced with the original:

    foo = myHouse.furniture
    myHouse.addFurniture( Obj.new('Credenza',1000) )
    # foo has two items, the house really has three.



    So...how do I solve this? The problem is that a 'read-only' copy of an
    array doesn't prevent code from getting a read-only reference to an
    element in that array, and then modifying it directly.


    [And as an aside...I realize that the particular problem could be solved
    if I either disallowed .value= or recalculated the furnitureValue by
    iterating the array each time it was asked for. Or I could have the
    furniture pieces know what house they are in, and any time they are
    changed have them tell the house that they were modified and any
    dependent information needs to be recalculated. While all are solutions
    to the above, I can sense that I'm going to be repeatedly bumping up
    against this problem...the desire to keep a collection of elements who
    should be able to be read, but not directly modified.]
    Gavin Guest

  2. #2

    Default Re: Read-Only Array Access


    "Gavin Kistner" <com> schrieb im Newsbeitrag
    news:g9bSb.50590$U%.. 

    [snip]
     

    That ain't going to be solved easily: What you really want is to mark a
    *graph* of instances to be unmodifiable, i.e., if any instance in your
    collection returns some member, that in turn must not be modified, too
    etc.

    You could try to use Delegator and add a state variable "modifyable" which
    is evaluated by all modifying methods. The hard part here is to
    automatically know which methods are modifying methods...

    If you've got enough mem you can clone the whole object graph starting
    with the collection with the typical Marshal idiom "Marshal.load(
    Marshal.dump( collection ) )". But if the collection is big, this will
    burn a lot of mem and might take some time.

    If you follow discussions in C++ ng's about "const" and think a while
    about the matter than you'll discover a lot of annoying things that happen
    once you start to try to differentiate const and mutable instances. For
    example, consider lazy intialization: an instances state might look the
    same from the outside (hence it could be regarded as const), while the
    real state does change in certain situations. Now, is this instance const
    or not? etc.

    I'd say, don't invest too much time into this and rather doent which
    parts of the application are allowed to do modifications and which are
    not.

    Regards

    robert

    Robert Guest

  3. #3

    Default Re: Read-Only Array Access

    On Thu, 29 Jan 2004, Gavin Kistner wrote:
     

    first - why not freeze the objects in the array? or simply give an access
    method which does something like

    class House
    def each_furniture_peice
    furniture.each{|f| f = f.dup; f.freeze; yield f}
    end
    end


    and make this the _only_ method (and perhaps a few other) of getting at the
    furniture.


    or you could use interfaces:



    class FurniturePrivate
    def intialize peice; peice = peice; end
    def method_missing(meth, *args, &block); peice.send meth, *args, &block; end
    end

    class FurniturePublic
    def intialize peice; peice = peice; end

    def exposed_method(*args); peice.exposed_method *args; end
    end

    class House
    private
    class Furniture
    ...
    end

    def initialize
    furniture = [ Furniture.new, Furniture.new ]
    public_furniture = furniture.map{|f| FurniturePublic.new f}
    private_furniture = furniture.map{|f| FurniturePrivate.new f}
    end

    def _furniture
    private_furniture
    end

    public
    def furniture
    public_furniture
    end
    end

    there a million ways (all better probably too) to do the above - even
    generically.

    the basic idea is that you either need to limit access somehow or give two
    entirely different access methods (interfaces)

    other approaches could include a 'lock and key' approach whereby a peice
    refused to modify itself unless 'unlocked' by a key know only to the house...


    2 cts.

    -a
    --

    ATTN: please update your address books with address below!

    ================================================== =============================
    | EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
    | PHONE :: 303.497.6469
    | ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
    | STP :: http://www.ngdc.noaa.gov/stp/
    | NGDC :: http://www.ngdc.noaa.gov/
    | NESDIS :: http://www.nesdis.noaa.gov/
    | NOAA :: http://www.noaa.gov/
    | US DOC :: http://www.commerce.gov/
    |
    | The difference between art and science is that science is what we
    | understand well enough to explain to a computer.
    | Art is everything else.
    | -- Donald Knuth, "Discover"
    |
    | /bin/sh -c 'for l in ruby perl;do $l -e "print \"\x3a\x2d\x29\x0a\"";done'
    ================================================== =============================

    Ara.T.Howard Guest

Similar Threads

  1. Read stdin into an array?
    By George in forum PHP Development
    Replies: 5
    Last Post: December 10th, 01:33 PM
  2. Save an Array to a file and re-read it
    By brian_estep@mac.com in forum Macromedia Director Lingo
    Replies: 3
    Last Post: January 26th, 06:05 PM
  3. read integer from array
    By Sarah Ann Cook in forum PERL Modules
    Replies: 3
    Last Post: December 7th, 05:25 PM
  4. Replies: 1
    Last Post: August 16th, 07:21 AM
  5. Read from file into array
    By Matthew Sims in forum PHP Development
    Replies: 5
    Last Post: August 11th, 12:25 PM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139