Here is the tricky part that you're missing: The variable @b
does not change in your example. It still contains the same string object you initially set it to. It's the string itself that is changing. This distinction is extremely important, and if you don't grasp it, you'll find your program plagued by a thousand subtle bugs. Here it is:
Objects and variables are two independent things. Variables are like slots, and objects are the things you put in them. Only the =
operator puts a new object into a slot*; everything else sends messages to the object in the slot. When you write @thing = "hello"
, that puts the String object "hello"
into the slot @thing
. When you write @thing << " world"
, you aren't setting @thing
to contain a new object; you're leaving the same object in there, but adding " world"
onto the end of the string that the object represents. This also means that any other slots holding the same object will also find their strings changed!
If you want to get around this, you'll have to use a proxy object (to receive the <<
message) like ormuriauga described instead of storing the string directly. Ruby's Delegator might be useful for that. Though I would advise considering whether you really need this, because it does complicate your design and there is often a better way to do it.
* OK, that's a little bit hand-wavy. There's also the special instance_variable_set
method that can set instance variables. But there wouldn't be any way to write that method yourself without using the =
operator and eval()
.