Hello, I am pretty new to Elixir. I am noticing that when I run String.trim() against the output of IO.gets() in iex, I get an error, supposedly because String.trim() cannot trim a binary string.
test.ex
defmodule Test do
def test do
IO.puts(String.trim(IO.gets("write something: ")))
end
end
iex(1)> c "Test.ex"
[Test]
iex(2)> Test.test
write something: hello
** (FunctionClauseError) no function clause matching in String.trim/1
The following arguments were given to String.trim/1:
# 1
~c"hello\n"
Attempted function clauses (showing 1 out of 1):
def trim(string) when is_binary(string)
(elixir 1.15.4) lib/string.ex:1270: String.trim/1
Test.ex:3: Test.test/0
iex:2: (file)
But when I run the same logic in an .exs file, I see no error.
It’s the other way round. It can trim a utf-8 encoded binaries (what is called a string in elixir), but it can’t deal with charlists or iolists, which can also be returned from IO.gets.
I don’t know about any conditions, which would make it return one over the other though.
It looks like I’m running into this as well. What are the steps to updating my local environment? Running brew install elixir and brew reinstall elixir say I’m already up-to-date.
So, I found this thread and am running into a similar issue.
I have an exs script that requires the user to paste in a large string, and my observation is that when I use IO.gets/1 inside a script file, the size the paste it will accept is capped at around 1024 characters, but when I run IO.gets/1 inside an iex session I can, in fact, paste a larger string.
I recorded a short demo of what I am seeing. After the recording also verified I see this in fish as well as bash just to remove those varients from consideration.
This behavior seems to be a limitation of the shell you’re using. In my test setup (Elixir 1.15/OTP 26/Bash/Ubuntu), IO.gets/1 has a limit of 4096 characters.
This is consistent with using the read bult-in command which cuts off input at the same length in my environment.
This can be changed with the following shell command that changes the shell’s input behavior: stty -icanon. After you run this, both read and IO.gets/2 from an exs script can accept longer input.
If anyone else is curious, here’s a script to try this for yourselves.
input = IO.gets("Input your string ... ")
{type, length} =
cond do
is_binary(input) -> {"string", String.length(input)}
is_list(input) -> {"charlist", length(input)}
end
IO.puts("The input had a length of #{length}. It was a #{type}.")