[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Coercion and ranges

Philipp Kern

5/27/2005 11:13:00 PM

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
5 Answers

ES

5/27/2005 11:37:00 PM

0


Le 27/5/2005, "Philipp Kern" <trash@philkern.de> a écrit:
>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.

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

5/28/2005 1:09:00 AM

0


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 jim@weirichhouse.org http://onest...
-----------------------------------------------------------------
"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

5/28/2005 9:02:00 AM

0

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

5/30/2005 7:23:00 AM

0

Philipp Kern wrote:
> 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#+.

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

5/30/2005 9:44:00 PM

0

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