Reputation: 6079
Can someone explain why this:
def do_something str
str = "bar"
end
str_main = "foo"
do_something str_main
puts str_main
displays foo
?
And this:
def do_something str
str.capitalize!
end
str_main = "foo"
do_something str_main
puts str_main
displays Foo
?
Upvotes: 0
Views: 97
Reputation:
All ruby methods return the last thing evaluated. However, object assignment stays within the scope of the current code block. Assigning str_main
to a new value within a method will not affect str_main
, unless it was an instance variable (@str_main
). Doing such allows you to reassign an object across scopes, or depths, of your program. This is why your first method outputs 'foo'
instead of 'bar'
.
Now, the second example. #capitalize
is a method called on a string object. It returns a new String
instance, where its value is original object capitalized.
string = 'foobar'
string.capitalize # => 'Foobar'
puts string # => 'foobar'
Notice how string
is only modified temporarily, and when called again it is back to normal.
Many methods in ruby have counterparts ending in !
. This convention is the same as: object = object.some_method
. Instead of creating a new instance of an object, these methods edit the original object's value. In the case of #capitalize!
, the string is capitalized and modified for future calls.
string = 'foo'
string.capitalize! # => 'Foo'
puts string # => 'Foo'
Back to your second example. Using the #capitalize!
method within the scope of do_something
allows you to modify the str_main
object. In a similar way to making str_main
an instance variable.
Upvotes: 1
Reputation: 36100
Because of the way Ruby passes arguments.
When the method is being called, you have two references, str_main
and str
, to the same object "foo"
.
In the first example, when you use str = "bar"
, you are just changing what the str
reference points to. So now you have str_main -> "foo"
and str -> "bar"
. Therefore, the original object is not changed.
In the second example, you didn't change the str
reference and changed the string in place with a mutator method, thus changing the same object that str_main
points to.
Upvotes: 3
Reputation: 18762
In Ruby, references are passed by value. So, a reference to str_main
is passed to method do_something
, a copy of reference is present in variable str
.
This, however, does not mean that value that is referred to by both variables also has been copied around - there is still a single copy of referred to value, which is the string defined in Main
.
Hence, when you assign a new value to str
, this does not alter the value of str_main
. However, when you modify the value that is referred by str
, its changes are visibble outside.
Upvotes: 1
Reputation: 26444
The exclamation mark or bang operator modifies the original value. It is a destructive method. For example, let's say you had a string
string = "hi";
If you call the upcase
method, you will get the following
string.upcase
=> "HI"
However, if you call string again, you will get the initial value.
string
=> "hi"
Now, let's say you use the destructive method upcase!
string.upcase!
=> "HI"
Now, if you call string again, you will see that the value was mutated.
string
=> "HI"
Upvotes: 1