Ninigi

Ninigi

Dedicated type for Stream - Why I think a stream is not an enumerable

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.

Most Liked

gregvaughn

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.

trisolaran

trisolaran

pi and sqrt(2) are irrational numbers, those are indeed uncountable.

Rational numbers are fractions: a/b.

The mapping between natural and rational numbers (proving that they are countable) is actually easier than one might think and kind of cool: https://www.homeschoolmath.net/teaching/rational-numbers-countable.php

Ninigi

Ninigi

Good point, and I admit I was arguing the wrong point.

Streams are enumerable, so are lists, maps etc. The difference is that streams are not finite, until they are. That makes streams different from other data structures implementing the enumerable protocol! Thanks for helping me with that :slight_smile:

I gotta be honest, I did not know why exactly it was bugging me so much, but I feel like I am getting a stronger case by gaining some insights.

Where Next?

Popular in Discussions Top

sashaafm
I’m trying to evaluate the best combo/stack for a BEAM Web app. Right now I’m exploring Yaws a bit, after having dealt with Phoenix for a...
New
arcanemachine
https://nitter.net/josevalim/status/1744395345872683471 https://twitter.com/josevalim/status/1744395345872683471
New
lucaong
Hello Elixir and Nerves community, I have been working for a while on an open-source embedded key-value database for Elixir, that I call...
230 13924 124
New
New
IVR
Hi all, I’ve seen a number of related threads in the past, but I’d still be very curious to hear an up-to-date opinion on this topic. I...
New
sashaafm
Piggy backing a bit on @dvcrn topic BEAM optimization for functions with static return type?, I’ve been trying to understand in a deeper ...
New
New
AstonJ
I’ve just started the Phoenix part of the utterly brilliant online course by @pragdave. On generating the Phoenix app he uses the --no-ec...
New
cblavier
Hey there, It’s been more than a year since we started using LiveView as our main UI library and building a whole library of UI componen...
New
scouten
I’m looking for a host for the server part of a small (personal) side project that I’m working on. It’s currently written in Node.js and ...
New

Other popular topics Top

sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 42920 311
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29377 241
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New

We're in Beta

About us Mission Statement