Crystal: Add Enumerable#take as a better named alias for Enumerable#first

Created on 2 Mar 2018  路  11Comments  路  Source: crystal-lang/crystal

After having a short conversation with @bew on Gitter I decided to open this as an issue. Enumerable currently has first and last methods which return the first and last elements of an Enumerable respectively. They also take an optional count parameter which allows you to get the first or last n elements.

I am proposing that Enumerable#take be added to compliment skip. It should return every element up to the count index.

An example of how this could be done:

module Enumerable(T)
  def take(count : Int)
    raise ArgumentError.new("Attempt to take negative size") if count < 0

    array = Array(T).new
    each_with_index do |e, i|
      array << e if i < count
    end
    array
  end
end

I'd be more than happy to PR this

discussion wontfix

Most helpful comment

first(5) reads fine to me, take is actually a little confusing since to me the act of taking means to move them, which implies take(5) is the same as shift(5) (i.e. it removes them from the array). I vote to close this: it's an unnecessary breaking change for pretty much negative benefit as far as I'm concerned.

All 11 comments

How is it different from first?

@jhass basically the only difference is that take requires an argument. Ruby also has first and take methods that you can use in the same way.

@z64 it's more about the naming than anything. When I see first I think first element, it's not until I see the API that I think first _n_ elements. Take however makes sense. I want to take 4 elements from the array. It would be a better named alias really.

That's a fine point for discussion, but we were just confused because the functionality was already there. It wasn't clear if you just didn't know this or wanted something different. You should update the issue description to reflect this.

@z64 how's that?

We have a pretty strict policy of no aliases in the standard library in particular and no two ways to do something in general, mainly to increase code understandabilty and decrease debate in the community about the right way to do something.

So to do this we would need to remove first with an argument

If take is more or less like first, most will agree there is no point to implement it.

But, if we can merge first and last in to take, why not?

My idea is to add support to negative counts, that will be used to return last n elements.

e.g: enumerable.take(-3) wil take the last 3 elements, and enumerable.take(3) the first ones.

Enumerable#skip could also support this.

first(5) reads fine to me, take is actually a little confusing since to me the act of taking means to move them, which implies take(5) is the same as shift(5) (i.e. it removes them from the array). I vote to close this: it's an unnecessary breaking change for pretty much negative benefit as far as I'm concerned.

@RX14 it wouldn't have to be breaking, just an addition, but whatever works

No, we already explained we don't have aliases in crystal. We have one name for one method. If there's two names for a method then everyone ends up learning that both names exist, and there's inevitably going to be conflicts between collaborators on which one to use (like this one). Closing.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

oprypin picture oprypin  路  3Comments

asterite picture asterite  路  3Comments

cjgajard picture cjgajard  路  3Comments

nabeelomer picture nabeelomer  路  3Comments

oprypin picture oprypin  路  3Comments