B
Brian Candler
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.
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.