user1934428
user1934428

Reputation: 22291

Changing the object identity of a formal parameter

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.

Upvotes: 0

Views: 38

Answers (3)

Roland Mai
Roland Mai

Reputation: 31097

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].

Upvotes: 1

Robo
Robo

Reputation: 1032

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"]

Upvotes: 1

J&#246;rg W Mittag
J&#246;rg W Mittag

Reputation: 369556

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.

Upvotes: 3

Related Questions