Ninigi
As an example I picked a random function in the Stream module
@spec chunk_every(Enumerable.t(), pos_integer) :: Enumerable.t()
def chunk_every(enum, count), do: chunk_every(enum, count, count, [])
Returns an Enumerable, which is technically true, but streams are different in many ways from the data we handle in Enum, for example:
# Direcly related to the line in the Elixir source code I linked to
iex> Enum.chunk_every([1, 2, 3, 4, 5, 6], 2)
[[1, 2], [3, 4], [5, 6]]
iex> Stream.chunk_every([1, 2, 3, 4, 5, 6], 2)
#Stream<[
enum: [1, 2, 3, 4, 5, 6],
funs: [#Function<3.58486609/1 in Stream.chunk_while/4>]
]>
The fact that inspect returns different results is a strong indicator to me that it is not the same.
Here is a more practice oriented example:
defmodule Printer do
def print([]), do: IO.puts("End of Input")
def print([something | rest]) do
IO.inspect(something)
print(rest)
end
end
iex> "asdf,11111,0000,last" |> String.split(",") |> Printer.print()
"asdf"
"11111"
"0000"
"last"
End of Input
:ok
iex> "asdf,11111,0000,last" |> String.splitter(",") |> Printer.print()
** (FunctionClauseError) no function clause matching in Printer.print/1
iex> "asdf,11111,0000,last" |> String.splitter(",") |> Enum.each(&IO.inspect/1)
"asdf"
"11111"
"0000"
"last"
:ok
Streams and Enumerables behave the same in many cases, and the Enum module knows how to treat streams, but they are (for practical purposes) not the same. Stream even has its own module to deal with streams, or convert enumerables into a stream, and vice versa Enum takes streams and converts them into enumerables.
Definition of enumerable
able to be counted by one-to-one correspondence with the set of all positive integers.
The definition of a stream is that it cannot be determinate, because as soon as it becomes determinate (as for example in reduce), it stops being a stream - hence a stream cannot be counted, because as soon as you know a stream has x members, you converted it into an enumerable. Follows that a stream is not an enumerable.
Maybe I am missing something important here, please let me know if I do, but everything I know about streams and enumerables points to their functions should have returns with different types.
EDIT: I feel like I was just ranting - but what I actually wanted was either an explanation of why it’s not possible, or a prompt to open an issue on the Elixir source code.
EDIT2: I get that implementing protocols is different from the type now - I am still not sure why the typespec is Enumerable though. Easier for the implementation?
EDIT3: Now I get it… duck typing. It still feels wrong to return Enumerable for a (by definition) non enumerable.
Trending in Discussions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #security










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
lud
That function does not work with streams but does neither work for all enumerable types. It only accepts lists.
For instance, maps are enumerables:
If your Printer module should work with any enumerable, it should use
Enum.map/2orEnum.each/2instead of pattern matching on lists recursively. And that would work with streams too.Ninigi
Thanks, that actually cleared up a lot for me!
Streams implement the enumerable protocol, but they are not enumerable.
I was pretty sure I must be missing something - but I couldn’t figure it out. Again, thanks
NobbZ
How are they not?
Ninigi
Because by definition, they are literally not enumerable. You cannot count them, unless you convert them into an enumerable.
They are more like… I can’t think of a good word here… I keep thinking about “traversable”, but that’s not right, because that would indicate you can have trees, or nodes etc., right?
NobbZ
They are countable.
There are enough natural numbers to give each element in a stream an index.
Ninigi
They are not countable until they stop being a stream.
I don’t want to sound condescending, but here is an analogy:
enumerable: I give you a basket full of apples. I ask you to count them. There are 10 apples. Countable.
stream: I give you one apple. And another one, and another one, and another one. I ask you how many I am going to give you. You have no idea until I tell you “that’s it”. Uncountable.
gregvaughn
Here’s my analogy. That is “counted”. Countable means that it is possible to count, not that it has already happened in the past.
Ninigi
Not sure if you are contradicting, or backing me
NobbZ
Even the latter example is countable, as for each apple you increase the current count by one.
Being countable does not mean “finite”.
The set of natural numbers is countable.
The set of integers is countable, as there is a technique to map one natural number to each integer. 0 is zero, positive integers are
n * 2, negative integers are mapped to1 - (n * 2). Or something like that, I don’t remember exactly.The set of rationals isn’t, as you can’t clearly map a single natural number to a single rational number.
Math differs between a finite countable, infinite countable and infinite uncountable set.
NobbZ
Contradicting.