Issue #14336 has been updated by jeremyevans0 (Jeremy Evans).

Tracker changed from Bug to Feature
Backport deleted (2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN)

dsferreira (Daniel Ferreira) wrote:
> There is also one important thing here that deserves consideration: We are doing a great effort to improve the performance of strings and everything associated to them.
> 
> Symbols are not taking advantage of those improvements.

I'm not sure what you mean here. Symbols were already as fast or faster than Strings as internally they are stored as a direct value (at least real symbols, as opposed to those created via `String#to_sym`).

> If we keep saying that everything is a Symbol except user input we will be constraining ourselves to use less performant code.

I don't think I've read anyone saying that "everything is a Symbol except user input". Multiple people have told you that symbols serve as identifiers. While it is true that some other languages merge identifiers and strings, some other languages use different classes for text and data too, where Ruby uses String for both.  Symbols are a core part of ruby, and removing/deprecating them would cause serious problems, as I explained in #7792 and #14277.

> Correct me if Im wrong but if Im not mistaken immutable strings can be more performant then symbols, not to mention the memory consumption.

I think there are few cases where a frozen string performs better than a symbol.  I'm guessing #to_s would be faster, but beyond that and possibly other cases where you are returning a string, symbols generally perform as well or better than strings.

Have you actually done any benchmarking in this area?  Here's a simple benchmark:

~~~ ruby
require 'benchmark/ips'

a = 'a'
a2 = a.dup
fa = a.dup.freeze
fa2 = a.dup.freeze
Benchmark.ips do |x|
  x.report("string"){a == a2}
  x.report("frozen string"){fa == fa2}
  x.report("literal fstring"){'a'.freeze == 'a'.freeze}
  x.report("symbol"){:a == :a}
end
~~~

results:

~~~

              string      6.031M ( 0.6%) i/s -     30.213M in   5.009466s
       frozen string      6.032M ( 0.6%) i/s -     30.237M in   5.012902s
     literal fstring      6.997M ( 0.7%) i/s -     35.148M in   5.023640s
              symbol      7.108M ( 0.7%) i/s -     35.580M in   5.005652s
~~~

Then you have cases like #hash, where String#hash is O(n)  and Symbol#hash is O(1). 

~~~ ruby
str = 'a'*1_000_000
fstr = str.dup.freeze
sym = str.to_sym
Benchmark.ips do |x|
  x.report("string"){str.hash}
  x.report("frozen string"){fstr.hash}
  x.report("symbol"){sym.hash}
end
~~~

results, note the difference between k and M:

~~~
              string      2.712k ( 0.4%) i/s -     13.770k in   5.077791s
       frozen string      2.713k ( 0.4%) i/s -     13.770k in   5.076325s
              symbol      6.589M ( 0.7%) i/s -     33.047M in   5.015775s
~~~

> By merging symbols into strings we can focus all our efforts in improving strings performance leaving symbols out of the equation.

Symbols were already faster, so this doesn't make sense.

> I only see positive things here.

I see a huge negative thing here.

> The transition path that I present will make sure that no code will be broken.

It sounds like these would still be broken, with no deprecation warning:

~~~ ruby
h['a'] = 1
h[:a] = 2
h['a'] # was 1, now 2

'a' == :a # was false, now true

'a'.hash == :a.hash # was false, now true
~~~

I don't see any transition plan for the C-API.

Daniel, are you OK with closing #14277?  There doesn't seem to be a reason to have two separate issues opened for basically the same feature request.

----------------------------------------
Feature #14336: Create new method String#symbol? and deprecate Symbol class
https://bugs.ruby-lang.org/issues/14336#change-69446

* Author: dsferreira (Daniel Ferreira)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
From  the discussions on the three previous issues related to the String vs Symbol subject ([5964](https://bugs.ruby-lang.org/issues/5964), [7792](https://bugs.ruby-lang.org/issues/7792), [14277](https://bugs.ruby-lang.org/issues/14277)) there are some conclusions we can assume:
* Current String vs Symbol is not the ideal scenario. See: Matz and Koichi comments.
* Current philosophy is to use Symbols as identifiers and Strings when strings are needed.
* Current situation is that Symbols are being used in many code bases as strings except for strings that really need the String methods.
* Current situation is that we are designing APIs to handle both String and Symbol inputs forcing an overhead of API development.

I propose the deprecation of `Symbol` class and the introduction of `String#symbol?`.

```ruby
foo = :foo
foo.class # => String
foo.symbol? # => true
bar = "bar"
bar.class # => String
bar.symbol? # => false
```

For backwards compatibility transition path I propose:

```ruby
class Symbol
  def self.===(var)
    warn ("Warning message regarding deprecated class")
    if var.class == Symbol
      true
    elsif var.class == String && var.symbol?
      true
    else
      false
    end
  end
end

class String
  def is_a?(klass)
    case klass
    when String
      true
    when Symbol
      self.symbol?
    else
      false
    end
  end
end
```



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>