Robert Pankowecki published a fascinating article titled “Could we drop Symbols from Ruby?”.
For me symbols are one of the most annoying features in Ruby so I instantly thought “Yes! That’s a great idea”.
But then I started reading comments on the blog and over the Internet and it turned out that the feedback is rather negative. Honestly, it’s quite surprising to me.
What’s the problem
First, let me quickly describe the problem.
Currently, symbols and strings look similar but they’re not equal.
:foo == "foo" # false
It’s inconvenient. Especially when working with hashes.
hash = {age: 32}
hash[:age] # 32
hash["age"] # nil
That’s the reason why workarounds such as HashWithIndifferentAccess exist.
It was even a source of a critical security bug. See CVE-2013-1854
Solution
Robert’s idea is to turn symbols into immutable strings. They would still exist but only as a syntactic sugar.
hash = {age: 32}
hash[:age] # 32
hash["age"] # 32
Legacy
So, why do symbols exist? What are the differences between symbols and strings?
Historically they differed significantly. However each new version of Ruby makes the gap between symbols and strings smaller and smaller.
Strings are garbage collected while Symbols are not
This isn’t true anymore. Since Ruby 2.2 both symbols and strings are GC’ed.
Strings are mutable. Symbols are immutable.
Nowadays this is true although we’re in the process of making strings immutable by default.
Ruby 2.3 introduced the frozen_string_literal
which makes Strings immutable.
In Ruby 3.0 all strings will be most likely immutable by default.
Symbols are faster than strings
Indeed, symbols are mapped to integers hence they are faster than strings. I don’t know how hard it would be to come up with as solution to this problem. Given that strings will be immutable maybe it’s possible to close the performance gap? Also, Ruby 3.0 will hopefully ship with a JIT which could help in this regard.
Backwards compatibiliy
This is an interesting problem. Turning symbols into immutable strings wouldn’t be fully backwards compatible. Why? Have a look at this snippet
case foo
when String then puts "foo is a string"
when Symbol then puts "foo is a symbol"
end
If symbols were just strings then :some_symbol.is_a?(String)
would return true
but currently it returns false
.
How many apps and libraries would be affected by this change? I don’t know but a quick research reveals
that ActiveRecord relies on such comparisions. See this line and that line.
Most likely there are would be more tools that would break.
Robert proposes that Symbol
could inherit from String
. It solves the problem but only partially.
This would work as expected
case foo
when Symbol then puts "foo is a symbol"
when String then puts "foo is a string"
end
but this would not
case foo
when String then puts "foo is a string"
when Symbol then puts "foo is a symbol"
end
Now, backwards compatibiliy is one of top reasons I stick to Ruby. Almost always it’s a breeze to upgrade from one version to another. The only non-trivial migration was Ruby 1.8 to 1.9. Compare it to Python. Python 3.0 was released in 2008 but it still hasn’t been widely adopted due to incompatible changes with 2.7.
ruby-lang.org advertises Ruby as a programmer’s best friend. And it really is. Backwards compatibiliy and harmless upgrades are major factors that contribute to this fact. We shouldn’t trade them easily.
It’s a though choice. Would I sacrifice backwards compatibiliy to remove one of the biggest annoyances? Obviously it depends but if dropping symbols wouldn’t impact significant part of the ruby ecosystem then my answer would be “yes”.
Don’t stop
At Euruko 2017 Matz said that “Ruby is a community effort”. I read this as an encouragement to share ideas, make contributions and shape the future Ruby. This is great power and I hope to read more propsals on how to make Ruby better. No matter whether they’re feasible or not.
Follow @mlomnicki Tweet"It's a community effort. Come together, and be nice to each other to build better future." Matz on Ruby's future n performance. #euruko2017 pic.twitter.com/IKFAQ7FYhc
— Bishwa Hang Rai (@KhambuJr) September 29, 2017