How Are Variables Kept Independent of Each Other Yet Pass Values?

Somewhere in the several books I’ve been learning Ruby from there was
the
note that when you create a new variable and assign it a value from
another
variable that you really haven’t created an independent variable at all
but
just another name for the source variable. So if you code “new_var =
old_var” the new_var simply points to the location of the value for
old_var. Consequently, if you change one variable, you have changed
both.
I’ve tested this and it appears to be true. I’ve made bold the crucial
part
of the code.

In the following code verifies that variables are not independent in
assignments:

Test to Determine how 2 Dimentional Arrays Work

current_state = [[1, 3, 6], [5, 0, 2], [4, 7, 8]]
#new_state = [[1, 3, 6], [5, 0, 2], [4, 7, 8]]
new_state = current_state
puts "Current State = " + current_state.to_s
puts "current_state[1][1] is " + current_state[1][1].to_s
puts "current_state[2][1] is " + current_state[2][1].to_s

Exchange positions

new_state[1][1] = current_state[2][1]
new_state[2][1] = current_state[1][1]

Show changed values

puts "New State[1][1] = " + new_state[1][1].to_s
puts "New State[2][1] = " + new_state[2][1].to_s

Gives the results:

ruby Simple_Test_Class_EightPuzzle.rb
Current State = 136502478
current_state[1][1] is 0 <== Values before the change
current_state[2][1] is 7 <== Values before the change
*New State[1][1] = 7 <== Values after the change
New State[2][1] = 7 <== Values after the change. Due to new_state and
current_state pointing to the same value.
*>Exit code: 0

Which would only happen if new_state and current_state point to the same
value!

If I execute the code with the above bold line commented out and the
comment
line above it executed, then the exchange occurs properly because
new_state
and current_state are two independent variables. Thus,

Test to Determine how 2 Dimentional Arrays Work

current_state = [[1, 3, 6], [5, 0, 2], [4, 7, 8]]
*new_state = [[1, 3, 6], [5, 0, 2], [4, 7, 8]]
*#new_state = current_state
puts "Current State = " + current_state.to_s
puts "current_state[1][1] is " + current_state[1][1].to_s
puts "current_state[2][1] is " + current_state[2][1].to_s

Exchange positions

new_state[1][1] = current_state[2][1]
new_state[2][1] = current_state[1][1]

Show changed values

puts "New State[1][1] = " + new_state[1][1].to_s
puts "New State[2][1] = " + new_state[2][1].to_s

produces the desired results, as

ruby Simple_Test_Class_EightPuzzle.rb
Current State = 136502478
current_state[1][1] is 0
current_state[2][1] is 7
*New State[1][1] = 7
New State[2][1] = 0 <== Proper exchange occurred because new_state and
current_state are independent.
*>Exit code: 0
Now, my problem is that I must give new_state the value that
current_state
has but keep them independent, because I need to save the original
configuration of values. How do I pass a value to a new variable from a
source variable yet keep them independent? I’m sure there is a way, I
just
cannot remember where I read it in the books and the indexes are not
helpful.

Thanks in advance!

No Sam

the easy way is you can have another temp variable to which u have to
assign the old value.and assing the temp value to new. in this case when
u change the new the temp will change but not old.

temp var = old var

new var = temp var

// here u can do what ever u want on new. unless u directly change any
thing on temp ur old var is safe.

ps:this is a work around, i dont recommend it.

-V

On Sep 9, 10:50 pm, venkatesh Peddi [email protected] wrote:

the easy way is you can have another temp variable to which u have to assign the old value.and assing the temp value to new. in this case when u change the new the temp will change but not old.

temp var = old var

new var = temp var

// here u can do what ever u want on new. unless u directly change any thing on temp ur old var is safe.

What are you talking about? Why would that work? Why would there be
any difference between x = a; b = x and b = a?

>> a = [1,2,3]
>> x = a
>> b = x
>> b[2] = 4
>> b
=> [1, 2, 4]
>> a
=> [1, 2, 4]

Mason, you’re going to want to make an actual copy of the original
variable, not simply a new pointer to it (which is what you get when
you do something like b = a). In many cases, calling .dup or .clone
will work. (As in b = a.dup or b = a.clone.)

However, since you have an array of arrays, you’re going to need a
“deep copy”. I believe b = Marshal.load(Marshal.dump(a)) is the
standard idiom.

Yossef M. wrote:

Mason, you’re going to want to make an actual copy of the original
variable, not simply a new pointer to it (which is what you get when
you do something like b = a). In many cases, calling .dup or .clone
will work. (As in b = a.dup or b = a.clone.)

However, since you have an array of arrays, you’re going to need a
“deep copy”. I believe b = Marshal.load(Marshal.dump(a)) is the
standard idiom.

Or, if that offends your sensibilities, in your case you can do this:

arr = [
[1, 2],
[“a”, “b”]
]

arr_copy = []

arr.each do |subarr|
arr_copy << subarr.dup
end

p arr
p arr_copy

–output:–
[[1, 2], [“a”, “b”]]
[[1, 2], [“a”, “b”]]

arr[0][1] = “******”

p arr
p arr_copy

–output:–
[[1, “******”], [“a”, “b”]]
[[1, 2], [“a”, “b”]]

By the way, I just modified and tested my code with your solution:

new_state = []
current_state.each do |substate| new_state << substate.dup end

and it worked beautifully!

If others are following this conversation, the “new_state = []” is
needed if
the variable, new_state, has not been defined at a prior time.

Ruby authors need to add the dup method in an early chapter where they
cover
assignments! Not included in “Beginning Ruby” 2nd ed. The pickaxe
book,
“Programming Ruby 1.9”, only mentions dup (and clone) in chapter 27 on
built-in classes and methods without any code examples. “Ruby Cookbook”
doesn’t mention it at all. “Ruby in a Nutshell” only says on page 48
“o.dup Creates a copy of the object (copying the content).”

Again, much thanks,

No Sam

On Thu, Sep 10, 2009 at 12:20 AM, Yossef M.[email protected]
wrote:

Mason, you’re going to want to make an actual copy of the original
variable, not simply a new pointer to it (which is what you get when
you do something like b = a).

I think it’s a good thing for a ruby learner to get the distinction
between variables and objects straight.

http://talklikeaduck.denhaven2.com/2006/09/13/on-variables-values-and-objects

You don’t copy variables, you copy objects, so I’d restate that as
“you’re going to want to make a copy of the object referenced by the
original variable.” It’s subtle I admit but it helps to start
thinking that way explicitly when dealing with languages with object
reference semantics.

In many cases, calling .dup or .clone
will work. (As in b = a.dup or b = a.clone.)

However, since you have an array of arrays, you’re going to need a
“deep copy”. I believe b = Marshal.load(Marshal.dump(a)) is the
standard idiom.

In this case, it’s probably not a bad idea to consider writing a more
‘domain specific class’ This took me a minute or two to refactor the
example code:

class Array2D
def initialize(rows)
@rows = rows
end

def self.
new(rows)
end

def
@rows[row][col]
end

def []=(row,col,val)
@rows[row][col] = val
end

def to_s
@rows.map {|row| row.join(“, “)}.join(”\n”)
end

def dup
Array2D.new(@rows.map {|row| row.dup})
end
end

current_state = Array2D[[1, 3, 6], [5, 0, 2], [4, 7, 8]]
new_state = current_state.dup
puts “Current State:”
puts current_state.to_s
puts "current_state[1, 1] is " + current_state[1, 1].to_s
puts "current_state[2, 1] is " + current_state[2, 1].to_s

Exchange positions

new_state = current_state.dup
new_state[1, 1] = current_state[2, 1]
new_state[2, 1] = current_state[1, 1]

Show changed values

puts “New State:”
puts new_state.to_s
puts "New State[1, 1] = " + new_state[1, 1].to_s
puts "New State[2, 1] = " + new_state[2, 1].to_s

Current State should be unchanged

puts “Current State:”
puts current_state.to_s
puts "current_state[1, 1] is " + current_state[1, 1].to_s
puts "current_state[2, 1] is " + current_state[2, 1].to_s

When run this outputs:

Current State:
1, 3, 6
5, 0, 2
4, 7, 8
current_state[1, 1] is 0
current_state[2, 1] is 7
New State:
1, 3, 6
5, 7, 2
4, 0, 8
New State[1, 1] = 7
New State[2, 1] = 0
Current State:
1, 3, 6
5, 0, 2
4, 7, 8
current_state[1, 1] is 0
current_state[2, 1] is 7


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

Much Thanks, 7stud. I’m puzzled by the Marshall plan you first had. Is
Marshall a class that you have to access? The second method seems the
better of the two methods, ignoring my delicate sensibilities or not.

Attention to Ruby instructors: I would recommend that Ruby instructors
make a bid deal about passing values from one variable to another. If a
student is not made aware of this curiosity to Ruby, they will be very
puzzled at how their code works. Transferance of value is a very common
function in any language. Yet the several texts I’ve see so far, it is
only
mentioned in passing in one. Big mistake. In all the languages I used
in
the past this way of doing things is unique. Why Matz decided on this
approach is worth mentioning. What problem was he solving by doing
things
this way?

Again, thanks,

No Sam

At 2009-09-10 10:43AM, “Mason K.” wrote:

new_state = []
current_state.each do |substate| new_state << substate.dup end

Or:
new_state = current_state.collect {|substate| substate.dup}

I agree with 7stud. I tried the method suggested by Peddi before I
asked
the original question and found that it didn’t work. What 7stud pointed
out
is that I was assuming that variables and objects behave the same way.
A
name for an object is just a pointer to the value of the object in
memory.
So when you do something like object1 = object2 all you are doing is
setting
the pointer for object1 to where object2 is pointing. Not coming from
an
object orientation for the most part, I ignored that distinction, and
didn’t
get the desired results.

This also answers my question of why Ruby was designed this way.
Because it
is an OO language.

Still, for the old timers coming from a COBOL environment, this is a bit
of
an annoyance. And any instructor needs to be sure that the students
understand the significance of variables being objects. They cannot
just
say, “X is an object” and expect the student to extrapolate. They need
to
explicitly tell the student how to transfer a value from one object to
another.

No Sam

On Thu, Sep 10, 2009 at 10:58 AM, Mason K.[email protected]
wrote:

Still, for the old timers coming from a COBOL environment, this is a bit of
an annoyance.

Yes, from my experience with COBOL flavored programers, admittedly
years ago, COBOL really does almost everything in terms of moving data
from place to place, or variable to variable, a feature it shares with
it’s generational friend FORTRAN. Pointers are foreign in these
languages.

Not that object references don’t trip up C programmers as well, since
thinking of variables as pointers isn’t completely correct either.

And any instructor needs to be sure that the students
understand the significance of variables being objects. They cannot just
say, “X is an object” and expect the student to extrapolate.

Actually variables AREN’T objects, they are references to objects.
You (actually other objects) interact with objects through variables.

They need to
explicitly tell the student how to transfer a value from one object to
another.

I think in the long run, when you really start to get
object-oriented thinking in a uniformely OO language like Ruby, you
stop thinking of transfering values, and start thinking about
interacting with objects by sending messages which return object
references, and about how those messages affect the state of those
objects.

Keep at it, ask questions as surprises come up, and things will start
clicking into place more and more.


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

Mason K. [email protected] writes:

Still, for the old timers coming from a COBOL environment, this is a bit of
an annoyance. And any instructor needs to be sure that the students
understand the significance of variables being objects. They cannot just
say, “X is an object” and expect the student to extrapolate. They need to
explicitly tell the student how to transfer a value from one object to
another.

Actually, the analogy that is often taught is that of “naming”.

You have objects who live independent lifes, and you can give them
names.
To some objects, for whatever reason, you may want to give several
names.

pascalBourguignon = Person.new({:height => 1.90})
pjb = pascalBourguignon # as he is known in some irc channels.
informatimago = pascalBourguignon # as he may be known in some other
internet circles
pascal = pascalBourguignon # as he’s known familiarly.

But there is still only one entity. (Unfortunately, I’d wish to be
able to be cloned as easily as copying data is). You can call that
entity by whatever name.

pascal.eat(cake)
pjb.writeProgram(specifications)
pascalBourguignon.getPaid(amount)

in all cases, its’ the same object who works.

2009/9/10 Mason K. [email protected]:

This also answers my question of why Ruby was designed this way. Because it
is an OO language.

There are other OO languages around that implement different concepts
of “value” and “reference”. This does not exactly have something to
do with Ruby being OO. In fact, you could have a procedural language
which behaves the same with regard to objects and references - you
just don’t have methods. If you look at C++

Still, for the old timers coming from a COBOL environment, this is a bit of
an annoyance. And any instructor needs to be sure that the students
understand the significance of variables being objects.

Variables are NOT objects. Variables hold references to objects. You
can copy a reference as much as you like, this does nothing to the
object where it points to. If there are no longer any live references
to an object, the object is no longer reachable (i.e. cannot be used).
Some time after this state is reached, Ruby’s garbage collector will
come along and free the memory. But that is just housekeeping - the
object was “lost” for the program before that point in time.

Kind regards

robert

Pascal J. Bourguignon wrote:

Actually, the analogy that is often taught is that of “naming”.

I’ve never liked that analogy much. It leads to the question “If I have
an object, how do I get its name?”. This is nonsense, unless the object
has a name attribute or (as with ruby classes) you are prepared to
search for a constant that refers to the object.

[1] as in this case:

irb(main):008:0> c = Class.new
=> #Class:0xb7d2e620
irb(main):009:0> c.name
=> “”
irb(main):010:0> CC=c
=> CC
irb(main):011:0> c.name
=> “CC”

On Fri, Sep 11, 2009 at 1:30 PM, Joel VanderWerf
[email protected] wrote:

Pascal J. Bourguignon wrote:

Actually, the analogy that is often taught is that of “naming”.

I’ve never liked that analogy much. It leads to the question “If I have an
object, how do I get its name?”. This is nonsense, unless the object has a
name attribute or (as with ruby classes) you are prepared to search for a
constant that refers to the object.

This objection seems to presuppose that each object has (or should
have) one and only one name. Why?

In general names are not actually atributes of any real world object.
The fact that ruby Classes know 0-1 name is an anomaly, and really
can’t be generalized.

An object can have multiple names. I’m Rick, Richard, RubyRedRick,
… Some people have pet names for their spouses, sometimes known
only by the two.

Sometimes a “sentient” object knows some of it’s names, sometimes it
doesn’t. That cute little redhead in my High School algebra never
knew that I called her “that cute little redhead.” And I’m sure that
my car doesn’t know that I call it Franz. I’m sure that people refer
to me by some names of which I’m unaware, probably some of which I
wouldn’t wish to be aware of.

And the connection between a name and an object can be temporary or
transitory, What I call my home is a different object now than it was
10 years ago, and still a different object 30 years ago.

No I think naming is quite a good analogy to the relationship between
variables and objects in Ruby.


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale