Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Evaluating a frozen string

My vague understanding is that, with Ruby 2.2's frozen method on string or Ruby 2.3's frozen-string-literal: true pragma, a relevant frozen string literal is evaluated only once throughout program execution if and only if the string does not have interpolation. The following seems to illustrate this:

Not interpolated

#frozen-string-literal: true
5.times{p "".object_id}

Outputs (same object IDs):

70108065381260
70108065381260
70108065381260
70108065381260
70108065381260

Interpolated

#frozen-string-literal: true
5.times{p "#{}".object_id}

Outputs (different object IDs):

70108066220720
70108066220600
70108066220420
70108066220300
70108066220180
  1. What is this property (i.e., being evaluated only once) called? It should be distinct from immutability.
  2. Is my understanding of the condition when strings come to have such property correct? Where is the official documentation mentioning this?
  3. Is there a way to make an interpolated string be evaluated only once?
like image 827
sawa Avatar asked Dec 26 '15 07:12

sawa


People also ask

What is a frozen string?

This means that any string literal within your code is frozen and cannot be modified. As an added bonus, identical string literals in multiple locations are the same object (and for what it's worth, this is how symbols already behave), so the memory profile of your app is potentially reduced.

What does Frozen_string_literal mean?

# frozen_string_literal: true is a magic comment, supported for the first time in Ruby 2.3, that tells Ruby that all string literals in the file are implicitly frozen, as if #freeze had been called on each of them.

What is FrozenStringLiteralComment?

Class: RuboCop::Cop::Style::FrozenStringLiteralCommentHelps you transition from mutable string literals to frozen string literals. It will add the `# frozen_string_literal: true` magic comment to the top of files to enable frozen string literals. Frozen string literals may be default in future Ruby.


1 Answers

  1. Interning. The strings are said to be interned.
  2. Not completely. It is more like if the interpreter can decide what the value of the string would be before evaluating it. For example, consider:

    5.times { puts "#{'foo'}".object_id }
    

    The id is the same even though there is interpolation involved.

  3. No. This is an internal optimization. The main point of Object#freeze is immutability.


UPDATE: Only literal strings get internalized. This is evident here.

I couldn't find the part of the code responsible for interpolation. So I'm not sure why "#{'foo'}" is considered a literal string. Note that wherever this translation occurs, it is on a lower parser level and happens way before any actual processing. This is evident by the fact that String#freeze is mapped to rb_str_freeze, which doesn't call opt_str_freeze.

like image 76
ndnenkov Avatar answered Sep 23 '22 15:09

ndnenkov