Bug #18905


:"@=".inspect is non-evaluatable

Added by qnighy (Masaki Hara) about 1 year ago. Updated about 1 year ago.

Target version:
ruby -v:
ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux]


There is an edge case where Symbol#inspect returns a non-evaluatable expression:

:"@=".inspect # => :@=
:"[][]=".inspect # => :[][]=
:"$$$$=" # => :$$$$=

More specifically, the quotations are stripped if the following conditions are met (but the converse does not hold):

  • It starts with @, @@, $ or [,
  • the prefix is not followed by an identifier, and
  • it ends with =.

But the rule should only apply to :$= and :[]=, because (in my understanding) we should generally have eval(sym.inspect) == sym for the programmers' convenience.

Updated by sawa (Tsuyoshi Sawada) about 1 year ago

Not sure what you mean. inspect is expected to return a string, and the cases you mention indeed return a string respectively.

:"@=".inspect #=> ":@="
:"[][]=".inspect #=> ":\"[][]=\""
:"$$$$=".inspect #=> ":$$$$="

However, among them, :"@=".inspect and :"$$$$=".inspect do not include quotations. Is that what you are at?

Updated by nobu (Nobuyoshi Nakada) about 1 year ago

First, inspect methods are not for eval.
We only guarantee that == sym.

Updated by qnighy (Masaki Hara) about 1 year ago

sawa (Tsuyoshi Sawada) wrote in #note-1:

However, among them, :"@=".inspect and :"$$$$=".inspect do not include quotations. Is that what you are at?

Ah yes, the second example is my mistake. It should have been :"[=]=" or such. I think these symbols are better quoted than not.

nobu (Nobuyoshi Nakada) wrote in #note-2:

First, inspect methods are not for eval.
We only guarantee that == sym.

I understand it is not a guarantee and thus this is a relatively subtle issue. Nonetheless I think the behavior is not an intended one because Ruby values (including symbols) often implement #inspect in a way it is evaluatable.

Let me give more context on it: I was implementing the parser gem's AST serialization in another language to use the gem as a reference implementation. Under the hood it uses Symbol#inspect to stringify symbols and thus I was interested in the Symbol#inspect algorithm.

Updated by ufuk (Ufuk Kayserilioglu) about 1 year ago

I was bitten by the same thing last week and was actually going to open an issue myself. Thanks for raising this @qnighy (Masaki Hara).

The thing that caught me out was that the following discrepancy:

#=> :"4_to_5"
#=> :4_to_5=

I realize that Ruby spends a considerable amount of effort to not print symbols in a format where they could not be roundtripped, and the discprancy between :"4_to_5" and :"4_to_5=" was surprising.

I bisected the change to the released versions of Ruby and found that the behaviour changed somewhere between ruby-2.2.0-preview1 and ruby-2.2.0-preview2:

$ docker run --rm -e "ALL_RUBY_SINCE=ruby-2.0" rubylang/all-ruby ./all-ruby -e "puts '4_to_5='.to_sym.inspect"
ruby-2.0.0-p0       :"4_to_5="
ruby-2.2.0-preview1 :"4_to_5="
ruby-2.2.0-preview2 :4_to_5=
ruby-3.2.0-preview1 :4_to_5=

Looking at the commit log, I can see that there is a commit that adds special casing for a trailing = but I don't understand the reason behind why the change was made:

@nobu (Nobuyoshi Nakada) I understand that Ruby does not guarantee that inspect methods are for eval but Ruby seems to consistently quote invalid Symbols in inspect, except for when they end with =. I think this is not consistent and Ruby might as well not quote Symbols in inspect at all, in this case. I think something has to change to keep consistency.

Actions #5

Updated by nobu (Nobuyoshi Nakada) about 1 year ago

  • Status changed from Open to Closed

Applied in changeset git|8f1759143533d2b772efd5184ba02738f66fe1fc.

[Bug #18905] Check symbol name types more strictly


Also available in: Atom PDF