eksperimental
unread,Sep 25, 2015, 2:30:39 PM9/25/15Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Sign in to report message
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to elixir-l...@googlegroups.com
While creating a new Enum.pad and Enum.pad_zip function, and
writting the tests I came accross a few issues dealing with empty
enumerables, that I think it's worth to look at.
1) On empty ranges
Should we have empty ranges?
Well, we do have them somehow.
iex> %Range{}
nil..nil
iex> %Range{first: nil, last: nil}
nil..nil
iex> Range.new(nil, nil)
nil..nil
iex> %Range{} == Range.new(nil, nil)
true
iex> Range.new(nil, nil) == nil..nil
** (ArgumentError) ranges (left .. right) expect both sides to be
integers, got: nil .. nil
(elixir) expanding macro: Kernel.../2
iex:52: (file)
iex> %Range{} == nil..nil
** (ArgumentError) ranges (left .. right) expect both sides to be
integers, got: nil .. nil
(elixir) expanding macro: Kernel.../2
iex:51: (file)
I think the message is wrong, saying that expects both sides to be an
integer, since nil..nil is a valid range.
I think Enumerable.Range.validate_range!/2 should be fixed to accept
nil..nil as a valid range.
*****************************************
2) Empty ranges should return 0 on Enum.count/1 and should return an
empty list when converted to a list
iex> %Range{}
nil..nil
iex> %Range{} |> Enum.count
** (ArgumentError) ranges (left .. right) expect both sides to be
integers, got: nil..nil (elixir) lib/range.ex:100:
Enumerable.Range.validate_range!/2 (elixir) lib/range.ex:90:
Enumerable.Range.count/1 (elixir) lib/enum.ex:437: Enum.count/1
iex> %Range{} |> Enum.to_list
** (ArgumentError) ranges (left .. right) expect both sides to be
integers, got: nil..nil
(elixir) lib/range.ex:100: Enumerable.Range.validate_range!/2
(elixir) lib/range.ex:56: Enumerable.Range.reduce/3
(elixir) lib/enum.ex:1389: Enum.reduce/3
(elixir) lib/enum.ex:2128:
Enum.to_list/1
# Same when we want to take an element
iex(49)> %{} |> Enum.take(1)
[]
iex(50)> %Range{} |> Enum.take(1)
** (ArgumentError) ranges (left .. right) expect both sides to be
integers, got: nil..nil
(elixir) lib/range.ex:100: Enumerable.Range.validate_range!/2
(elixir) lib/range.ex:56: Enumerable.Range.reduce/3
(elixir) lib/enum.ex:1948: Enum.take/2
*****************************************
3) Stream.cycle/1 : cycling over an empty list should return an
empty list.
iex(42)> [:a] |> Enum.take(1)
[:a]
iex(43)> [:a] |> Enum.take(0)
[]
iex(44)> [] |> Enum.take(1)
[]
iex(45)> [] |> Enum.take(0)
[]
iex(46)> Stream.cycle([:a]) |> Enum.take(1)
[:a]
iex(47)> Stream.cycle([:a]) |> Enum.take(0)
[]
iex(48)> Stream.cycle([]) |> Enum.take(1)
** (FunctionClauseError) no function clause matching in anonymous fn/1
in Stream.cycle/1
(elixir) lib/stream.ex:920: anonymous fn({[], []}) in
Stream.cycle/1
(elixir) lib/stream.ex:1152: Stream.do_unfold/4
(elixir) lib/enum.ex:1948: Enum.take/2
iex(48)> Stream.cycle([]) |> Enum.take(0)
[]
# Here's a bug, it hangs endlessly when provided an empty map
iex(63)> Stream.cycle(%{}) |> Enum.take(1)
******************
It think the idea of empty ranges and streams, like in any other
enumerable makes sense.
Let me know what you guys think about it?
- eksperimental