2

After comments by Mike H-R and Stefan to a question of mine, I noticed that ObjectSpace.each_object(String) includes just about any string I can think of:

strings = ObjectSpace.each_object(String)
strings.include?("some random string") # => true

or

strings = ObjectSpace.each_object(String).to_a
strings.include?("some random string") # => true

I thought that strings should include only strings that existed at that point. Why does it include just about any string?

Yet, when I count the length of strings, it returns a finite number:

ObjectSpace.each_object(String).to_a.length # => 15780

This is observed on Ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-linux] interpreter and irb.

Does this have anything to do with frozen string literal optimization introduced in Ruby 2.1?

Community
  • 1
  • 1
sawa
  • 165,429
  • 45
  • 277
  • 381
  • runnning `strings = ObjectSpace.each_object(String).to_a` before introducing `"some random string"` resulted in `false`... – Uri Agassi Jun 05 '14 at 15:52

2 Answers2

5

When writing code in the IRB strings are added to the ObjectSpace as they are typed:

strings = ObjectSpace.each_object(String)
strings.include?("some random string") # => true

strings = ObjectSpace.each_object(String).to_a
strings.include?("some other random string") # => false

When trying to do it inside an rb file, the text is already there, because it is added when the file is parsed.

test.rb

strings = ObjectSpace.each_object(String)
strings.include?("some random string") # => true

strings = ObjectSpace.each_object(String).to_a
strings.include?("some other random string") # => true

strings = ObjectSpace.each_object(String).to_a
strings.include?("some other random string " + "dynamically built") # => false
Uri Agassi
  • 36,848
  • 14
  • 76
  • 93
  • This seems to contradict your comment to my question. – sawa Jun 05 '14 at 15:59
  • I tried it in `irb`, that's the first part of the answer. The behavior is different when I put it in `test.rb` and run it – Uri Agassi Jun 05 '14 at 16:02
  • Are you claiming that `ObjectSpace.each_object` keeps the state right after parsing before execution of the script? – sawa Jun 05 '14 at 16:17
  • 2
    I conclude by the behavior I see that the literal strings inside a loaded ruby file are loaded to the `ObjectSpace` before its code is run. – Uri Agassi Jun 05 '14 at 16:19
  • 2
    I'm quite sure that IRB does not add the string to `ObjectSpace` before you type them ;) – Stefan Jun 05 '14 at 16:59
  • @Stefan - nowhere in my answer do I conclude that in IRB strings are added before they are typed - the first example shows that it returns `false`... the behavior is different when you run code in IRB and code inside a file... – Uri Agassi Jun 05 '14 at 17:01
  • I know and of course you are right. *"I believe that"* just sounds a bit uncertain :) – Stefan Jun 05 '14 at 17:18
0

That's because in order to pass "some random string" to the include? method on ObjectSpace's each_object iterator, you have to create the string "some random string" first.

Simply by asking ObjectSpace about the existence of "some random string", you are creating "some random string", so of course it exists in the object space. See what I'm saying? So that explains your first example.

In your second example when you get the array of string objects before referencing "some random string", you would think that you'd get false. As you noted though, that's not the case. I assume this is because you are using a string literal, and Ruby is optimizing your code by creating the string before you actually reference it. I don't know enough about Ruby's internals though to go into specifics on that.

Ajedi32
  • 45,670
  • 22
  • 127
  • 172
  • That may apply to my first example without `to_a`, but not to my second example with `to_a`. – sawa Jun 05 '14 at 16:16