Asd

Asd

Stream.peek, Stream.pop

Stream.peek and Stream.pop

I find Stream API limited and I often have to introduce workarounds for things like taking values from enumerable one by one without traversing the whole enumerable at one go.

To achieve this I do some functional magic which is completely unreadable and I honestly don’t understand it completely. It is also possible to do reduce/transform, but it introduce huge runtime overhead, slowing down enumeration around 4-5 times to closure solutions according to my homemade benchmarks.

Example

Works like this

one_to_five = 1..5
Stream.peek(one_to_five, fn first, enumerable ->
  IO.inspect first, label: :first
  IO.inspect Enum.to_list(enumerable), label: :all
end)

# Prints
# first: 1
# all: [1, 2, 3, 4, 5]

Stream.pop(one_to_five, fn first, rest ->
  IO.inspect first, label: :first
  IO.inspect Enum.to_list(rest), label: :rest
end)

# Prints
# first: 1
# all: [2, 3, 4, 5]

Please note that we pass the fn instead of doing something like {first, stream} = Stream.peek(stream) to ensure that the stream is automatically closed when the closure ends. I personally find it too defensive, but that’s how Stream and Enum works today.

Details

  • Each value in the enumerable is traversed only once, enumeration starts once and ends once.
  • When the closure is called, enumeration will be started and the rest of the enumerable will be a continuation wrapped in the Enumerable-compatible closure.

Use-cases

  • Parsing a CSV stream. Sometimes I need to get a headers line and all the rows from CSV stream. NimbleCSV only returns a single stream. There are three solutions do this problem:

    1. functional magic (the best in terms of performance but completely unreadable), doing
    2. Doing [headers] = Enum.take(stream, 1); Enum.reduce(stream), but it opens and closes the descriptor two times, which is a fairly expensive operation
    3. Doing a single Enum.reduce which tracks the state if we’re in the first element or not. Hard to implement, since it breaks the pipelining of Enumerable across functions
  • I wrote a very scary function to merge two ordered streams into one ordered stream, using functional magic. I think that functions proposed here would make the code much more readable

First Post!

josevalim

josevalim

Creator of Elixir

Does Enum.reduce have poor performance? That’s how we traverse the stream in all cases, so I don’t see how Stream.peek or any other operation would be faster than that?

Stream.transform does have a cost though.

Most Liked

Asd

Asd

Yeah, I was not quite clear in the last point. Enum.reduce is not slow, it just requires to move everything to reduce.

For example, if I have a function which accepts a Enumerable.t(%{String.t() => term()}) and it lazily evaluates it and writes it to database or log or whatever and I would want to transform a CSV stream from stream of lists into stream of maps, I’d have to do something weird and strange

Where Next?

Popular in Proposals: Ideas Top

beepboop
(re-post of: Feature idea: measure and expose socket latency · Issue #1890 · phoenixframework/phoenix_live_view · GitHub) This is relate...
New
alaadahmed
Hi folks, I tried Phoenix 1.7 and it is awesome, but I have small suggestion, which in my opinion will organize files in a better way. ...
New
byhemechi
Many web frameworks (e.g. Remix, Gatsby) have an option for their link components that begins the navigation request on hover so that whe...
New
cheerfulstoic
I feel like Elixir is getting big enough and old enough that I’m starting to experience problems with conflicting dependencies. An examp...
New
BartOtten
I’d like to propose that we refrain from using the term "DeadView" as the opposite of “LiveView” and instead choose an alternative. A new...
New
GregPhx
Greetings Everyone!!! A little bit of my background so it could be easier to understand where my comments are coming from, and to take t...
New
dogweather
Hi Phoenix community! First off, huge thanks for an amazing framework - Phoenix has been a joy to work with. I have a small UX suggestio...
New

Other popular topics Top

hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
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
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New

We're in Beta

About us Mission Statement