ruby picture

RCR 204: Negative arg for Array#first and

Submitted by flgr (Thu Jan 29 17:01:58 UTC 2004)

Abstract

Array#last and Array#first should accept negative arguments relative to the end of the Array.

Problem

Currently Array#[] and Array#last / Array#first are inconsistent in their handling of negative arguments. It would be expected for both of them to work analogous in this case.

Proposal

Handle a negative argument to these constructs just like in Array#[]. (Add the length of the Array to it to make it relative to the end of the Array.)

Analysis

This would also add the rest() function of LISP (which was already wanted by some in the standard Ruby in the past) by generalising something which is already there.

There would be no incompatibilities caused by this because negative lengths previously had no meaning in this construct. (They used to raise an exception.)

Implementation

class Array
  def first(amount = 1); self[0 ... amount]; end
  def last(amount = 1); self[-amount .. -1]; end
end

if __FILE__ == $0
  ary = [1, 2, 3, 4, 5]
  p ary.first(2)
  p ary.last(-2)
end
ruby picture
Comments Current voting

What do you mean by "inconsistent"? The optional argument to "first" and "last" means number of items requested, not offset. For example, the second value for "ary[pos,len]" does not accept negative value.

-- matz.


I agree with matz. A negative parameter only makes sense when you are asking for an offset. When you are asking for the number of items to return, a negative number doesn't really apply.

-- Jamis


I think there shouldn't be a distinction between indices and lengths in this case -- I think #first and #last should really use Range fetches instead which would avoid also having to accept arr[1, -5]. (which doesn't seem to make sense to me)

I think it makes sense to think about the argument as an amount of values you're asking for which can be relative to the total amount of values available.

-- flgr


I couldn't see any reason for your "should". Can you show us why do you think they should be no distinction? I feel offsets and number of items are different, even though they are related (e.g. 0 .. number of items = range for those items). When I describe the "first(n)" method, it should be: "retrieve first n items from the array"; not "retrive items from offset zero to offset n (including n)", which makes me somewhat confusing.

- matz.


I think I see what you're getting at -- so this is about not exposing features of underlying implementations, because the underlying implementation might change and make it harder to make those features available?

I still think this would a nice compromise between another pair of methods and not having the features they would offer at all without introducing any icky flags and the like, but I think I can understand if you choose to reject this because of the above reason. (Though it would be a bit sad.)

-- flgr


When I request n items from an array, I think and I expect, n must be a natural number (non zero, positive integer). Respecting *my* expectation is the key of Ruby's design. If you want to persuade me, you have to give me rationale better than "compromise". How often do you want to retrieve "items but last n"? If you want often, it's good to have another pair of methods. If you want rarely, ary[0..-n] would be suffice.

-- matz.


I have found myself trying to use items.first(-1) multiple times, simply assuming that it would work, and feeling quite satisfied that Ruby allowed me to express the idea so succinclty. Except it didn't, and I was disappointed. To me, it seems prefectly reasonable to expect that since items[-1] selects the last item, items.first(-1) should select everything up to the last item.

Matz, you argue that this change would make it more difficult to explain exactly what the #first method does. That's certainly true, but isn't that a pretty small price to pay? After all, it still wouldn't be particularly hard: ``It selects the first item of the array. To select multiple initial items, give an integer argument. To count from the end, give a negative argument, just like with Array#[].''

Certainly, it is not immediately obvious what items.first(-1) means. However, that is equally true for items[-1], and I really think that if one works, then both should. It just seems like the natural thing to expect. And I definitely think that they should --- it's a really great notation.

Voted strongly in favor.

-- Daniel Brockman


Strongly opposed 5
Opposed 2
Neutral 2
In favor 2
Strongly advocate 3
ruby picture
If you have registered at RCRchive, you may now sign in below. If you have not registered, you may sign up for a username and password. Registering enables you to submit new RCRs, and vote and leave comments on existing RCRs.
Your username:
Your password:

ruby picture

Powered by .