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

M

Mason Kelsey

[Note: parts of this message were removed to make it a legal post.]

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
 
V

venkatesh Peddi

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

=20

temp var =3D old var

new var =3D temp var

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

=20

ps:this is a work around=2C i dont recommend it.

=20

=20

-V
=20
Date: Thu=2C 10 Sep 2009 12:24:05 +0900
From: (e-mail address removed)
Subject: How Are Variables Kept Independent of Each Other Yet Pass Values= ?
To: (e-mail address removed)
=20
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 anoth= er
variable that you really haven't created an independent variable at all b= ut
just another name for the source variable. So if you code "new_var =3D
old_var" the new_var simply points to the location of the value for
old_var. Consequently=2C if you change one variable=2C you have changed b= oth.
I've tested this and it appears to be true. I've made bold the crucial pa= rt
of the code.
=20
In the following code verifies that variables are not independent in
assignments:
=20
# Test to Determine how 2 Dimentional Arrays Work
current_state =3D [[1=2C 3=2C 6]=2C [5=2C 0=2C 2]=2C [4=2C 7=2C 8]]
#new_state =3D [[1=2C 3=2C 6]=2C [5=2C 0=2C 2]=2C [4=2C 7=2C 8]]
*new_state =3D current_state*
puts "Current State =3D " + 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] =3D current_state[2][1]
new_state[2][1] =3D current_state[1][1]
# Show changed values
puts "New State[1][1] =3D " + new_state[1][1].to_s
puts "New State[2][1] =3D " + new_state[2][1].to_s
=20
Gives the results:
=20
ruby Simple_Test_Class_EightPuzzle.rb
Current State =3D 136502478
current_state[1][1] is 0 *<=3D=3D Values before the change*
current_state[2][1] is 7 *<=3D=3D Values before the change*
*New State[1][1] =3D 7 <=3D=3D Values after the change
New State[2][1] =3D 7 <=3D=3D Values after the change. Due to new_state a= nd
current_state pointing to the same value.
*>Exit code: 0
=20
Which would only happen if new_state and current_state point to the same
value!
=20
If I execute the code with the above bold line commented out and the comm= ent
line above it executed=2C then the exchange occurs properly because new_s= tate
and current_state are two independent variables. Thus=2C
=20
# Test to Determine how 2 Dimentional Arrays Work
current_state =3D [[1=2C 3=2C 6]=2C [5=2C 0=2C 2]=2C [4=2C 7=2C 8]]
*new_state =3D [[1=2C 3=2C 6]=2C [5=2C 0=2C 2]=2C [4=2C 7=2C 8]]
*#new_state =3D current_state
puts "Current State =3D " + 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] =3D current_state[2][1]
new_state[2][1] =3D current_state[1][1]
# Show changed values
puts "New State[1][1] =3D " + new_state[1][1].to_s
puts "New State[2][1] =3D " + new_state[2][1].to_s
=20
produces the desired results=2C as
=20
ruby Simple_Test_Class_EightPuzzle.rb
Current State =3D 136502478
current_state[1][1] is 0
current_state[2][1] is 7
*New State[1][1] =3D 7
New State[2][1] =3D 0 <=3D=3D Proper exchange occurred because new_state = and
current_state are independent.
*>Exit code: 0
Now=2C my problem is that I *must* give new_state the value that current_= state
has but keep them independent=2C 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=2C I j= ust
cannot remember where I read it in the books and the indexes are not
helpful.
=20
Thanks in advance!
=20
No Sam

_________________________________________________________________
Sports=2C news=2C fashion and entertainment. Pick it all up in a package ca=
lled MSN India
http://in.msn.com=
 
Y

Yossef Mendelssohn

the easy way is you can have another temp variable to which u have to ass=
ign the old value.and assing the temp value to new. in this case when u cha=
nge the new the temp will change but not old.
temp var =3D old var

new var =3D temp var

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

What are you talking about? Why would that work? Why would there be
any difference between `x =3D a; b =3D x` and `b =3D a`?
a =3D [1,2,3]
x =3D a
b =3D x
b[2] =3D 4
b =3D> [1, 2, 4]
a
=3D> [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 =3D a`). In many cases, calling .dup or .clone
will work. (As in `b =3D a.dup` or `b =3D a.clone`.)

However, since you have an array of arrays, you're going to need a
"deep copy". I believe `b =3D Marshal.load(Marshal.dump(a))` is the
standard idiom.
 
7

7stud --

Yossef said:
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"]]
 
R

Rick DeNatale

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.[](*rows)
new(rows)
end

def [](row,col)
@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
 
M

Mason Kelsey

[Note: parts of this message were removed to make it a legal post.]

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

Yossef said:
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"]]
 
M

Mason Kelsey

[Note: parts of this message were removed to make it a legal post.]

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

Yossef said:
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"]]
 
M

Mason Kelsey

[Note: parts of this message were removed to make it a legal post.]

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

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

Rick DeNatale

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.
=A0And any instructor needs to be sure that the students
understand the significance of variables being objects. =A0They cannot ju= st
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.


--=20
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
 
P

Pascal J. Bourguignon

Mason Kelsey said:
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.
 
R

Robert Klemme

2009/9/10 Mason Kelsey said:
This also answers my question of why Ruby was designed this way. =A0Becau= se 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. =A0And 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

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
J

Joel VanderWerf

Pascal said:
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"
 
R

Rick DeNatale

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,008
Latest member
Rahul737

Latest Threads

Top