An interesting way to speed up Ruby code. I probably would not have considered the amount of strings being passed around as something that could slow things down that much.
I rejected a similar patch a few years ago, and I had hoped it would not become necessary when Ruby implementations became better. Too bad it’s not the case.
Wait, Ruby doesn’t have constant folding for literals?
I’m not a rubyist, but I think that it’s because symbols are supposed to take the place of string literals, and ruby strings are mutable by default.
Symbols are interned automatically, and you’re expected to use symbols in most places where you would use interned strings in other languages. My guess is that symbols are supposed to be thought of as keys with semantic meaning (and since each key is meaningful, may be reused many times) whereas strings are thought of as fancily encoded array bytes, and may be sliced and diced and combined with other strings any which way.
Strings are mutable by default, and you must “freeze” strings (as noted by @benolee) if you want an immutable string. If string literals were interned by default, and we also had mutable strings, they would have very odd semantics. There are two options:
We intern mutable strings. This means that when I ask for a “foo” but someone else has already used “foo” in the code, and then modified it to be uppercase, I actually see “FOO” when I inspect my “foo”.
We intern immutable strings, but COW them and adjust the reference of the var so that they turn into mutable ones later on. So when I check whether my two literals strings “bar” are references to the same object, they evaluate to true! But when I uppercase one or both of them, then they point to separate objects. Or else we create a copy when we inspect the object so that a equal? b is consistent. So this means that equal? may entail an object allocation … again this is a very weird semantic.
So yeah, it seems a little unusual to me, since I spend most of my time on the JVM, but I guess it works for them.
Ruby 2.1 added some optimizations for frozen strings: http://tmm1.net/ruby21-fstrings
Not for literal String anyway.
Isn’t this 2-4% on what’s still a pretty slow number?