Why do tuples not implement the String.Chars protocol?

1,551 views
Skip to first unread message

w.m.w...@student.rug.nl

unread,
Mar 31, 2016, 8:20:57 AM3/31/16
to elixir-lang-talk
iex> IO.inspect {1,2,3}
{1,2,3}

iex
> IO.puts {1,2,3}
** (Protocol.UndefinedError) protocol String.Chars not implemented for {1,2,3}

Is there a reason why the String.Chars protocol is not implemented for tuples?

Onorio Catenacci

unread,
Mar 31, 2016, 8:38:51 AM3/31/16
to elixir-lang-talk
I cannot tell you _why_ the behavior was designed in this fashion but I can point you to something that will give you a workaround:


--
Onorio

Eric Meadows-Jönsson

unread,
Mar 31, 2016, 9:41:26 AM3/31/16
to elixir-l...@googlegroups.com
String.Chars is only implemented for something that has straight-forward string conversion. Examples of this are strings (of course), charlists, integers, atoms and so on. The Inspect protocol on the other hand should be implemented for all data types (among them tuples) and also converts a term to a string.

So when is which protocol used? A good rule thumb is that String.Chars should be used for data you want to present to users (you wouldn't want to show users the internal representation of tuples) and Inspect for internal data, for example when you want to log terms.

--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-ta...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-talk/14e06acf-cedc-4a50-8cb7-8fcbf6bcf411%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Eric Meadows-Jönsson

Alex Shneyderman

unread,
Mar 31, 2016, 10:08:53 AM3/31/16
to elixir-lang-talk
comments are inlined further down

On Thursday, March 31, 2016 at 9:41:26 AM UTC-4, Eric Meadows-Jönsson wrote:
String.Chars is only implemented for something that has straight-forward string conversion. Examples of this are strings (of course), charlists, integers, atoms and so on. The Inspect protocol on the other hand should be implemented for all data types (among them tuples) and also converts a term to a string.

just out of curiosity what is not straight forward about the tuples? I keep hearing this over and over but no detailed explanation is available on what is not straight-forward about tuples and it is not really obvious that there is no straight forward implementation out there. For example, I would think 

iex(5)> defimpl String.Chars, for: Tuple do
...(5)>   def to_string(tuple) do
...(5)>     "{ #{(:erlang.tuple_to_list(tuple) |> Enum.map(fn(e) -> String.Chars.to_string(e) end) |> Enum.join(","))} }"
...(5)>   end
...(5)> end

iex(6)> IO.puts {1,2,3}
{ 1,2,3 }
:ok

is a straight-forward implementation IMHO; can you point out why in your opinion it is not? 

Cheers,
Alex. 

José Valim

unread,
Mar 31, 2016, 10:18:06 AM3/31/16
to elixir-l...@googlegroups.com
It is not about being straight-forward implementation wise. It is about being straight-forward to recognize outside of your programming environment.

Another way to put this is: does the data structure have a string representation that makes sense *outside* of Elixir? If so, String.Chars should be implemented. If instead are looking for the developer representation of the data-structure, then you *must* use inspect.


José Valim
Skype: jv.ptec
Founder and Director of R&D

--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-ta...@googlegroups.com.

Ben Wilson

unread,
Mar 31, 2016, 10:18:53 AM3/31/16
to elixir-lang-talk
You're printing a debug representation. Go do

IO.puts [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]

Note now it looks like the text "hello world" and not a list literal? This is the difference. Your string.chars implementation prints a debug representation of a tuple, but that isn't what String.Chars is about. String.Chars is about printing whatever the item is _as text_. The only reason that works for lists at all is because for a long time lists of codepoints were the canonical way of doing text in erlang.

No such convention exists with tuples.

Onorio Catenacci

unread,
Mar 31, 2016, 10:21:55 AM3/31/16
to elixir-lang-talk
Consider this case:

iex(8)> IO.puts({1,["A","B"],3, :abc})
{ 1,AB,3,abc }
:ok

Now look at the output of inspect:

iex(9)> inspect({1,["A","B"],3, :abc})
"{1, [\"A\", \"B\"], 3, :abc}"

The fact that [A, B] is a list isn't lost in inspect nor is the fact that :abc is an atom.  And, of course, someone may want to know that when they output the tuple. I wouldn't presume to speak for Eric but this may have something to do with the answer to your question.  

--
Onorio



On Thursday, March 31, 2016 at 10:08:53 AM UTC-4, Alex Shneyderman wrote:
Reply all
Reply to author
Forward
0 new messages