[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

[RCR] New [] Semantics

Bill Atkins

10/4/2004 11:24:00 PM

Currently, the following code

a = [1, 2, 3, 4, 5]
a[0, 3]

returns

[1, 2, 3]

This is somewhat counter-intuitive. Since Ruby has a built-in range
type, [] ought to take advantage of it. I propose that the []
operators be redefined so that this behavior can only be achieved by
explicitly providing a Range, e.g. a[0...3]. The original code would
then work like #values_at and return [1, 3].

Also, I don't know what happened with the earlier mention about the
confusion between .. / ... but I'm a supporter of getting rid of '...'
and just making .. inclusive. Exclusive ranges can be represented
with 0..(n + 1) if necessary. I don't know if this is appropriate for
an RCR.

I think the above [] behavior is more in keeping with POLS and is
slightly more intuitive than the current default.

Obviously this suggestion (and the sub-suggestion about .. and ...)
would break existing code. I don't know if RCR's are allowed to do
that, but I'm just throwing this idea out there.

Bill Atkins


98 Answers

Yukihiro Matsumoto

10/4/2004 11:37:00 PM

0

Hi,

In message "Re: [RCR] New [] Semantics"
on Tue, 5 Oct 2004 08:24:23 +0900, Bill Atkins <batkins57@gmail.com> writes:

|I think the above [] behavior is more in keeping with POLS and is
|slightly more intuitive than the current default.
|
|Obviously this suggestion (and the sub-suggestion about .. and ...)
|would break existing code. I don't know if RCR's are allowed to do
|that, but I'm just throwing this idea out there.

RCR's are allowed to break exisiting codes, but NOT ALLOWED to mention
POLS in them. Being intuitive is a weak reason to break
compatibility.

matz.


Ara.T.Howard

10/4/2004 11:44:00 PM

0

Florian Gross

10/5/2004 12:36:00 AM

0

Bill Atkins wrote:

> Currently, the following code
>
> a = [1, 2, 3, 4, 5]
> a[0, 3]
>
> returns
>
> [1, 2, 3]
>
> This is somewhat counter-intuitive. Since Ruby has a built-in range
> type, [] ought to take advantage of it. I propose that the []
> operators be redefined so that this behavior can only be achieved by
> explicitly providing a Range, e.g. a[0...3]. The original code would
> then work like #values_at and return [1, 3].

I've also thought about this circa one and a half year ago. (And I
didn't even realize that I'm using Ruby for that long a time already. I
still feel like I've only barely scratched the surface of what this
language is able to do and there's so many unexplored libraries,
concepts, mind sets that I haven't explored properly yet...)

That aside, my solution was to use ary[[0, 1..3, 4]] for this.

I coded up an implementation of it, but please note that this is quite
old code. I didn't know about values_at at the time I wrote it and I'm
not even sure if the code is correct in all cases. (Had I written this
now, I would want to have a handful of test cases, even though I might
hesitate to write them -- I really need to make this a habit.)

I have attached the code, because it is a quick way of testing this
alternate syntax from irb -- it might be especially interesting to see
what happens with other Enumerables in action -- it is hard to think
about such border cases without an implementation.

So, what do you think about using this syntax instead? It is slightly
more complex than the one you proposed of course, but it is also
consistent with ary[1..3] and could in theory be useful in more cases.

Regards,
Florian Gross
# this changes Array#[] so that it will also take arrays
# e. g.:
# ary = ["foo", "bar", "qux", "quz", "quv"]
# ary[[0..1, 0..2, 0..3]]
# => ["foo", "bar", "foo", "bar", "qux", "foo", "bar", "qux", "quz"]

# it also changes Array#[]=
# e. g.:
# ary = (100..110).to_a
# ary[[0..3, 6..9]] = (0..3).to_a + (6..9).to_a
# ary
# => [0, 1, 2, 3, 104, 105, 6, 7, 8, 9, 110]

class Array
alias :old_get :[]
def [](index, *more)
if !more.empty?
return old_get(index, *more)
# Ranges are likely handled more efficently internally therefore we ignore them
elsif index.respond_to?(:each) and !index.is_a? Range
result = []
index.each { |subindex|
element = self[subindex]
element = [element] unless element.is_a? Array
result += element
}
return result
else
return old_get(index)
end
end

alias :old_set :[]=
def []=(index, *more)
args = more.clone
to = more.pop
old_to = to.clone
raise ArgumentError unless to

if !more.empty?
return old_set(index, *args)
# Ranges are likely handled more efficently internally therefore we ignore them
elsif index.respond_to?(:each) and !index.is_a? Range
index.each { |subindex|
self[subindex] = to.slice!(0 ... subindex.length)
}
return old_to - to
else
return old_set(index, *args)
end
end
end

Yukihiro Matsumoto

10/5/2004 12:36:00 AM

0

Hi,

In message "Re: [RCR] New [] Semantics"
on Tue, 5 Oct 2004 08:54:53 +0900, Ara.T.Howard@noaa.gov writes:

|> Being intuitive is a weak reason to break compatibility.
|
|that's NOT what my wife says! ;-)

Don't tell her. She would notice we are weird people.
Maybe it's too late.

matz.


Charles Comstock

10/5/2004 1:07:00 AM

0

Bill Atkins wrote:
> Currently, the following code
>
> a = [1, 2, 3, 4, 5]
> a[0, 3]
>
> returns
>
> [1, 2, 3]
>
> This is somewhat counter-intuitive. Since Ruby has a built-in range
> type, [] ought to take advantage of it. I propose that the []
> operators be redefined so that this behavior can only be achieved by
> explicitly providing a Range, e.g. a[0...3]. The original code would
> then work like #values_at and return [1, 3].
>

Yes but [start,length] is capable of expressing ranges that make no
sense using [range]. For instance:

a = [:a,:b,:c,:d,:e,:f,:g,:h]
a[-2,2] # => [:g,:h]
a[-2..2] # => []
a[-2..-1] # => [:g, :h]
a[0..-1] # => [:a,:b,:c,:d,:e,:f,:g,:h]

Obviously it isn't too hard to convert between the two formats, but many
times it makes far more sense to express it in the [start,length] format
as opposed to the range format of start..end.

> Also, I don't know what happened with the earlier mention about the
> confusion between .. / ... but I'm a supporter of getting rid of '...'
> and just making .. inclusive. Exclusive ranges can be represented
> with 0..(n + 1) if necessary. I don't know if this is appropriate for
> an RCR.
>

This makes perfect sense when the range is over numeric values, but to
me ("a"..("c".succ)) is ugly and not easily read. Or any other range of
objects like that for that matter.

Charles Comstock

Bill Atkins

10/5/2004 1:15:00 AM

0

On Tue, 5 Oct 2004 10:09:52 +0900, Charles Comstock <cc1@cec.wustl.edu> wrote:
> This makes perfect sense when the range is over numeric values, but to
> me ("a"..("c".succ)) is ugly and not easily read. Or any other range of
> objects like that for that matter.

Good point. I hadn't thought about that. I just think the difference
between .. / ... is sort of confusing.

Bill Atkins


dblack

10/5/2004 1:22:00 AM

0

T. Onoma

10/5/2004 3:36:00 AM

0

On Monday 04 October 2004 09:09 pm, Charles Comstock wrote:
> Yes but [start,length] is capable of expressing ranges that make no
> sense using [range]. For instance:
>
> a = [:a,:b,:c,:d,:e,:f,:g,:h]
> a[-2,2] # => [:g,:h]
> a[-2..2] # => []
> a[-2..-1] # => [:g, :h]
> a[0..-1] # => [:a,:b,:c,:d,:e,:f,:g,:h]
>
> Obviously it isn't too hard to convert between the two formats, but many
> times it makes far more sense to express it in the [start,length] format
> as opposed to the range format of start..end.

Hmm... It's still signifies a range. So if there were just a notation, then it
might be nice. I'm not sure what that would be though.

Really, in looking over Ruby's Range class, it is bit limited. You can't
exclude the start element, and it doesn't provide a way to specify a
increment so you can't iterate over floats. A more complete range would have
the initializer something like:

Range.new(start, end, start_exclude=false, end_exclude=false, inc=1)

Again, sure the best way to make a nice neat literal notation for all that.
Although one simple suggestion is to have a '+' method to set the increment.

(1.0 .. 3.0 + 0.5).to_a #=> [1.0, 1.5, 2.0, 2.5, 3.0]

T.


Joe Cheng

10/5/2004 4:09:00 AM

0

Bill Atkins wrote:
> Also, I don't know what happened with the earlier mention about the
> confusion between .. / ... but I'm a supporter of getting rid of '...'
> and just making .. inclusive. Exclusive ranges can be represented
> with 0..(n + 1) if necessary. I don't know if this is appropriate for
> an RCR.

I find it surprising that several people have expressed so much aversion
to '...' that they would actually favor removing it from the language.
In all earnestness, why don't you just forget it exists?

While you may find inclusive ranges less confusing than exclusive
ranges, for some people (including me and, apparently[1], Ara),
exclusive ranges are more useful and intuitive.

Using exclusive ranges eliminates error-prone "n+1" calculations. As a
case in point, you said "0..(n + 1)" but I think you actually meant
"0..(n - 1)". This may have just been a typo on your part, but I
personally make a lot of mistakes of this kind when I have to use
inclusive ranges, especially when converting from start/end indexes to
offset/length.

[1]http://groups-beta.google.com/group/comp.lang.ruby/msg/a6cbf0...

Markus

10/5/2004 5:08:00 AM

0

On Mon, 2004-10-04 at 16:24, Bill Atkins wrote:

> Also, I don't know what happened with the earlier mention about the
> confusion between .. / ... but I'm a supporter of getting rid of '...'


I think I killed it (admittedly, the thread was on it's last legs
in any case) by pointing out an idiom (which everyone had seemed to
approve of) from the cypher-quiz that would be very hard to replicate as
concisely without exclusive ranges:

> Here's a simple example of where ... is very nice to have. You want
> to cut a deck and card x, so that x is on the top after the cut:
>
> deck = deck.values_at(x..-1,0...x)
>
> *grin* Try doing that as concisely without "..."


-- Markus