From: Eric Mahurin Date: 2008-06-07T23:33:44+09:00 Subject: Re: A crosspost from the Perl Community ------=_Part_17237_19830548.1212849297620 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Disposition: inline On 6/7/08, Robert Klemme wrote: > On 07.06.2008 04:30, Eric Mahurin wrote: > > > On Fri, Jun 6, 2008 at 10:49 AM, Robert Klemme > > wrote: > > > > > On 06.06.2008 17:01, Eric Mahurin wrote: > > > > > > > another solution: a) pass the node containing the link you want to > > > > operate along with something saying which link in the node (you'll > > > > probably also need a dummy node at the root/head), b) have a separate > > > > object for the link so you can pass it around (i.e. simply an Array of > > > > one element), c) pass a lambda that can modify the link. None of > > > > these are as elegant as an lvalue reference IMHO. In my early ruby > > > > days a few years ago I put some code in the rubyforge "reference" > > > > project. I still think having something like this readily available > > > > would be useful. > > > > > > > The usual solution in Ruby would probably be a) which I find perfectly > ok. > > > Since the manipulation is typically encapsulated inside a LinkedList > class > > > it does not bother me too much if there are two additional elements (for > > > head and tail). :-) But I can see how this might be a bit more elegant > with > > > references (although not as much to create an urgent need for references > in > > > Ruby). :-) > > > > > > > Definitely no urgent need, but a nice thing to have in a bag of > > tricks. It could be implemented in Ruby, but you'll get more > > efficiency if done in C (ruby implementation would typically need eval > > - at least for local vars). No special syntax needed. > > > > Acutally, there *is* an implementation already: > > irb(main):002:0> s=SimpleDelegator.new nil > => nil > irb(main):003:0> s.__getobj__ > => nil > irb(main):004:0> s.__setobj__ "foo" > => "foo" > irb(main):005:0> s > => "foo" > irb(main):006:0> s.__getobj__ > => "foo" > irb(main):007:0> s.__setobj__ "bar" > => "bar" > irb(main):008:0> s.__getobj__ > => "bar" > irb(main):009:0> s.length > => 3 > irb(main):010:0> s.gsub /./, 'X' > => "XXX" > > :-) But, this doesn't give you an lvalue reference, just an anonymous reference (which could be used for a case b implementation). A one element Array would work just as well: s = ["foo"] p s[0] # => "foo" s[0] = "bar" p s[0] # => "bar" I usually make a little class with [] and []= methods that take no args in the [], so I don't need the "0" and the [] suffix is equivalent to the * prefix in C/C++. Here would be an fairly efficient instance variable lvalue reference class: class InstanceVariable def initialize(obj, var); @obj=obj; @var=var; end def []; @obj.instance_variable_get(@var); end def []=(val); @obj.instance_variable_set(@var, val); end end node = Object.new node.instance_variable_set(:@next, nil) node2 = Object.new link = InstanceVariable.new(node, :@next) p link[] # => nil link[] = node2 p link[].equal?(node2) # => true p node.instance_variable_get(:@next).equal?(node2) # => true Here would be a more general class for referencing any lvalue: class LValue def initialize(&lvalue); @lvalue = lvalue; end def []; eval(@lvalue[].to_s, @lvalue.binding); end def []=(val); eval("proc {|v| #{@lvalue[].to_s} = v}", @lvalue.binding)[val]; end end def swap(a, b); b[], a[] = a[], b[]; end x = 1 y = 2 swap(LValue.new { :x }, LValue.new { :y }) p x # => 2 p y # => 1 > > #zip doesn't help if you want to write, back-up, insert, delete, etc > > during iteration. > > > > Correct. For Array this could easily be build as an external class > (attached is an experimental version). For Array, there isn't a whole lot of value for an external iterator, because we already have something that works as a poor man's replacement - index (an integer). The index can't do its own dereferencing (to read and write an element), but Array can using an index. In C++ STL, an external iterator can't do all operations either. To do an erase or insert for example, you call a method on the container with an iterator. I think external iterators are more useful for other data structures where you don't have random access - linked lists, trees, etc. I guess you could provide an index-like API (but the index might not be an integer) instead of a normal external iterator. BTW, another external iterator we already have is IO, which operates at a specific point in a file. Eric ------=_Part_17237_19830548.1212849297620--