How to get real reference to an object?

P

Pavel Smerk

Assume a big hash and/or a nested structure and the need of a plenty of
operations on some hash[...][...][...] which is Float. How can one avoid
the repetitious evaluation of the indices? I have not been able to get a
"real" reference to that variable to do _something_like_ tmp =
referenceof(hash[...][...][...]) and work with the value directly
through the (dereferenced) tmp variable. In Perl I would say

$ perl -e '$x[1][2][3] = 1; $a = \$x[1][2][3]; $$a = 3; print $x[1][2][3]'
3

(where \... is a reference and $ before $a is a dereference).

Morover, why the return value of the assignment is not an l-value? The
following is legal in Perl ($x ||= 1) *= 2 --- why it is not legal in
Ruby as well?

Thanks, P.
 
D

David A. Black

Hi --

Assume a big hash and/or a nested structure and the need of a plenty of
operations on some hash[...][...][...] which is Float. How can one avoid the
repetitious evaluation of the indices? I have not been able to get a "real"
reference to that variable to do _something_like_ tmp =
referenceof(hash[...][...][...]) and work with the value directly through the
(dereferenced) tmp variable. In Perl I would say

$ perl -e '$x[1][2][3] = 1; $a = \$x[1][2][3]; $$a = 3; print $x[1][2][3]'
3

(where \... is a reference and $ before $a is a dereference).

h = { :a => { :b => {} } }
tmp = h[:a][:b]
tmp[:x] = "hi"
tmp[:x] << " there"
p h # => {:a=>{:b=>{:x=>"hi there"}}}

You're (almost) always dealing in references in Ruby. (And the almost
part doesn't affect you much anyway.) Every reference is exactly one
step away from the object; there's no such thing as a reference to a
reference. It's very different from Perl in that respect.
Morover, why the return value of the assignment is not an l-value? The
following is legal in Perl ($x ||= 1) *= 2 --- why it is not legal in Ruby as
well?

I assume it's because (x ||= 1) evaluates to the object 1, and 1 *= 2
doesn't make sense.


David

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Now available: The Well-Grounded Rubyist (http://manning.com/black2)
Training! Intro to Ruby, with Black & Kastner, September 14-17
(More info: http://rubyurl.com/vmzN)
 
Q

Quintus

Pavel said:
Assume a big hash and/or a nested structure and the need of a plenty
of operations on some hash[...][...][...] which is Float. How can one
avoid the repetitious evaluation of the indices? I have not been able
to get a "real" reference to that variable to do _something_like_ tmp
= referenceof(hash[...][...][...]) and work with the value directly
through the (dereferenced) tmp variable. In Perl I would say

$ perl -e '$x[1][2][3] = 1; $a = \$x[1][2][3]; $$a = 3; print
$x[1][2][3]'
3

(where \... is a reference and $ before $a is a dereference).

Morover, why the return value of the assignment is not an l-value? The
following is legal in Perl ($x ||= 1) *= 2 --- why it is not legal in
Ruby as well?

Thanks, P.

You can't get references of immediate values like Fixnums or Symbols. If
you want a reference, the only way you could do is to get a reference to
the innermost Hash:

irb(main):001:0> hsh = {1 => {2 => {3 => :value}}}
=> {1=>{2=>{3=>:value}}}
irb(main):002:0> hsh[1][2][3]
=> :value
irb(main):003:0> ref = hsh[1][2]
=> {3=>:value}
irb(main):004:0> ref[3] = :xyz
=> :xyz
irb(main):005:0> ref[3]
=> :xyz
irb(main):006:0> hsh[1][2][3]
=> :xyz
Morover, why the return value of the assignment is not an l-value? The
following is legal in Perl ($x ||= 1) *= 2 --- why it is not legal in
Ruby as well?
You try to assign a value to a Fixnum. The result of $x ||= 1 is 1 (if
$x is unintitialized) and so your expression would evolve to:
1 = 1 * 2
which is invalid code.

Marvin
 
P

Pavel Smerk

David said:
Assume a big hash and/or a nested structure and the need of a plenty of
operations on some hash[...][...][...] which is Float. How can one avoid the
repetitious evaluation of the indices? I have not been able to get a "real"
reference to that variable to do _something_like_ tmp =
referenceof(hash[...][...][...]) and work with the value directly through the
(dereferenced) tmp variable. In Perl I would say

$ perl -e '$x[1][2][3] = 1; $a = \$x[1][2][3]; $$a = 3; print $x[1][2][3]'
3

(where \... is a reference and $ before $a is a dereference).

h = { :a => { :b => {} } }
tmp = h[:a][:b]
tmp[:x] = "hi"
tmp[:x] << " there"
p h # => {:a=>{:b=>{:x=>"hi there"}}}

Yes, but I need something like:

$ ruby -e 'h = { :a => { :b => "hi" } }; tmp = h[:a][:b]; tmp << "
there"; p h'
{:a=>{:b=>"hi there"}}

which is OK, but not for Float:

$ ruby -e 'h = { :a => { :b => 5.0 } }; tmp = h[:a][:b]; tmp += 5.0; p h'
{:a=>{:b=>5.0}}

And that's why I'm asking for a "real" reference, because tmp apparently
is not any kind of reference to the h[:a][:b].
You're (almost) always dealing in references in Ruby. (And the almost
part doesn't affect you much anyway.) Every reference is exactly one
step away from the object; there's no such thing as a reference to a
reference. It's very different from Perl in that respect.

Mhm, an unfortunate difference, I'm afraid...

Of course, I could write tmp = h[:a] and then many times tmp[:b]. But
something like simple tmp as in Perl would seem to me far more elegant.
I assume it's because (x ||= 1) evaluates to the object 1, and 1 *= 2
doesn't make sense.

I know, my question is, why it does not evaluate to x. Then it would
have the same value (the value of x) and moreover it could stand on the
left side of an another assignment (as the x *= 2 does make sense).

Thanks, P.
 
G

Gary Wright

You're (almost) always dealing in references in Ruby. (And the almost
part doesn't affect you much anyway.) Every reference is exactly one
step away from the object; there's no such thing as a reference to a
reference. It's very different from Perl in that respect.

Mhm, an unfortunate difference, I'm afraid...

[...]
I assume it's because (x ||= 1) evaluates to the object 1, and 1 *= 2
doesn't make sense.

I know, my question is, why it does not evaluate to x. Then it would
have the same value (the value of x) and moreover it could stand on
the left side of an another assignment (as the x *= 2 does make
sense).

It doesn't evaluate to x because Ruby isn't Perl. It isn't like there
is an absolute right or wrong way to design a language. Each language
has its own idioms and techniques, some of which are not translatable
from one language to the next.
$ ruby -e 'h = { :a => { :b => "hi" } }; tmp = h[:a][:b]; tmp << "
there"; p h'
{:a=>{:b=>"hi there"}}

which is OK, but not for Float:

$ ruby -e 'h = { :a => { :b => 5.0 } }; tmp = h[:a][:b]; tmp += 5.0;
p h'
{:a=>{:b=>5.0}}

And that's why I'm asking for a "real" reference, because tmp
apparently is not any kind of reference to the h[:a][:b].

Variables in Ruby hold references to objects. They are not labels for
memory where values are stored. Your example should be written as:

h[:a][:b] += 5.0

Gary Wright
 
R

Rob Biedenharn

David said:
Assume a big hash and/or a nested structure and the need of a
plenty of operations on some hash[...][...][...] which is Float.
How can one avoid the repetitious evaluation of the indices? I
have not been able to get a "real" reference to that variable to
do _something_like_ tmp = referenceof(hash[...][...][...]) and
work with the value directly through the (dereferenced) tmp
variable. In Perl I would say

$ perl -e '$x[1][2][3] = 1; $a = \$x[1][2][3]; $$a = 3; print $x[1]
[2][3]'
3

(where \... is a reference and $ before $a is a dereference).
h = { :a => { :b => {} } }
tmp = h[:a][:b]
tmp[:x] = "hi"
tmp[:x] << " there"
p h # => {:a=>{:b=>{:x=>"hi there"}}}

Yes, but I need something like:

$ ruby -e 'h = { :a => { :b => "hi" } }; tmp = h[:a][:b]; tmp << "
there"; p h'
{:a=>{:b=>"hi there"}}

which is OK, but not for Float:

$ ruby -e 'h = { :a => { :b => 5.0 } }; tmp = h[:a][:b]; tmp += 5.0;
p h'
{:a=>{:b=>5.0}}

And that's why I'm asking for a "real" reference, because tmp
apparently is not any kind of reference to the h[:a][:b].

Well, it is, but Fixnum's are immediate (implementation detail) and
Float's act like value objects. What would happen if:
5.0 += 5.0
were legal? All 5's now act like 10's??
You're (almost) always dealing in references in Ruby. (And the almost
part doesn't affect you much anyway.) Every reference is exactly one
step away from the object; there's no such thing as a reference to a
reference. It's very different from Perl in that respect.

Mhm, an unfortunate difference, I'm afraid...

Of course, I could write tmp = h[:a] and then many times tmp[:b].
But something like simple tmp as in Perl would seem to me far more
elegant.
I assume it's because (x ||= 1) evaluates to the object 1, and 1 *= 2
doesn't make sense.

I know, my question is, why it does not evaluate to x. Then it would
have the same value (the value of x) and moreover it could stand on
the left side of an another assignment (as the x *= 2 does make
sense).

Thanks, P.


Because in Ruby, "x.y = z" is just syntactic sugar when x is an object
for:
x.send:)y=, z)
with the rule that the "value" of an assignment is the right-hand side
(i.e., z) so things like
w = x.y = z
are predictable (meaning that the "y=" method sent to x can't return
something other than z for the assignment to w. (And, the rule breaks
down if you don't use the sugar, but make the calls yourself:
w = x.send:)y=, z)
might result in w != z, but any programmer that does such a thing in
"real" code should be punished.)

-Rob

Rob Biedenharn http://agileconsultingllc.com
(e-mail address removed)
 
D

David A. Black

Hi --

David said:
Assume a big hash and/or a nested structure and the need of a plenty of
operations on some hash[...][...][...] which is Float. How can one avoid
the repetitious evaluation of the indices? I have not been able to get a
"real" reference to that variable to do _something_like_ tmp =
referenceof(hash[...][...][...]) and work with the value directly through
the (dereferenced) tmp variable. In Perl I would say

$ perl -e '$x[1][2][3] = 1; $a = \$x[1][2][3]; $$a = 3; print $x[1][2][3]'
3

(where \... is a reference and $ before $a is a dereference).

h = { :a => { :b => {} } }
tmp = h[:a][:b]
tmp[:x] = "hi"
tmp[:x] << " there"
p h # => {:a=>{:b=>{:x=>"hi there"}}}

Yes, but I need something like:

$ ruby -e 'h = { :a => { :b => "hi" } }; tmp = h[:a][:b]; tmp << " there"; p
h'
{:a=>{:b=>"hi there"}}

which is OK, but not for Float:

$ ruby -e 'h = { :a => { :b => 5.0 } }; tmp = h[:a][:b]; tmp += 5.0; p h'
{:a=>{:b=>5.0}}

And that's why I'm asking for a "real" reference, because tmp apparently is
not any kind of reference to the h[:a][:b].

Right; I wasn't taking into account the fact that your example was
dealing with numbers.
Mhm, an unfortunate difference, I'm afraid...

You'll have to talk to Larry about fixing it :) Seriously though... I
would advise you strongly not to compare Ruby and Perl token-by-token
or construct-by-construct. It's like criticizing a flute because it
doesn't have strings.

Of course, I could write tmp = h[:a] and then many times tmp[:b]. But
something like simple tmp as in Perl would seem to me far more elegant.

The two languages have completely different variable and assignment
semantics. Again, I'd try to get to know Ruby on its own terms.
There's plenty of elegance to be had there :)


David

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Now available: The Well-Grounded Rubyist (http://manning.com/black2)
Training! Intro to Ruby, with Black & Kastner, September 14-17
(More info: http://rubyurl.com/vmzN)
 

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

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,170
Latest member
Andrew1609
Top