6

I am using the # frozen_string_literal: true magic comment that RuboCop enforces by default, and I can't append something to a string:

string = 'hello'

string << ' world'

because it errors out with:

can't modify frozen String (RuntimeError)

2
  • 1
    Why do you turn on frozen strings when you don't want your strings to be frozen? Commented Sep 4, 2019 at 21:16
  • Because, as mentioned, it's enforced by default by RuboCop, and I tend to trust them, and because I do want some strings to be immutable. Commented Sep 4, 2019 at 22:10

4 Answers 4

16

You add a + before the string like:

string = +'hello'

string << ' world'

puts(string)

hello world

Sign up to request clarification or add additional context in comments.

1 Comment

Backwards compatible alternatives: String.new('hello') or 'hello'.dup
5

You can also use +=:

s = 'H'
s += 'ello

=> "Hello"

Comments

3

frozen_string_literal is for string literal. To create a mutable String instance, use String#new or prepend a + to the string literal.

# frozen_string_literal: true
'foo'.frozen? # => true
String.new.frozen? # => false
(+'foo').frozen? # => false

2 Comments

What does this answer add different from this anwer and this comment?
1) I usually don't read all comments of all other answers, so do some people. 2) My answer is unique to other answers in this thread.
0

When # frozen_string_literal: true is enabled, you cannot 'mutate' any strings.

Want proof? With the following script...

# frozen_string_literal: true

str = 'hello'
str << ' world'

you will get the following error...

Traceback (most recent call last):
frozen_strings.rb:4:in `<main>': can't modify frozen String (FrozenError)

'Mutate' means change the value of the object. Therefore, your example fails because << mutates strings and it is mutating your string string since you are using the << operator.

Want proof? Go into irb! Enter the follow:

str = 'hello' # => 'hello'
obj_id1 = str.object_id # => some number, ex: 12345
str << ' world' # => 'hello world'
obj_id2 = str.object_id # => some number, ex: 12345
obj_id1 == obj_id2 # this should return true, proving that you mutated the object

However, you can get around this by using str += ' world'. Why? Because += is a shorthand reassignment. Instead of mutating, += creates a brand new string (with a brand new object_id) and stores it under the same variable name (in this case, str).

Want Proof? Check it out in irb!

str = 'hello' # => 'hello'
obj_id1 = str.object_id # => some number, ex: 12345
str += ' world' # => ' world'
obj_id2 = str.object_id # => some other number, ex: 356456345
obj_id1 == obj_id2 # => this returns false!

Let me know if this helped!

4 Comments

When # frozen_string_literal: true is enabled, you can 'mutate' a string by using string << 'string' instead of string += 'string' that you mentioned.
This code gave me an error... ruby # frozen_string_literal: true str = 'hello' str << ' world' ``` Traceback (most recent call last): frozen_strings.rb:4:in `<main>': can't modify frozen String (FrozenError) ```
And besides, that example proves that you cannot mutate strings while # frozen_string_literal: true is enabled, but in your first comment you're asserting that you can.
I didn't want to come up as rude. But your last reply is still incorrect. Again, you can mutate strings, even when frozen_string_literal is set to true, if you initialize it using = +, and not simply =.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.