Notice the hash signature for b is the same as the hash signature for a. Which is why even though you re-assign it to point to a it's already read the contents of the StringIO you created and hence nils out.

The first time you clone a and point it to b, it creates the hash signature as "#<StringIO:0xb6d968ac>" and the second time you clone it it creates a different hash signature "#<StringIO:0xb7053464>". Hence, multiple clone calls actually still point to different memory space, but it's still the same variable?