Brian Candler
9/6/2007 7:50:00 AM
I just had a thought.
One of the problems with using strings as hash keys is that every time you
refer to them, you create a throw-away garbage string:
params["id"]
^
+-- temporary string, needs to be garbage collected
In Rails you have HashWithIndifferentAccess, but this actually isn't any
better. Although you write params[:id], when executed the symbol is
converted to a string anyway.
In a Rails-like scenario, using symbols as the real keys within the hash
doesn't work: the keys come from externally parsed data, which means (a)
they were strings originally, and (b) if you converted them to symbols you'd
risk a symbol exhaustion attack.
So I thought, wouldn't it be nice to have a half-way house: being able to
converting a symbol to a string, in such a way that you always got the same
(frozen) string object?
This turned out to be extremely easy:
class Symbol
def fring
@fring ||= to_s.freeze
end
end
irb(main):006:0> :foo.fring
=> "foo"
irb(main):007:0> :foo.fring.object_id
=> -605512686
irb(main):008:0> :foo.fring.object_id
=> -605512686
irb(main):009:0> :bar.fring
=> "bar"
irb(main):010:0> :bar.fring.object_id
=> -605543036
irb(main):011:0> :bar.fring.object_id
=> -605543036
irb(main):012:0> :bar.fring << "x"
TypeError: can't modify frozen string
from (irb):12:in `<<'
from (irb):12
from :0
Is this a well-known approach, and/or it does it exist in any extension
library?
I suppose that an instance variable lookup isn't necessarily faster than
always creating a temporary string with to_s and then garbage collecting it
at some point later in time, but it feels like it ought to be :-)
However, since I've seen discussion about string modifiers like "..."u,
perhaps there's scope for adding in-language support, e.g.
"..."f - frozen string, same object ID each time it's executed
In that case, it might be more convenient the other way round:
"..." - frozen string literal, same object
"..."m - mutable (unfrozen) string literal, new objects
String.new("...") - another way of making a mutable string
"...".dup - and another
That would break a lot of existing code, but it could be pragma-enabled.
Sorry if this ground has been covered before - it's hard to keep up with
ruby-talk :-)
Regards,
Brian.