Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Coercion and ranges

0 views
Skip to first unread message

Philipp Kern

unread,
May 27, 2005, 7:13:26 PM5/27/05
to
Dear Ruby fellows,

what is the reason behind the fact that there is no generic coercion
system apart from the additional overhead?

Concretly I tried to add some ranges. Childish as I am I thought of a
straightforward way by implementing Range#+:

class Range
def +(other)
self.entries + other.entries
end
end

However, this does not work on multiple ranges as a temporary array is
constructed, which does not know of the ability to coerce ranges to arrays.

irb(main):001:0> (?A..?C) + (?a..?c)
=> [65, 66, 67, 97, 98, 99]
irb(main):002:0> (?A..?C) + (?a..?c) + (?0..?3)
TypeError: cannot convert Range into Array
from (irb):2:in `+'
from (irb):2

From my understanding the conversion should happen automatically when
coercion is properly implemented. Surely one could just add "to_a" to
all the ranges, but it certainly made me pondering about it.

Kind regards,
Philipp Kern

ES

unread,
May 27, 2005, 7:36:53 PM5/27/05
to

I think you probably would be able to create a properly working
addition operator, but you should consider the semantics, as well.
What logical range is represented by (?A..?C) + (?0..?3)? I believe
any range should be characterized by being able to move from start
to end by repeatedly calling #succ.

So you could presumably do something like

def +(other)
(self.first..other.last)
end

>Kind regards,
>Philipp Kern

E

--
template<typename duck>
void quack(duck& d) { d.quack(); }


Jim Weirich

unread,
May 27, 2005, 9:08:37 PM5/27/05
to

Philipp Kern said:
> From my understanding the conversion should happen automatically when
> coercion is properly implemented. Surely one could just add "to_a" to
> all the ranges, but it certainly made me pondering about it.

I find it a bit odd that adding two ranges results in an array, but
assuming that is /really/ what you want, you could indicate a Range's
willingness to be converted to an array by including a to_ary method.

class Range
def to_ary
to_a
end
end

> (?A..?C) + (?a..?c) + (?x..?y)
=> [65, 66, 67, 97, 98, 99, 120, 121]

The difference between to_a and to_ary is that to_a is an explicit
conversion to an array. to_ary indicates that whenever the object is
found in the context where an array is desired, it can be treated as an
array by calling to_ary (an implicit conversion).

--
-- Jim Weirich j...@weirichhouse.org http://onestepback.org
-----------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)

Philipp Kern

unread,
May 28, 2005, 5:02:04 AM5/28/05
to
Jim Weirich wrote:
> I find it a bit odd that adding two ranges results in an array, but
> assuming that is /really/ what you want, you could indicate a Range's
> willingness to be converted to an array by including a to_ary method.

Well if I see the range as an array of its elements (which you would get
when you iterate over it), then it's what one might want. Thank you,
that solved it. I thought about to_ary yesterday night, but I was not
aware that it would be called by Array#+.

Kind regards,
Philipp Kern

Robert Klemme

unread,
May 30, 2005, 3:22:40 AM5/30/05
to

Another probably more efficient variant would be to create a special class
that represents sums (= sequences) of Enumerables:

class EnumSequence
include Enumerable

def initialize(*enums) @enums = enums end

def each(&b)
@enums.each {|e| e.each(&b)}
self
end

def +(enum)
@enums << enum
self
end
end

class Range
def +(r) EnumSequence.new(self,r) end
end

>> x = (1..10) + (100..101) + (23..25)
=> #<EnumSequence:0x100c3d48 @enums=[1..10, 100..101, 23..25]>
>> x.to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 101, 23, 24, 25]

Kind regards

robert

Philipp Kern

unread,
May 30, 2005, 5:43:33 PM5/30/05
to
Robert Klemme wrote:
> Another probably more efficient variant would be to create a special class
> that represents sums (= sequences) of Enumerables:

It's at least the more elegant solution, thank you Robert. (:

Kind regards,
Philipp Kern

0 new messages