2

I want to create a destructive function. Let's consider the following example:

def not_really_destructive_fun(arr)
  arr = [1,1,1]
  puts "arr changed to: " + arr.to_s
end
def destructive_fun(arr)
  p "Destructive function run."
  arr.map!{|x| x+= 1}
end

Output of calling such methods is the following:

a = [1,2,3]
not_really_destructive_fun a # => arr changed to: [1, 1, 1]
a # => [1, 2, 3]
destructive_fun a            # => "Destructive function run."
a # => [2, 3, 4]

map! still changed the original value. However, = didn't. How can I write a destructive function?

sawa
  • 165,429
  • 45
  • 277
  • 381
MatthewRock
  • 1,071
  • 1
  • 14
  • 30
  • 1
    Your example is illustrating scope more than mutation (i.e. destruction). In the first method you're array argument is being assigned to `arr` then right away you're re-assigning a new array to `arr`. This is why it not not changing the original array. – Nathan Sep 02 '15 at 11:12
  • 3
    Read this article - http://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/, and just earlier someone else had asked same question - http://stackoverflow.com/questions/32338232/variable-scope-and-modification – Wand Maker Sep 02 '15 at 11:17
  • `def demolish_everything; end` – fylooi Sep 02 '15 at 17:57

2 Answers2

3

All the parameters in Ruby are passed to methods using call-by-sharing. That said, you might change the content of a variable passed, but can not reassign it (the latter will just reassign a value, leaving the old value intact.)

So, one should modify content, e.g.:

def not_really_destructive_fun(arr)
    # that won’t work
    # arr = [1,1,1]
    # that will
    arr.replace [1,1,1]
    # and that will
    arr.clear # array is now empty
    arr << 1 << 1 << 1
end
Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
  • Pass / call by reference usually means the opposite, i.e. that you can assign to the variable being passed. – Stefan Sep 02 '15 at 11:39
  • @Stefan Frankly, this part of terminology was always tricky to me. I treat it like one might change anything save for the reference itself. What would be the right term here? – Aleksei Matiushkin Sep 02 '15 at 11:48
  • Wikipedia mentions a third term: [call-by-sharing](https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing) – Stefan Sep 02 '15 at 11:52
2

You could use replace to replace the an array with another:

def really_destructive_fun(arr)
  arr.replace([1,1,1])
  puts "arr changed to: #{arr}"
end

a = [1,2,3]
really_destructive_fun(a)
#=> arr changed to: [1, 1, 1]

a
#=> [1, 1, 1]
spickermann
  • 100,941
  • 9
  • 101
  • 131