0

Given the following two methods:

    [53] pry(main)> def my_method
    [53] pry(main)*   leti = 'leti'
    [53] pry(main)*   edit(leti)
    [53] pry(main)*   leti 
    [53] pry(main)* end  
    => :my_method
    [54] pry(main)> def edit(a_leti)
    [54] pry(main)*   a_leti.gsub!('e', '3')
    [54] pry(main)*   a_leti
    [54] pry(main)* end  
    => :edit
    [55] pry(main)> my_method
    => "l3ti"

Can someone explain why I am getting the value edited inside the edit method and not the original value ('leti'). I though Ruby was passed by value. In fact, if instead of using the function gsub I use a simple assignment, I get the original value. Does the gsub! make it by reference?

Thank you!

Leticia Esperon
  • 2,499
  • 1
  • 18
  • 40
  • 1
    The docs for `gsub!` explain what it does. – Dave Newton Jul 25 '18 at 19:09
  • 1
    It is passed by value, but internally reference the same object, which is altered with `gsub!`, changing both. Ruby's value/reference passing isn't as "clear" as in some other languages. Hopefully [this answer](https://stackoverflow.com/questions/19889245/ruby-pass-by-value-clarification?rq=1) can help clarify for you. – ForeverZer0 Jul 25 '18 at 19:16
  • Okay, thanks. Should I delete the question? – Leticia Esperon Jul 25 '18 at 19:18

1 Answers1

0

In Ruby: Objects like strings are passed by reference. Variables with objects like strings are in fact references to those strings. Parameters are passed by value. However, for strings, these are references to those strings.

So here is the classic example:

irb(main):004:0* a = "abcd"
=> "abcd"
irb(main):005:0> b = a
=> "abcd"
irb(main):006:0> b << "def"
=> "abcddef"
irb(main):007:0> a
=> "abcddef"
irb(main):008:0> b
=> "abcddef"

If you do not wish to modify the original string, you need to make a copy of it:

Three ways (of many) to do this are:

b = a.dup
b = a.clone
b = String.new a

Using dup

irb(main):009:0> a = "abcd"
=> "abcd"
irb(main):010:0> b = a.dup
=> "abcd"
irb(main):011:0> b << "def"
=> "abcddef"
irb(main):012:0> a
=> "abcd"
irb(main):013:0> b
=> "abcddef"

BTW: For myself, this effect is the number one cause of defects in my own code.

Peter Camilleri
  • 1,882
  • 15
  • 17
  • 1
    No, Ruby is pass by value, full stop. However, those values are references and some objects (such as strings) provide methods (such as `#gsub!`) that make the objects mutable, other objects (such as numbers and symbols) don't provide such methods. – mu is too short Jul 25 '18 at 19:32
  • That was what I was trying to say. My clumsy. – Peter Camilleri Jul 25 '18 at 19:34
  • Fair enough, the terminology is rather cumbersome. – mu is too short Jul 25 '18 at 19:38
  • The examples could be slightly better here. By writing it as `b = b << "def"` it makes it _seem_ like it's necessary to assign back to the variable in order for `b` to have the new value. The point is that `<<` modifies the original string and so I think `b << "def"`with no assignment makes the point more clearly. – mikej Jul 25 '18 at 20:17
  • 1
    Very true. It did not occur to me at the time. I have updated my reply. – Peter Camilleri Jul 25 '18 at 20:51
  • @muistooshort: The terminology is clumsy because it was developed for ALGOL, and "pass by reference" is used by very few languages nowadays (C++ being a notable one). IMO, best to avoid stuffing oval objects in round holes, and use "pass by sharing" (with a completely new term), or "pass by reference value", which more correctly describes the behaviour of many modern programming languages, to avoid the pitfall of conflating true pass by value where objects are cloned (like what PHP does by default) from this. https://en.wikipedia.org/wiki/Evaluation_strategy – Amadan Jul 26 '18 at 01:30