Skip to content

Instantly share code, notes, and snippets.

@alexblom
Last active December 11, 2015 07:59
Show Gist options
  • Save alexblom/4570548 to your computer and use it in GitHub Desktop.
Save alexblom/4570548 to your computer and use it in GitHub Desktop.
Ruby string concatenation does not break assignment, which can lead to unexpected results
# When assigning string a = string b, Ruby simply makes string b a *ptr to string a
# The generic string a += string b will convert string b to a new object
# String concatenation (a.concat(b), a << b) will not, leading to unexpected values for a
#Initialize first and last name
1.9.3p125 :002 > first_name = "Alex"
=> "Alex"
1.9.3p125 :003 > last_name = " Blom"
=> " Blom"
#Join strings with +
1.9.3p125 :004 > full_name = first_name
=> "Alex"
1.9.3p125 :005 > full_name += last_name
=> "Alex Blom"
#Confirm variables are as we would expect
1.9.3p125 :006 > first_name
=> "Alex"
1.9.3p125 :007 > last_name
=> " Blom"
1.9.3p125 :008 > full_name
=> "Alex Blom"
#As we would expect: + / += creates new objects
#This is not the case when using any of the concat operators
#i.e. .contact, <<
1.9.3p125 :009 > full_name = nil
=> nil
1.9.3p125 :010 > full_name = first_name
=> "Alex"
#Ruby internally makes full_name a *ptr to first_name
1.9.3p125 :011 > full_name.object_id
=> 70105840720680
1.9.3p125 :012 > first_name.object_id
=> 70105840720680
#Concat will not break the *ptr to a new object like += does
1.9.3p125 :013 > full_name.concat(last_name)
=> "Alex Blom"
#Because the pointer was not broken, first_name has the unexpected value of full_name
1.9.3p125 :014 > first_name
=> "Alex Blom"
#Confirm it is still the same object
1.9.3p125 :015 > full_name.object_id
=> 70105840720680
1.9.3p125 :016 > first_name.object_id
=> 70105840720680
#The same will apply with other contact operators (i.e. <<)
1.9.3p125 :017 > full_name = nil
=> nil
1.9.3p125 :018 > first_name = "Alex" #full name is Alex Blom due to above
=> "Alex"
1.9.3p125 :019 > first_name.object_id
=> 70105706563920
1.9.3p125 :020 > full_name = first_name
=> "Alex"
1.9.3p125 :021 > full_name << last_name
=> "Alex Blom"
1.9.3p125 :022 > first_name
=> "Alex Blom"
#Full name will still be a *ptr to first_name
1.9.3p125 :023 > full_name.object_id
=> 70105706563920
#Thus, be wary of assignment pre concat
1.9.3p125 :024 > first_name = "Alex"
=> "Alex"
1.9.3p125 :025 > full_name = ""
=> ""
1.9.3p125 :026 > full_name << first_name
=> "Alex"
1.9.3p125 :027 > full_name << last_name
=> "Alex Blom"
1.9.3p125 :028 > first_name
=> "Alex"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment