Hello,
I am using iex to learn Elixir and I have noticed something weird in iex while playing with StringIO.open
and Stream.chunk_while
.
If I copy and paste this code directly in iex, I will have an error:
open = fn -> {:ok, pid} = StringIO.open("12345"); pid end
chunk_fun = fn char, acc -> {:cont, char, [char | acc]} end
after_fun = fn acc -> {:cont, acc} end
# Note the break lines here
result =
open.()
|> IO.binstream(1)
|> Stream.chunk_while([], chunk_fun, after_fun)
Enum.to_list(result)
# The error:
** (Protocol.UndefinedError) protocol Enumerable not implemented for #PID<0.251.0> of type PID. This protocol is implemented for the following type(s): Date.Range, File.Stream, Function, GenEvent.Stream, HashDict, HashSet, IO.Stream, List, Map, MapSet, Range, Stream
(elixir 1.13.4) lib/enum.ex:1: Enumerable.impl_for!/1
(elixir 1.13.4) lib/enum.ex:143: Enumerable.reduce/3
(elixir 1.13.4) lib/enum.ex:4144: Enum.reverse/1
(elixir 1.13.4) lib/enum.ex:3491: Enum.to_list/1
For some reason, a pid is assigned to result
before calling Enum.to_list
But if I try different other ways, it will work:
- This works with pipes on a single line:
open = fn -> {:ok, pid} = StringIO.open("12345"); pid end
chunk_fun = fn char, acc -> {:cont, char, [char | acc]} end
after_fun = fn acc -> {:cont, acc} end
# Piping in a single line
result = open.() |> IO.binstream(1) |> Stream.chunk_while([], chunk_fun, after_fun)
Enum.to_list(result)
# => ["1", "2", "3", "4", "5"]
- This works when not using pipes:
open = fn -> {:ok, pid} = StringIO.open("12345"); pid end
chunk_fun = fn char, acc -> {:cont, char, [char | acc]} end
after_fun = fn acc -> {:cont, acc} end
# No pipes
stream = open.()
binstream = IO.binstream(stream, 1)
result = Stream.chunk_while(binstream, [], chunk_fun, after_fun)
Enum.to_list(result)
# => ["1", "2", "3", "4", "5"]
- This will works if I pipe and do not add a break line for the first pipe:
open = fn -> {:ok, pid} = StringIO.open("12345"); pid end
chunk_fun = fn char, acc -> {:cont, char, [char | acc]} end
after_fun = fn acc -> {:cont, acc} end
# 1 pipe on the first line, second pipe on the next line
result = open.() |> IO.binstream(1)
|> Stream.chunk_while([], chunk_fun, after_fun)
Enum.to_list(result)
# => ["1", "2", "3", "4", "5"]
If I put the not working version in a module then call the function module from iex, it works without issues.