Inconsistency in Array#[]

  • Thread starter Wojciech Piekutowski
  • Start date
W

Wojciech Piekutowski

Disclaimer: I know what docs say, but I'd prefer a different
behaviour. I want to understand why this design decision was made.

Some code first:
irb(main):001:0> a = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
irb(main):002:0> a[0,10]
=> [1, 2, 3, 4, 5] # ad 1
irb(main):003:0> a[-10,10]
=> nil # ad 2

1. Get 10 elements starting from the first element until the end of
the array. If array is smaller than 10 just return everything. This
makes sense, because in the range <0, 10) there are 5 elements that
can be returned.
2. Get 10 elements starting from the 10th element from the end, up to
the end. I got nil, but looking from -10 to 0 there are 5 elements, in
other words in the range (-10, 0> there are 5 elements, like in case
1.

I expected I'd get the same result as in 1 (yes, no additional nils,
just the whole array). I think this isn't really complying with the
principle of the least surprise. I'd be grateful if somebody can
explain me a reasoning behind this behaviour.

Greetings,
Wojciech Piekutowski
 
D

David A. Black

Hi --

Disclaimer: I know what docs say, but I'd prefer a different
behaviour. I want to understand why this design decision was made.

Some code first:
irb(main):001:0> a = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
irb(main):002:0> a[0,10]
=> [1, 2, 3, 4, 5] # ad 1
irb(main):003:0> a[-10,10]
=> nil # ad 2

1. Get 10 elements starting from the first element until the end of
the array. If array is smaller than 10 just return everything. This
makes sense, because in the range <0, 10) there are 5 elements that
can be returned.
2. Get 10 elements starting from the 10th element from the end, up to
the end. I got nil, but looking from -10 to 0 there are 5 elements, in
other words in the range (-10, 0> there are 5 elements, like in case
1.

I expected I'd get the same result as in 1 (yes, no additional nils,
just the whole array). I think this isn't really complying with the
principle of the least surprise. I'd be grateful if somebody can
explain me a reasoning behind this behaviour.

The way I see it, the process short-circuits as soon as it realizes
that you're asking it to start at an out-of-range index. The same
happens here:

array = [1,2,3]
array[5,10] # => nil, because there's no a[5]

I would also always expect that if this succeeds:

sub = array[x,y]

then this is true:

sub[0] == array[x]

since you've asked for a subarray starting at array[x]. If sub[0]
isn't array[x], then the subarray cannot be said to have started at
array[x].


David

--
David A. Black / Ruby Power and Light, LLC / http://www.rubypal.com
Q: What's the best way to get a really solid knowledge of Ruby?
A: Come to our Ruby training in Edison, New Jersey, September 14-17!
Instructors: David A. Black and Erik Kastner
More info and registration: http://rubyurl.com/vmzN
 
B

Bertram Scharpf

Hi,

Am Montag, 03. Aug 2009, 05:50:10 +0900 schrieb Wojciech Piekutowski:
Disclaimer: I know what docs say, but I'd prefer a different
behaviour. I want to understand why this design decision was made.

a = [1,2,3,4,5]
a[-10,10] #=> nil

I got nil, but looking from -10 to 0 there are 5 elements, in
other words in the range (-10, 0> there are 5 elements, like in case
1.

I expected I'd get the same result as in 1 (yes, no additional nils,
just the whole array). I think this isn't really complying with the
principle of the least surprise.

In the end, it is probably a matter of taste but I agree with you.
I would even prefer a behaviour like this:

a[3,-3] #=> [4,3,2]

This would be the least surprise to me.

I'm pleading for years for an `Array#notempty?' method analogous
to `Numeric#nonzero?' which would be a one-liner in C. But that
seems to be a real imposition on the developers community.

Bertram



________________________________________________________________

VALUE rb_ary_notempty( ary)
VALUE ary;
{
return RARRAY( ary)->len == 0 ? Qnil : ary;
}
 
B

Bertram Scharpf

Hi,

Am Montag, 03. Aug 2009, 09:11:11 +0900 schrieb Bertram Scharpf:
Am Montag, 03. Aug 2009, 05:50:10 +0900 schrieb Wojciech Piekutowski:
a = [1,2,3,4,5]
I would even prefer a behaviour like this:

a[3,-3] #=> [4,3,2]

This would be the least surprise to me.

Sorry! The least surprise of course would be

a[3,-3] #=> [3,2,1]

Bertram
 
H

Harry Kakueki

Hi,

Am Montag, 03. Aug 2009, 09:11:11 +0900 schrieb Bertram Scharpf:
Am Montag, 03. Aug 2009, 05:50:10 +0900 schrieb Wojciech Piekutowski:
a = [1,2,3,4,5]
I would even prefer a behaviour like this:

a[3,-3] #=> [4,3,2]

This would be the least surprise to me.

Sorry! The least surprise of course would be

a[3,-3] #=> [3,2,1]

Bertram

Really?

a = [1,2,3,4,5]
p a[3,2] #=> [4, 5]

#p a[3,-3] #=> [4,3,2]
#a[start,length]

This seems least surprising to me.


Harry
 
B

bbiker

Am Montag, 03. Aug 2009, 09:11:11 +0900 schrieb Bertram Scharpf:
Am Montag, 03. Aug 2009, 05:50:10 +0900 schrieb Wojciech Piekutowski:
  a = [1,2,3,4,5]
I would even prefer a behaviour like this:
  a[3,-3]    #=> [4,3,2]
This would be the least surprise to me.
Sorry! The least surprise of course would be
 a[3,-3]    #=> [3,2,1]

Really?

a = [1,2,3,4,5]
p a[3,2] #=> [4, 5]

#p a[3,-3] #=> [4,3,2]
#a[start,length]

This seems least surprising to me.

Harry

I'm sorry to butt in, but your getting exactly what you ask for but
you expecting otherwise!

a[x, y] means starting at element x give me up to y elements

a = [1.2.3.4,5]
a[-3,3] => [3,4,5]
a[-3,4] => [3.4,5]

a[-3,0] => []

a[3,-3] => # there is no such thing -3 elements therefore it
returns nil
 
H

Harry Kakueki

Am Montag, 03. Aug 2009, 09:11:11 +0900 schrieb Bertram Scharpf:
Am Montag, 03. Aug 2009, 05:50:10 +0900 schrieb Wojciech Piekutowski:
a = [1,2,3,4,5]
I would even prefer a behaviour like this:
a[3,-3] #=> [4,3,2]
This would be the least surprise to me.
Sorry! The least surprise of course would be
a[3,-3] #=> [3,2,1]

Really?

a = [1,2,3,4,5]
p a[3,2] #=> [4, 5]

#p a[3,-3] #=> [4,3,2]
#a[start,length]

This seems least surprising to me.

Harry

I'm sorry to butt in, but your getting exactly what you ask for but
you expecting otherwise!

a[x, y] means starting at element x give me up to y elements

a = [1.2.3.4,5]
a[-3,3] => [3,4,5]
a[-3,4] => [3.4,5]

a[-3,0] => []

a[3,-3] => # there is no such thing -3 elements therefore it
returns nil

I am not expecting otherwise.
I realize it does not work, and I understand why.
That is why it is commented out.

It was suggested that this type of behavior would be nice.

If it did work, I would expect it to work that way.

Harry
 
B

Bertram Scharpf

Hi,

Am Dienstag, 04. Aug 2009, 08:40:06 +0900 schrieb bbiker:
Am Montag, 03. Aug 2009, 09:11:11 +0900 schrieb Bertram Scharpf:
Sorry! The least surprise of course would be
=A0a[3,-3] =A0 =A0#=3D> [3,2,1]
=20
a =3D [1.2.3.4,5]
=20
a[3,-3] =3D> # there is no such thing -3 elements therefore it
returns nil

That's the way it is. I wrote that my suggestion is a matter of
taste and it's no more. The most weird thing would be to change
the language's definition and the common sense.

Anyway, it is still my opinion that there should be methods
Array#notempty?, Hash.notempty? and String.notempty? analogous to
Numeric#nonzero?. Expect me to repeat it soon.

Bertram


--=20
Bertram Scharpf
Stuttgart, Deutschland/Germany
http://www.bertram-scharpf.de
 
J

John W Higgins

[Note: parts of this message were removed to make it a legal post.]

Good evening,

Hi,


Anyway, it is still my opinion that there should be methods
Array#notempty?, Hash.notempty? and String.notempty? analogous to
Numeric#nonzero?. Expect me to repeat it soon.

Have you actually written the patch to implement these methods and had it
rejected? I can't imagine at least not getting a very good reason from the
core team why they wouldn't put it in if you have a patch in hand for
them......

John
 
R

Rob Biedenharn

Good evening,




Have you actually written the patch to implement these methods and
had it
rejected? I can't imagine at least not getting a very good reason
from the
core team why they wouldn't put it in if you have a patch in hand for
them......

John


Just take a look at the definition of blank? (and present?) from the
ActiveSupport gem

activesupport-2.3.2/lib/active_support/core_ext/blank.rb

Yeah, it is bundled with Rails and this is the Ruby list, but it's
only 58 lines (including comments and empty lines) of ruby code.

I typically add a NilClass#nonzero? just so nil plays nicely with
Numeric#nonzero? myself.

-Rob

Rob Biedenharn http://agileconsultingllc.com
(e-mail address removed)
 
B

Bertram Scharpf

B

Brian Candler

Rob said:
Just take a look at the definition of blank? (and present?) from the
ActiveSupport gem

activesupport-2.3.2/lib/active_support/core_ext/blank.rb

I think that demonstrates a problem - there are different ideas of what
"notempty?" means. In the case of ActiveSupport, a string which consists
entirely of whitespace is "blank?", even though it is not "empty?"
I typically add a NilClass#nonzero? just so nil plays nicely with
Numeric#nonzero? myself.

I find it useful how Javascript treats 0 and "" as false (although
strangely not an empty array). You can write things like

emit(doc.foo || null);

to make things consistent - null and empty string both map to null.

Maybe there's a case for something that you can rely on being present at
the Object level:

class Object; def true?; true; end; end
class NilClass; def true?; false; end; end
class FalseClass; def true?; false; end; end
class String; def true?; !empty?; end; end
class Array; def true?; !empty?; end; end
class Numeric; def true?; !zero?; end; end

Then 'true?' could be called automatically in boolean contexts, like
'if' and 'and'. The latter would be a big language change though.

I think the problem with this idea is the same as above: people would
disagree as to what's the natural definition of 'not empty', as it would
vary from one application to another.
 
B

Bertram Scharpf

Hi,

Am Dienstag, 04. Aug 2009, 21:59:21 +0900 schrieb Brian Candler:
Maybe there's a case for something that you can rely on being present at
the Object level:

class Object; def true?; true; end; end
class NilClass; def true?; false; end; end
class FalseClass; def true?; false; end; end
class String; def true?; !empty?; end; end
class Array; def true?; !empty?; end; end
class Numeric; def true?; !zero?; end; end

Again: I use it for default values. Here's an example.

class Array ; def notempty? ; self if any? ; end ; end

def halign list
...
end

halign lines.notempty? || %w{(no entries)}

Another name for any? doesn't help here.


Bertram
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top