Skip to content

Commit 42fc70a

Browse files
author
José Valim
committed
Deprecate Enum.first/1 in favor of Enum.at/2 and List.first/1
The main reason for this change is because `Enum.first/1` does not communicate that enumeration will happen, in contrast to functions like Enum.at/2 and Enum.fetch/2 which are meant to be used with non-indexed collections and the need for enumeration is made a bit more obvious. Closes #1983
1 parent 87fee37 commit 42fc70a

File tree

5 files changed

+30
-36
lines changed

5 files changed

+30
-36
lines changed

lib/elixir/lib/enum.ex

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -741,22 +741,15 @@ defmodule Enum do
741741
end
742742
end
743743

744-
@doc """
745-
Returns the first item in the collection or `nil` if the collection is empty.
746-
747-
## Examples
748-
749-
iex> Enum.first([])
750-
nil
751-
iex> Enum.first([1, 2, 3])
752-
1
753-
754-
"""
744+
@doc false
755745
@spec first(t) :: :nil | element
756-
def first([]), do: nil
757-
def first([h|_]), do: h
746+
def first(list) when is_list(list) do
747+
IO.write "Enum.first/1 is deprecated, please use Enum.at/2 or List.first/1 instead\n#{Exception.format_stacktrace}"
748+
List.first(list)
749+
end
758750

759751
def first(collection) do
752+
IO.write "Enum.first/1 is deprecated, please use Enum.at/2 instead\n#{Exception.format_stacktrace}"
760753
Enumerable.reduce(collection, { :cont, nil }, fn(entry, _) ->
761754
{ :halt, entry }
762755
end) |> elem(1)

lib/elixir/lib/list.ex

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,23 @@ defmodule List do
116116
:lists.foldr(function, acc, list)
117117
end
118118

119+
@doc """
120+
Returns the first element in `list` or `nil` if `list` is empty.
121+
122+
## Examples
123+
124+
iex> List.first([])
125+
nil
126+
iex> List.first([1])
127+
1
128+
iex> List.first([1, 2, 3])
129+
1
130+
131+
"""
132+
@spec first([elem]) :: nil | elem when elem: var
133+
def first([]), do: nil
134+
def first([h|_]), do: h
135+
119136
@doc """
120137
Returns the last element in `list` or `nil` if `list` is empty.
121138
@@ -130,12 +147,9 @@ defmodule List do
130147
131148
"""
132149
@spec last([elem]) :: nil | elem when elem: var
133-
134-
def last([]), do: nil
135-
136-
def last(list) do
137-
:lists.last(list)
138-
end
150+
def last([]), do: nil
151+
def last([h]), do: h
152+
def last([_|t]), do: last(t)
139153

140154
@doc """
141155
Receives a list of tuples and returns the first tuple

lib/elixir/test/elixir/enum_test.exs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,6 @@ defmodule EnumTest.List do
143143
assert Enum.fetch([2, 4, 6], -4) == :error
144144
end
145145

146-
test :first do
147-
assert Enum.first([]) == nil
148-
assert Enum.first([1, 2, 3]) == 1
149-
end
150-
151146
test :filter do
152147
assert Enum.filter([1, 2, 3], fn(x) -> rem(x, 2) == 0 end) == [2]
153148
assert Enum.filter([2, 4, 6], fn(x) -> rem(x, 2) == 0 end) == [2, 4, 6]
@@ -530,14 +525,6 @@ defmodule EnumTest.Range do
530525
refute Enum.empty?(range)
531526
end
532527

533-
test :first do
534-
range = 1..0
535-
assert Enum.first(range) == 1
536-
537-
range = 1..2
538-
assert Enum.first(range) == 1
539-
end
540-
541528
test :each do
542529
try do
543530
range = 1..0

lib/mix/lib/mix/tasks/local.install.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ defmodule Mix.Tasks.Local.Install do
3232
def run(argv) do
3333
{ opts, argv, _ } = OptionParser.parse(argv, switches: [force: :boolean])
3434

35-
unless path = Enum.first(argv) do
35+
unless path = List.first(argv) do
3636
path = Mix.Archive.name(Mix.project[:app], Mix.project[:version])
3737

3838
unless File.exists?(path) do
@@ -66,8 +66,8 @@ defmodule Mix.Tasks.Local.Install do
6666
end
6767

6868
defp previous_version_filename(src) do
69-
app = Mix.Archive.dir(src) |> String.split("-") |> Enum.first
70-
Path.join(Mix.Local.archives_path, app <> "-*.ez") |> Path.wildcard |> Enum.first
69+
app = Mix.Archive.dir(src) |> String.split("-") |> List.first
70+
Path.join(Mix.Local.archives_path, app <> "-*.ez") |> Path.wildcard |> List.first
7171
end
7272

7373
defp remove_previous_version(_previous=nil) do

lib/mix/lib/mix/tasks/local.uninstall.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ defmodule Mix.Tasks.Local.Uninstall do
1919
archive = Mix.Local.archives_path
2020
|> Path.join(name <> "-*.ez")
2121
|> Path.wildcard
22-
|> Enum.first
22+
|> List.first
2323

2424
unless archive do
2525
raise Mix.Error, message: "Could not find a local archive named #{inspect name} "<>

0 commit comments

Comments
 (0)