Proposal: Enum.take/1

88 views
Skip to first unread message

Sam Davies

unread,
Apr 20, 2017, 12:33:11 PM4/20/17
to elixir-lang-core
When working with collections it's often convenient to grab the first element that comes to hand. I find myself writing this a lot:

`Enum.take(collection, 1)` or `Enum.at(collection, 0)`

How about a function `Enum.take/1` which takes only the collection and returns the "first" value (I avoid naming it `Enum.first/1` since some collections may not have any concept of ordering).

OvermindDL1

unread,
Apr 20, 2017, 12:44:01 PM4/20/17
to elixir-lang-core
Two things:
1. The `List` module already has a `List.first/1`.
2. Not all enumerables have a concept of ordering, like a map, so I'm not sure an Enum version of such a thing makes conceptual sense?

Allen Madsen

unread,
Apr 20, 2017, 12:55:22 PM4/20/17
to elixir-l...@googlegroups.com
Also hd, which takes the head of the list.

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/69a0953e-07b3-4cc6-8cc0-bee718337ea5%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Sam Davies

unread,
Apr 22, 2017, 5:12:30 AM4/22/17
to elixir-lang-core, allen.c...@gmail.com
I understand the reasoning. That's why I suggest the name `take` NOT the name `first` to make it clear there is no implied ordering.

The use case for this is often while working in IEx. I have a collection of _somethings_ and I want to see what one _something_looks like. I don't care about ordering.

Rails' ActiveRecord has a method called `take` which does much the same thing - there is no implied ordering, it just grabs a member using some unspecified ordering and returns it.

We already have `take/1` which returns the "first" X elements, so it seems logical to me to extend that to `take/0` which returns the "first" ONE element.


On Thursday, April 20, 2017 at 5:55:22 PM UTC+1, Allen Madsen wrote:
Also hd, which takes the head of the list.
On Thu, Apr 20, 2017 at 12:44 PM, OvermindDL1 <overm...@gmail.com> wrote:
Two things:
1. The `List` module already has a `List.first/1`.
2. Not all enumerables have a concept of ordering, like a map, so I'm not sure an Enum version of such a thing makes conceptual sense?

On Thursday, April 20, 2017 at 10:33:11 AM UTC-6, Sam Davies wrote:
When working with collections it's often convenient to grab the first element that comes to hand. I find myself writing this a lot:

`Enum.take(collection, 1)` or `Enum.at(collection, 0)`

How about a function `Enum.take/1` which takes only the collection and returns the "first" value (I avoid naming it `Enum.first/1` since some collections may not have any concept of ordering).

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.

Amos King

unread,
Apr 22, 2017, 10:10:27 AM4/22/17
to elixir-l...@googlegroups.com
You want to add a default of 1 to Enum.take/2? I personally don't mind that but I think it takes away from the explicit nature of the module. I prefer explicitness if we are only saving a few keystrokes. 

Amos King
Binary Noggin

Myron Marston

unread,
Apr 22, 2017, 1:49:10 PM4/22/17
to elixir-lang-core
I don't think this would improve Elixir.  Elixir favors explicitness over implicitness and fewer keystrokes and the only argument for this seems to be convenience.

More worrying, `Enum.take/2` returns a list of items.  If there was an `Enum.take/1`, I'd expect it to simply default the number of items taken, but to still return a list (even if it's just a list of one item).  But from this thread it sounds like you're wanting an `Enum.take/1` that returns just the first item without it being wrapped in a list.  IMO, that would be incredibly confusing.  It would lead to different behavior for `&Enum.take/1` and `&Enum.take(&1, 1)` which would be very counter-intuitive.

Myron

Matt Jadczak

unread,
Apr 23, 2017, 12:23:38 PM4/23/17
to elixir-lang-core
I don't think this is needed, but as far as naming suggestions go, perhaps `Enum.one/1` would work, as it both indicates that a single element is returned, and doesn't necessarily imply ordering like `first` would. However, what happens when the Enum is empty? Do we need a bang and non-bang version? As others have said, I think that keeping this explicit is nicer. You can always add a private helper or a function to a project-level utility module if you use this often.

Sam Davies

unread,
Apr 25, 2017, 5:06:57 PM4/25/17
to elixir-lang-core
I like `Enum.one/1`. Agree that it's confusing to have `take/1` return a single element and `take/2` returning a list, although Rails' `take` works like this.

If the collection is empty it returns nil naturally. A bang and non-bang version could work, this would make it work like Ecto's `one/2` function.

As for keeping things explicit, if we wanted to be explicit we'd still be writing for loops in C ;). I like abstractions and a rich set of functions in the standard library, where it makes sense and doesn't duplicate functionality.

Amos King

unread,
Apr 25, 2017, 6:30:02 PM4/25/17
to elixir-l...@googlegroups.com
"Sins of the father." - I prefer consistency to having `take` return two different result types.

I think that `Enum.one\2` is a much better idea. I expect the second argument to default to nil and allow a default to be passed in.

There is a difference between verbose and explicit. Ruby's each is still explicit, but doesn't include the verbosity of a C for loop. I think abstractions are fine, and we should consider each one carefully. We need to think about their uses and if it should be in the core, an external library, or the code using it. Anything that makes it into the core must be maintained in the core. In thinking through this like the explicitness of the name, but it doesn't buy much more than utilizing `Enum.take\2`.

Amos King
Owner
Binary Noggin
=======================================================
I welcome VSRE emails. Learn more at http://vsre.info/
=======================================================

To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/9123abef-0f2a-47a8-8e93-69626f9515b2%40googlegroups.com.

Sam Davies

unread,
Apr 26, 2017, 1:26:32 AM4/26/17
to elixir-lang-core
Compare these two:

`hd Enum.take(collection, 1)` or `collection |> Enum.take(1) |> Enum.at(0)`

and this:

`Enum.one(collection)`

The second seems more readable to me and its purpose is more clear than either of the first two options.

Michał Muskała

unread,
Apr 26, 2017, 2:36:49 AM4/26/17
to elixir-lang-core
Proposed Enum.one(x) is exactly the same as Enum.at(x, 0). I'm not sure it's worth it intruding a new function just to shave off 2 characters.

Michał.

Sam Davies

unread,
Apr 26, 2017, 5:36:11 AM4/26/17
to elixir-lang-core
Hi Michal

It's not about saving keystrokes. It's about readability, clarity and intent of purpose.

You could make the same argument for  `List.first(x)`. Why use that when we already have `Enum.at(x, 0)` ?

José Valim

unread,
Apr 26, 2017, 6:09:21 AM4/26/17
to elixir-l...@googlegroups.com
You could make the same argument for  `List.first(x)`. Why use that when we already have `Enum.at(x, 0)` ?

Because it works only on lists and it gives an idea of ordering which Enum.at/2 does not have. :)

Enum.one does not any new property, validation or interpretation to the current API.

OvermindDL1

unread,
Apr 26, 2017, 10:37:17 AM4/26/17
to elixir-lang-core, jose....@plataformatec.com.br
Why does `Enum.at/2` exist anyway?  That seems to imply that the enumerable is something indexable, which may not be the case in something like a large map (and many other things)...
Reply all
Reply to author
Forward
0 new messages