#freeze

Hi,

It’s not quite a Ruby questing, but much more a general developer
question.
I believe I’m an experienced Ruby programmer, but there’s one thing I
havent
ever used, but would like to be able to grasp the concept. This is when
to
freeze an object. Could you please show me the right use of #freeze and
#frozen? ? What are the usage patterns of these? When is this language
feature really useful?

On Mon, Apr 21, 2014 at 10:29 AM, Nokan E. [email protected]
wrote:

Hi,

It’s not quite a Ruby questing, but much more a general developer question.
I believe I’m an experienced Ruby programmer, but there’s one thing I havent
ever used, but would like to be able to grasp the concept. This is when to
freeze an object. Could you please show me the right use of #freeze and
#frozen? ? What are the usage patterns of these? When is this language
feature really useful?

For example, Hash uses it internally when the keys are strings, in
order to avoid aliasing effects, as a string is mutable. When you set
a value in a hash and the key is a string, it freezes the string.

Jesus.

On Apr 21, 2014, at 4:57, Quintus [email protected] wrote:

Reassigning will still work, but as said this will trigger a warning.

Which is easily avoidable. If you’re that paranoid about your code,
don’t let strangers run it.

Freezing string constants does have some performance benefits, but
you’re starting to get that for free in later ruby versions.

Am 21.04.2014 10:29, schrieb Nokan E.:

Hi,

It’s not quite a Ruby questing, but much more a general developer question.
I believe I’m an experienced Ruby programmer, but there’s one thing I havent
ever used, but would like to be able to grasp the concept. This is when to
freeze an object. Could you please show me the right use of #freeze and
#frozen? ? What are the usage patterns of these? When is this language
feature really useful?

From time to time, I need string constants in my classes, like this:


class Foo

SOME_CONSTANT = “foo bar baz”

end

However, one could still change the string without resorting to a
reassignment (which issues a warning):


Foo::SOME_CONSTANT.replace(“some other stuff”)

To prevent that, you can freeze your string constant.


class Foo

SOME_CONSTANT = “foo bar baz”.freeze

end

Reassigning will still work, but as said this will trigger a warning.

Vale,
Quintus


Blog: http://www.quintilianus.eu

I will reject HTML emails. | Ich akzeptiere keine HTML-Nachrichten.
|
Use GnuPG for mail encryption: | GnuPG für Mail-Verschlüsselung:
http://www.gnupg.org | The GNU Privacy Guard

On Mon, Apr 21, 2014 at 9:14 PM, Ryan D. [email protected]
wrote:

On Apr 21, 2014, at 4:57, Quintus [email protected] wrote:

Reassigning will still work, but as said this will trigger a warning.

Which is easily avoidable. If you’re that paranoid about your code, don’t let
strangers run it.

:slight_smile:

Freezing string constants does have some performance benefits, but you’re
starting to get that for free in later ruby versions.

Because of what changes?

Btw.: IMO freezing a String constant is more about avoiding bugs than
about performance gains. That’s a nice side effect though.

Kind regards

robert

Robert K. [email protected] wrote:

On Mon, Apr 21, 2014 at 9:14 PM, Ryan D. [email protected] wrote:

Freezing string constants does have some performance benefits, but you’re
starting to get that for free in later ruby versions.

Because of what changes?

2.1 deduplicates string literals in source (but strings still get
created).

2.2 will also reuses frozen strings for hash[“lit”] and hash[“lit”]=,
so no new strings are created for common hash get/set ops.
(r44551 + a few followup fixes)

On Tue, Apr 22, 2014 at 12:11 PM, Eric W. [email protected]
wrote:

Robert K. [email protected] wrote:

On Mon, Apr 21, 2014 at 9:14 PM, Ryan D. [email protected] wrote:

Freezing string constants does have some performance benefits, but you’re
starting to get that for free in later ruby versions.

Because of what changes?

2.1 deduplicates string literals in source (but strings still get
created).

So basically there will be a shared string buffer but still individual
instances, i.e.

def f(a)
“foo” + a + “foo”
end

in Ruby there were two buffers and each String literal would create a
new instance. In 2.1 there is just one buffer and still every literal
creates a new instance for every evaluation.

If I understand http://rkh.im/ruby-2.1 properly String instance
creation can be avoided by using the “freeze” modifier:

def f(a)
"foo"f + a + "foo"f
end

Still, with the unfrozen String there is only a space gain and no
performance gain, correct?

2.2 will also reuses frozen strings for hash[“lit”] and hash[“lit”]=,
so no new strings are created for common hash get/set ops.
(r44551 + a few followup fixes)

How does that work? If I understand the diffs [1] properly then the
decision is made at parse time and it seems to me that it is done for
all #[] that fit the bill. Is that correct?

Kind regards

robert

[1]
https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/44551/diff/

Robert K. [email protected] wrote:

So basically there will be a shared string buffer but still individual
instances, i.e.

def f(a)
“foo” + a + “foo”
end

in Ruby there were two buffers and each String literal would create a
new instance. In 2.1 there is just one buffer and still every literal
creates a new instance for every evaluation.

Correct.

If I understand http://rkh.im/ruby-2.1 properly String instance
creation can be avoided by using the “freeze” modifier:

def f(a)
"foo"f + a + "foo"f
end

We dropped “f”, but “.freeze” is equivalent for compatibility with <=2.0

"foo".freeze + a + "foo".freeze

No new “foo” strings created.

Still, with the unfrozen String there is only a space gain and no
performance gain, correct?

Right, since large strings are copy-on-write.

2.2 will also reuses frozen strings for hash[“lit”] and hash[“lit”]=,
so no new strings are created for common hash get/set ops.
(r44551 + a few followup fixes)

How does that work? If I understand the diffs [1] properly then the
decision is made at parse time and it seems to me that it is done for
all #[] that fit the bill. Is that correct?

At parse time, we change the instruction from opt_a* to opt_a*_with
if we detect #[“lit”] or #[“lit”]=. #[non_lit] calls still become
opt_a* instructions.

At runtime, the new opt_a*_with instructions allow us to avoid
String instance creation if the receiver is a hash.

On Tue, Apr 22, 2014 at 11:25 PM, Eric W. [email protected]
wrote:

At runtime, the new opt_a*_with instructions allow us to avoid
String instance creation if the receiver is a hash.

Ah! That was the missing link. Thank you again, Eric!

Good night

robert