From: Robert Klemme Date: 2008-06-07T21:28:49+09:00 Subject: Re: A crosspost from the Perl Community --------------040505040604000407060103 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit 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" :-) >>> External iterators are also like lvalue references and is something >>> ruby is missing (IMHO). >> Is it? >> >> irb(main):027:0> require 'generator' > This just gives a very limited external iterator that can read and > move forward (just like an internal iterator). In C++ terms, this > corresponds to one of the simplest - "Input Iterator". Other > operations you might want to do where the iterator is at would be: > write, move back, insert, delete, random access. Right you are. >>> An external iterator could be thought of as a >>> superset of the reference/pointer concept (external iterator looks >>> like a pointer in C++). >> Which is nicely done (in C++'s STL, I mean). But with blocks I don't really >> miss external iterators. I rarely have to iterate through multiple >> collections in lock step and if I had #zip served me well. > > #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). >> Maybe I'm just not doing enough development that involves sophisticated >> algorithms. :-) > > Well, the last year or so I've been exposed to quite a bit of > computational geometry and graph theory. Most of that has been in C++ > and a bit of Python (would have used Ruby, but needed a certain API). > Outside of that, my experience would say the same as you. Usually > simple data structures and access methods suffice. Thank you for this exchange! Kind regards robert --------------040505040604000407060103 Content-Type: text/plain; name="iter.rb" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="iter.rb" #!/bin/env ruby class Array class ArrayIterator def initialize(ar,pos) @array = ar @pos = pos @fw = pos >= 0 # hack to get #remove working end def value ensure_valid @array[@pos] end def value= val ensure_valid @array[@pos] = val end def insert val ensure_valid @array[@pos,0] = val end def remove ensure_valid x = @array.delete_at @pos @pos -= 1 if @fw x end def next? @fw = true @pos < @array.size - 1 end def next raise "At end" unless next? @fw = true @array[@pos += 1] end def previous? @fw = false @pos > 0 end def previous raise "At beginning" unless previous? @fw = false @array[@pos -= 1] end def valid? @pos >= 0 && @pos < @array.size end private def ensure_valid raise "Invalid" unless valid? end end def iterator(pos = 0) raise IndexError unless pos >= -1 - length && pos < length ArrayIterator.new self, pos < 0 ? length + 1 + pos : pos - 1 end end a = (1..5).to_a p a it = a.iterator while it.next? it.next puts it.value += 10 end p a it = a.iterator -1 while it.previous? it.previous puts it.value -= 5 end p a it = a.iterator while it.next? it.next if it.value % 2 == 0 it.remove else puts it.value += 33 end end p a --------------040505040604000407060103--