Project

General

Profile

Feature #14624

#{nil} allocates a fresh empty string each time

Added by bumblingbear (Dillon Welch) 28 days ago. Updated 19 days ago.

Status:
Open
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:86257]

Description

This causes a bunch of unnecessary string allocations in the following scenario: "#{'rails' unless boolean_condition} is great". Each time this line is called when boolean_condition is true, it evaluates to nil and when nil is interpolated into a string it allocates an empty string. Ideally, the behavior of nil.to_s would reference a frozen empty string that wouldn't need to be reallocated each time.

History

#1 [ruby-core:86264] Updated by Hanmac (Hans Mackowiak) 27 days ago

i have a problem with that, what if someone might do:

x = obj.to_s
x << obj2.to_s

then it might be nil, return a frozen string and it would do a RuntimeError

better imo would be that if "#{nil}" would do a check if to_s is overwritten or redefined and if not do other magic

#2 [ruby-core:86317] Updated by bumblingbear (Dillon Welch) 24 days ago

That sounds fine to me!

Hanmac (Hans Mackowiak) wrote:

i have a problem with that, what if someone might do:

x = obj.to_s
x << obj2.to_s

then it might be nil, return a frozen string and it would do a RuntimeError

better imo would be that if "#{nil}" would do a check if to_s is overwritten or redefined and if not do other magic

#3 [ruby-core:86318] Updated by phluid61 (Matthew Kerwin) 24 days ago

I'm confused; are you proposing that nil.to_s returns the same String object every time, or that string interpolation detects a nil object and optimises it?

A lot of times I rely on "#{foo}" returning a new String object that contains a copy of the #to_s of foo, so it seems to me like spec that "#{nil}" returns a new empty string every time.

#4 [ruby-core:86320] Updated by bumblingbear (Dillon Welch) 24 days ago

Closer to the string interpolation optimization part. The problem with "#{nil}" is that it allocates two empty strings each time. I feel like it would be possible to do this with zero/one allocation. I don't know what the underlying code looks like, but the logic I'm thinking of is something like

def interpolate(obj)
  if obj == nil
    ''
  else 
    obj.to_s # assuming this is current behavior
  end
end

phluid61 (Matthew Kerwin) wrote:

I'm confused; are you proposing that nil.to_s returns the same String object every time, or that string interpolation detects a nil object and optimises it?

A lot of times I rely on "#{foo}" returning a new String object that contains a copy of the #to_s of foo, so it seems to me like spec that "#{nil}" returns a new empty string every time.

#5 Updated by nobu (Nobuyoshi Nakada) 23 days ago

  • Backport deleted (2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN)
  • Description updated (diff)
  • Tracker changed from Bug to Feature

Also available in: Atom PDF