#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?

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 Mon, Apr 21, 2014 at 10:29 AM, Nokan Emiro <uzleepito@gmail.com> 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?

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

···

Am 21.04.2014 10:29, schrieb Nokan Emiro:

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?

----------------------------------
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

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.

···

On Apr 21, 2014, at 4:57, Quintus <quintus@quintilianus.eu> wrote:

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

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

···

On Mon, Apr 21, 2014 at 9:14 PM, Ryan Davis <ryand-ruby@zenspider.com> wrote:

On Apr 21, 2014, at 4:57, Quintus <quintus@quintilianus.eu> wrote:

--
[guy, jim].each {|him| remember.him do |as, often| as.you_can - without end}
http://blog.rubybestpractices.com/

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)

···

Robert Klemme <shortcutter@googlemail.com> wrote:

On Mon, Apr 21, 2014 at 9:14 PM, Ryan Davis <ryand-ruby@zenspider.com> 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?

> 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/

···

On Tue, Apr 22, 2014 at 12:11 PM, Eric Wong <normalperson@yhbt.net> wrote:

Robert Klemme <shortcutter@googlemail.com> wrote:

On Mon, Apr 21, 2014 at 9:14 PM, Ryan Davis <ryand-ruby@zenspider.com> wrote:

--
[guy, jim].each {|him| remember.him do |as, often| as.you_can - without end}
http://blog.rubybestpractices.com/

>> > 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.

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.

···

Robert Klemme <shortcutter@googlemail.com> wrote:

On Tue, Apr 22, 2014 at 12:11 PM, Eric Wong <normalperson@yhbt.net> wrote:
> Robert Klemme <shortcutter@googlemail.com> wrote:
>> On Mon, Apr 21, 2014 at 9:14 PM, Ryan Davis <ryand-ruby@zenspider.com> wrote:

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

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

Good night

robert

···

On Tue, Apr 22, 2014 at 11:25 PM, Eric Wong <normalperson@yhbt.net> wrote:

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

--
[guy, jim].each {|him| remember.him do |as, often| as.you_can - without end}
http://blog.rubybestpractices.com/