From: Nokan Emiro Date: 2012-11-24T19:39:30+09:00 Subject: I'm exploiting Ruby references --f46d043c7f4291d36104cf3b501b Content-Type: text/plain; charset=UTF-8 Hi, I think I've found a nice example that shows the power of Ruby usually *not* making copies of objects. But while I was trying to take it further, I just bumped into a limitation: as far as I know it's impossible to replace an object with any other and changing all the references pointing to the new one at once. It is possible to do it with #replace(other_obj) only if the type of the new object is still an Array, Hash or String. But what if I want to change the underlying type? Let me explain what I'm trying to do in a more details: I'm dealing with an equation system in my Ruby code, and references are very useful in my case. Suppose that we have an equation system that always has a variable on the left hand side, and an expression on the right hand side, and variables have maximum one equations where they appear on the left hand side. So, it is straightforward to represent this in a Hash, like this: eq = { "k"=>12, "y"=>["k", :+, 1], "a"=>"y", "x"=>["y", :*, ["a", :+, "k", :+, 1]] } This represents the equation system k = 12 y = k + 1 a = y x = y * (a + k + 1) Variables are always Strings, operators are Symbols, and compound statements are represented by Arrays. Now suppose that I want to substitute values in one equation from another. For instance let's replace the variable "y" in the equation x = y * (...) with k+1 from the second equation (y = k+1): eq['x'][0] = eq['y'] The equation system changes to this: { "k"=>12, "y"=>["k", :+, 1], "a"=>"y", "x"=>[["k", :+, 1], :*, ["a", :+, "k", :+, 1]] } The wonderful thing in this is that instead of having a copy of it the expression of k+1 it's now referenced by two equations. The befit of this is that if I do further substitutions on the y = k+1 equation, I'll have the modifications in the x =... equation too. When we replace "k" with it's value from the first equation: eq['y'][0] = eq['k'] # eq['k'] is 12 we'll get this { "k"=>12, "y"=>[12, :+, 1], "a"=>"y", "x"=>[[12, :+, 1], :*, ["a", :+, "k", :+, 1]] } Can you see the number 12 appering in the last equation? :) Awesome! It's exactly what I wanted to get. So far so good. Now let's do some simplifications here. Everybody knows that 12+1 is 13, so let's replace eq['y'] with 13. Well, the problem is, that we can't, because eq['y'] = 13 will break the carefully built reference system between the equations. The new value of eq['y'] will be 13, of course, but the other references (the one from the last equation) pointing to the array [12, :+, 1] will still hold the old reference to the array. There's one ugly solution however. I can use Array#replace on eq['y'] to replace it with another Array, for instance with the array [13]. ([13] is an array with a single element that is the numbe 13) The array [13] is not exactly 13, but very similar, and I don't know any better solution at the moment: eq['y'].replace [13] This will do the trick, but [13] is not very nice, it's like the numbe 13 in totally unnecessary brackets: {"k"=>12, "y"=>[13], "a"=>"y", "x"=>[[13], :*, ["a", :+, "k", :+, 1]]} I don't want to represent 13 as [13]. What I really would love to do it to replace an object (in this case the array [12, :+, 1]) with any other object (in this case the Fixnum 13) in a way that changes all the references from the old object to the new one. Just like #replace does if the new object has the same type as the old one (String, Array or Hash). Array#replace does not work with non-Array arguments, but it would be great to force it to work somehow. Is it somehow possible? u. --f46d043c7f4291d36104cf3b501b Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Hi,

I think I've found a nice example that shows the= power of Ruby
usually *not* making copies of objects. =C2=A0But = while I was trying to
take it=C2=A0further, I just bumped into a = limitation: =C2=A0as far as I know it's
impossible to replace an object with any other and changing all
<= div>the references pointing to the new one at once. =C2=A0It is possible to= do
it=C2=A0with #replace(other_obj) only if the type of the new = object is still an
Array, Hash or String. =C2=A0But what if I want to change the underlyi= ng
type?


Let me explain w= hat I'm trying to do in a more details:

I'= m dealing with an equation system in my Ruby code, and
references are very useful in my case. =C2=A0Suppose that we have an
equation system that always has a variable on the left hand side,<= /div>
and an expression on the right hand side, and variables have maxi= mum
one equations where they appear on the left hand side. So, it is
=
straightforward=C2=A0to represent this in a Hash, like this:

eq =3D {
=C2=A0"k"=3D>12= ,
=C2=A0"y"=3D>["k", :+, 1],
=C2=A0"a"=3D>"y",
=C2=A0"x"=3D>["y", :*, ["a"= ;, :+, "k", :+, 1]]
}

This represents the equation system<= /div>

k =3D 12
y =3D k + 1
a = =3D y
x =3D y * (a + k + 1)

Variables are always = Strings, operators are Symbols, and compound statements
are repre= sented by Arrays. =C2=A0Now suppose that I want to substitute values in one=
equation from another. =C2=A0For instance let's replace the variab= le "y" in the equation
x =3D y * (...)=C2=A0with k+1 fr= om=C2=A0the second equation (y =3D k+1):

eq['x'][0] =3D eq['y']
<= br>
The equation system changes to this:

{
=C2=A0"k"=3D>12,
= =C2=A0"y"=3D>["k", :+, 1],
=C2=A0"a"=3D>"y",
=C2=A0"x"=3D>[["k", :+, 1], :*, [&qu= ot;a", :+, "k", :+, 1]]
}

The wonderful thing in this is that = instead of having a copy of it the expression of k+1
it's now= referenced by two=C2=A0equations. =C2=A0The befit of this is that if I do = further substitutions
on the y =3D k+1 equation, I'll have the modifications in the x = =3D... equation too. =C2=A0When we
replace "k" with it&= #39;s value from the first equation:

eq['y'][0] =3D eq['k'] =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 # eq['k'] is 12

we= 'll get this

{
=C2=A0"= ;k"=3D>12,
=C2=A0"y"=3D>[12, :+, 1],
=C2=A0"a"=3D>"y",
=C2=A0"x"=3D>[[12, :+, 1], :*, ["a",= :+, "k", :+, 1]]
}

Can you see the number 12 appering i= n the last equation? :) =C2=A0Awesome! =C2=A0It's exactly what I
<= div>wanted to get.

So far so good.

<= /div>

Now let's do some simplifications here. =C2=A0Everybody = knows that 12+1 is 13, so let's replace
eq['y'] with = 13. =C2=A0Well, the problem is, that we can't, because=C2=A0eq['y&#= 39;] =3D 13 will break the
carefully built reference system between the equations. =C2=A0The new = value of eq['y'] will be
13, of course, but the other ref= erences (the one from the last equation) pointing to the
array [1= 2, :+, 1] will still hold the=C2=A0old reference to the array.

There's one ugly solution however. =C2=A0I can use = Array#replace on eq['y'] to replace it with
another Array= , for instance with the array [13]. =C2=A0 ([13] is an array with a single = element that is
the numbe 13) =C2=A0The array [13] is not exactly 13, but very similar= , and I don't know any
better solution at the moment:

eq['y'].replace [13]

<= div>This will do the trick, but [13] is not very nice, it's like the nu= mbe 13 in totally unnecessary
brackets:

{"= ;k"=3D>12, "y"=3D>[13], "a"=3D>"y&qu= ot;, "x"=3D>[[13], :*, ["a", :+, "k", :+, = 1]]}

I don't want to represent 13 as = [13]. =C2=A0What I really would love to do it to replace an
objec= t (in this case the array [12, :+, 1]) with any other object (in this case = the Fixnum
13) in a way that changes=C2=A0all the references from the old object = to the new one. =C2=A0Just
like #replace does if the=C2=A0new obj= ect has the same type as the old one (String, Array or
Hash).

Array#replace does not work with non-Array arguments, but it wou= ld be great to force
it to work somehow. =C2=A0Is it somehow poss= ible?

u.


--f46d043c7f4291d36104cf3b501b--