0

I will try to explain the problem with a simple example:

def enclose(x)
  [x]
end

In my application, enclose does something more complex, but in essence it returns an array, the content of which is solely determined by the value of the parameter x. I could it use it like this:

foo = 'abcd'
....
foo = enclose(foo)

Now to my question: Is it possible to write a method enclose!, which simply replaces the parameter by its enclosed version, so that the example could be written as

foo = 'abcd'
....
enclose!(foo)

Since Ruby passes arguments by reference, I thought hat this could maybe be possible. The naive approach,

def enclose!(x)
    x = [x]
end

does not work - I think this is because the assignment creates a new object and leaves the actual parameter untouched.

Is there way, that I can achieve my goal? I think in Smallalk, there would be a method become which would change the object identity, but I didn't find something similar in Ruby.

user1934428
  • 19,864
  • 7
  • 42
  • 87
  • Isn't `foo = enclose(foo)` what you really want? – Candide Mar 08 '16 at 22:29
  • It's the same (as you can see from my posting), just that I wanted to mention the variable `foo` once. I took the idea from the String methods `chomp` of `chomp!`, but with a `String`, it works, because you can change the content of the string without changing the identity of the String object. In my case, a value of some arbitrary type would have been changed to a value of type `Array`, and I now realize that this is not possible in Ruby. – user1934428 Mar 09 '16 at 10:58

3 Answers3

3

Since Ruby passes arguments by reference, I thought hat this could maybe be possible.

Ruby is pass-by-value, not pass-by-reference, which you have proven yourself, because otherwise your code would have worked.

I think in Smallalk, there would be a method become which would change the object identity, but I didn't find something similar in Ruby.

There isn't. Ruby has neither pass-by-reference nor become:, what you want simply isn't possible.

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
1

There's some other interesting posts about how ruby is pass by value, but the values are references.

What it boils down to is, you can modify the variable an object refers to, but you cannot change it to refer to another object.

> a = [1]
=> [1]
> def add_a(array)
>   array << "a"
> end
=> :add_a
> add_a a
=> [1, "a"]
> a
=> [1, "a"]
Community
  • 1
  • 1
Robo
  • 992
  • 4
  • 10
1

There is a way to sort of accomplish what you are asking for but it's not quite pretty. Ruby has this concept of a binding (http://ruby-doc.org/core-2.2.0/Binding.html), which is like a CallContext in .NET.

You can do something like this:

def enclose(x)
  [x]
end

def enclose!(x, binding)
  eval("#{x} = [#{x}]", binding)
end

foo = 'abcd'
enclose!(:foo, binding)
=> ["abcd"]

In the script above, the :foo means you are passing the name of the variable, and the binding (context) where to find its value. Then you're dynamically calling eval to evaluate the assignment operation foo = [foo].

Candide
  • 30,469
  • 8
  • 53
  • 60