Selfassignment and close

I would like to overload the ‘+=’ operator. But it doesn’t seems to be
possible? If it isn’t possible, then how to use the ‘+’ operator and at
the same time get the instance #closed correctly ?

ruby a.rb
open 42
open 43
close 42
close 43

···

open 42
open 43
close 43

expand -t2 a.rb
class Iterator
def initialize(value)
@value = value
puts “open #{@value}”
end
def close
puts “close #{@value}”
end
def +(n)
self.class.new(@value + n)
end
end

a = Iterator.new(42)
b = a + 1
a.close
b.close

puts “-----------------------”

a = Iterator.new(42)
a += 1 # Question: How to do selfassignment ?
a.close

42 never gets closed!


Simon Strandgaard

Simon Strandgaard wrote:

a = Iterator.new(42)
a += 1 # Question: How to do selfassignment ?
a.close

42 never gets closed!

What’s happening here is that += is dependent on +, yet it is still
an assignment.

a += 1 is equivalent to a=a+1; so as you can see, a new object is
created and assigned to a.

You could always implement methods like succ or add that would
change the value without changing the object’s identity.

For an analogy with strings and arrays, these have a #replace
method that will change all the contents without changing the
object’s identity.

Or an append can be done with << on either of these also.

But = or += (with a nontrivial expression) would create new objects:

x = “abc”
y = [1,2,3]
def x.foo
puts “The string #{self} has a singleton”
end
def y.foo
puts “The array #{self} also has a singleton”
end

x.foo # The string abc has a singleton
y.foo # The array 123 also…
x << “def”
y << [4,5,6]
x.foo # The string abcdef has a …
y.foo # The array 123456 has…

x += “ghi”
y += [7,8,9]
x.foo # Error
y.foo # would also be an error

Does this clarify any?

Hal

something like this:

class Iterator
class << self
def objs; @objs ||= ; end
def reap; objs.each{|obj| obj.close}; end
def new(*args,&block); objs << (obj = super); obj; end
at_exit { Iterator.reap }
end
def initialize(value)
@value = value
puts “open #{@value}”
end
def close
puts “close #{@value}” unless @closed
@closed = true
end
def +(n)
self.class.new(@value + n)
end
end

#a = Iterator.new(42)
#b = a + 1
#a.close
#b.close

puts “-----------------------”

a = Iterator.new(42)
a += 1 # Question: How to do selfassignment ?
a.close

42 never gets closed!

if you rely on ObjectSpace.define_finalizer you don’t really know when the
call will be made, but perhaps something using it would be better… this
would cause an apparent ‘leak’ in long running programs. the general idea -
track objects within the class itself and make sure to free them - should be
workable for you though.

food for thought…

-a

···

On Fri, 28 Nov 2003, Simon Strandgaard wrote:

Date: Fri, 28 Nov 2003 20:24:58 +0100
From: Simon Strandgaard neoneye@adslhome.dk
Newsgroups: comp.lang.ruby
Subject: selfassignment and close

I would like to overload the ‘+=’ operator. But it doesn’t seems to be
possible? If it isn’t possible, then how to use the ‘+’ operator and at
the same time get the instance #closed correctly ?

ruby a.rb
open 42
open 43
close 42
close 43


open 42
open 43
close 43

expand -t2 a.rb
class Iterator
def initialize(value)
@value = value
puts “open #{@value}”
end
def close
puts “close #{@value}”
end
def +(n)
self.class.new(@value + n)
end
end

a = Iterator.new(42)
b = a + 1
a.close
b.close

puts “-----------------------”

a = Iterator.new(42)
a += 1 # Question: How to do selfassignment ?
a.close

42 never gets closed!

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 :: Solar-Terrestrial Physics Data | NCEI
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’
===============================================================================

Simon Strandgaard wrote:

a = Iterator.new(42)
a += 1 # Question: How to do selfassignment ?
a.close

42 never gets closed!

What’s happening here is that += is dependent on +, yet it is still
an assignment.

a += 1 is equivalent to a=a+1; so as you can see, a new object is
created and assigned to a.

I know that. What I don’t know, are if there are any tricks when dealing
with ‘+=’ ?

You could always implement methods like succ or add that would
change the value without changing the object’s identity.

Yes I already have #next and #prev.

Does this clarify any?

Conclusion: providing a PLUS (‘+’) operator, can be dangerous because the
user can invoke ‘+=’ and the instance will not get #closed correctly.
safer to undef ‘+’.

···

On Sat, 29 Nov 2003 04:47:37 +0900, Hal Fulton wrote:


Simon Strandgaard

I would like to overload the ‘+=’ operator. But it doesn’t seems to be
possible? If it isn’t possible, then how to use the ‘+’ operator and at
the same time get the instance #closed correctly ?
[snip code]

if you rely on ObjectSpace.define_finalizer you don’t really know when the
call will be made, but perhaps something using it would be better… this
would cause an apparent ‘leak’ in long running programs. the general idea -
track objects within the class itself and make sure to free them - should be
workable for you though.

I had something similar, a WrapperIterator which kept track of all clones.
When the operation were completed, I could then sweep them.
But I don’t consider it as a ‘real’ solution :slight_smile:

It has to be solved correct, before im satisfied.

···

On Fri, 28 Nov 2003 14:54:59 -0700, Ara.T.Howard wrote:

On Fri, 28 Nov 2003, Simon Strandgaard wrote:


Simon Strandgaard

expand -t2 wrapper_close.rb
require ‘iterator’ # http://raa.ruby-lang.org/list.rhtml?name=iterator

class Scanner
def initialize(iterator)
@iterator = iterator
end
def execute
a = @iterator.clone
b = @iterator.clone
c = @iterator.clone
d = @iterator.clone
end
end

keep track of how many instances we have

class CountingIterator < Iterator::Collection
@@count = 0
def clone
@@count += 1
super()
end
def self.count; @@count end
def close
@@count -= 1
super()
end
end

class WrapperIterator < Iterator::Base
def initialize(iterator, stack=nil)
@iterator = iterator
@stack = stack ||
end
def clone
i = @iterator.clone
@stack << i
WrapperIterator.new(@iterator, @stack)
end
def close
@stack.map{|i| i.close; nil}
end
end

ary = (0…19).to_a
iterator = CountingIterator.new(ary)
#wrap_iterator = iterator
wrap_iterator = WrapperIterator.new(iterator)
s = Scanner.new(wrap_iterator)
s.execute
p CountingIterator.count
wrap_iterator.close # ensure all iterators gets closed
p CountingIterator.count

ruby wrapper_close.rb
4
0

“Simon Strandgaard” neoneye@adslhome.dk schrieb im Newsbeitrag
news:pan.2003.11.28.20.00.51.850573@adslhome.dk…

Simon Strandgaard wrote:

a = Iterator.new(42)
a += 1 # Question: How to do selfassignment ?
a.close

42 never gets closed!

What’s happening here is that += is dependent on +, yet it is still
an assignment.

a += 1 is equivalent to a=a+1; so as you can see, a new object is
created and assigned to a.

I know that. What I don’t know, are if there are any tricks when dealing
with ‘+=’ ?

You could always implement methods like succ or add that would
change the value without changing the object’s identity.

Yes I already have #next and #prev.

Does this clarify any?

Conclusion: providing a PLUS (‘+’) operator, can be dangerous because
the
user can invoke ‘+=’ and the instance will not get #closed correctly.
safer to undef ‘+’.

IMHO “+” carries the wrong semantics for an iterator in Ruby: you don’t
want a new object to be created, instead you want the iterator to change
its state.

If you want to provide numeric updates, why not just define succ like
this:

def succ(inc=1) … end

Regards

robert
···

On Sat, 29 Nov 2003 04:47:37 +0900, Hal Fulton wrote:

[snip]

If you want to provide numeric updates, why not just define succ like
this:

def succ(inc=1) … end

Its already defined like this:

# move <i>n</i> steps forward
def next(n=1)
	n.times { self.next1 }
	self
end

# move <i>n</i> steps backwards
def prev(n=1)
	n.times { self.prev1 }
	self
end  

Thanks anyway :slight_smile:

···

On Mon, 01 Dec 2003 08:57:26 +0100, Robert Klemme wrote:


Simon Strandgaard

“Simon Strandgaard” neoneye@adslhome.dk schrieb im Newsbeitrag
news:pan.2003.12.01.14.03.56.882810@adslhome.dk…

[snip]

If you want to provide numeric updates, why not just define succ like
this:

def succ(inc=1) … end

Its already defined like this:

Great! So you read my mind even before I could. :slight_smile:

Thanks anyway :slight_smile:

You’re welcome! :slight_smile:

robert
···

On Mon, 01 Dec 2003 08:57:26 +0100, Robert Klemme wrote: