value by reference

M

Mohammad Khan

What I was missing, this thread made me to understand that.

a = 5
puts a.class -> Fixnum

As I knew everything is object in Ruby.. I thought a = 5 would do something like Fixnum.new(5) internally.
and 'a' would remain as object. I was wrong at this point.

Thanks everybody, specially Florian and Austin for their nice explanation.

I am out of this tread.

Mohammad
 
A

Austin Ziegler

In this instance it would be confusing.
But using this concept...
I would be able to do what I wanted to do (please see my original posting)

Which gets right back to the original question:

*Why* do you want to be able to do that? Is there not something else
that you can perhaps do to improve your design that doesn't require
this, since it's not really a supported mode of operation in Ruby?

-austin
 
M

Mark Hubbart

Third:

Ref.new(false) or Ref.new(nil) do not act like you would expect them to
in conditional contexts:

do_something if ref # always done
x = ref || y # x is always ref

Ah, I hadn't thought of that. I guess if you would need to
de-reference in conditionals:
do_something if ref.__value__
Fourth:

Some of Ruby's C methods want their arguments to be instances of a
particular class. They won't even call the usual #to_x methods.
str.scan(ref) is one example of that.

I didn't know of that one. So String.scan doesn't use duck typing?
Fifth:

Object.instance_method:)inspect).bind(ref).call calls the #inspect
method of the ref, not of the Object it refers to.

I would consider that a feature :) at a later time, a method could be
added, __ref__, would would allow you to call normal ruby methods on
the reference object; get its id, inspect it, etc.

This was really just a proof-of-concept... and you showed a couple of
big holes in it. :) Ahh, well. I suspect that for most things, this
will work, with stated caveats.

cheers,
Mark
 
F

Florian Gross

Mark said:
Ah, I hadn't thought of that. I guess if you would need to
de-reference in conditionals:
do_something if ref.__value__

Yup, #to_bool is really missing here.
I didn't know of that one. So String.scan doesn't use duck typing?

Lots of C methods don't even try to convert their arguments which is
quite sad. There's no #to_re or #to_regexp. Because of that I have to
use a huge work-around in Regexp::English that involves sub classing
Regexp and recalling the Regexp#initialize method whenever the value
changes...
I would consider that a feature :) at a later time, a method could be
added, __ref__, would would allow you to call normal ruby methods on
the reference object; get its id, inspect it, etc.

I agree, I'm even using the above when I don't trust the methods the
Object provides. (Sandboxes, DRb)

But it's still a case where the caller needs to be aware of refs and
possibly dereference them manually.
 
W

why the lucky stiff

Florian said:
So far, the cons are two:

1. The current model doesn't support it.
2. The performance would be poor:

[...] but maybe that statement ("ruby doesn't
work that way") is enough to stop any further improvement.

I disagree. I think there are some core principles of Ruby that make it
Ruby. These should not change, especially not if there are no good
sample situations that would require the change to work correctly.

Disagreement here as well. I've needed Object#become quite a bit in my
travels and I think Ruby could support it without incurring cost. It's
as simple as a memcpy of an RStruct.

I think Ruby lacks this feature either because it's a scary change that
could be misunderstood or because it's difficult to distill into a
technique that fits within the current Ruby.

I only have one use case: I'm building a complex Ruby object, when I find
a point of recursion or transformation which requires me to retrace my
steps and replace a node farther back in the tree.

What I'm looking for is closer to a SymbolTable#sub!. Where I pass it
two object IDs and every instance of the former becomes the latter.
Better yet, a third object ID parameter would cause substitution only
within the tree starting at that VALUE.

It would be fine if this mechanism checked for ! BUILTIN_TYPE(obj) in
the first call described above, but allowed builtin type subs within a
tree.

_why
 
G

Glenn Parker

David said:
In any case, I believe the two things in your example are actually
equivalent. My understanding is that Ruby always expands:
x += y
to
x = x + y


Ouch! That's what I get for posting code without trying it out first.
Even something that trivial tripped me up, and I should know better. :(


Austin said:
"a += i" is syntax magic for "a = a + i". Perhaps you're referring
to something like:

def app1(a, i); a << i; end
def app2(a, i); a += i; end


Right, that is closer to what I was trying to illustrate. As to whether
those two should be considered equivalent, I assert each person's answer
will depend on their expectations and their prior experience. :)


Austin said:
Except that Ruby's call model isn't that far from the way that Perl
works. Probably not far from Python's model, either.

Perl generally uses call-by-value, but it also supports
call-by-reference using the backslash operator:

sub inc {
$arg = shift @_;
$$arg += 1;
}
$x = 1;
inc(\$x);
print $x;

This prints "2". Here, "\$x" is a reference to $x, and "inc" assigns it
to $arg. $$arg dereferences the reference, allowing inc to modify $x
directly.

Like Ruby, Python doesn't seem to have any support for
call-by-reference, and Python coders have been through the exact same
discussion that we're having here (almost word-for-word):
http://mail.python.org/pipermail/python-list/2001-June/048603.html


Florian said:
I'm not experienced at Tcl. What do those built ins do?

Tcl's "upvar" is a generalized call-by-reference method. It allows a
function to bind a local variable to variable from the calling scope.

proc inc name {
upvar $name a
set a [expr $a + 1]
}
set x 1
inc x
puts $x

This also prints "2". In this case, "a" becomes an alias for "x" after
the call to upvar. Tcl's "uplevel" is very similar in concept to
Binding.of_caller, allowing execution of code in the caller's scope.
Tcl coders can use uplevel to create new flow-of-control structures.

I've seen one or two posts here that flat out denigrate
call-by-reference, or suggest that it is a workaround necessitated by
weak language design. This is a narrow view, IMHO. If we can define
methods that modify an object in place, then we are already halfway to
using call-by-reference semantics.

Oh well, this was probably more educational for me than for anybody
else, so thanks to everybody for your patience.
 
J

Jim Weirich

Glenn Parker said:
Perl generally uses call-by-value, but it also supports
call-by-reference using the backslash operator:

sub inc {
$arg = shift @_;
$$arg += 1;
}
$x = 1;
inc(\$x);
print $x;

Perl does it by creating a reference (with a backslash) and then
dereferencing the reference (with an extra $).

If you want the same in Ruby (with only a bit heavier syntax ... ref{:x}
instead of \$x and arg.value instead of $$arg), you could write:

def inc(arg)
arg.value += 1
end
x = 1
inc(ref{:x})
puts x # => 2

See http://onestepback.org/index.cgi/Tech/Ruby/RubyBindings.rdoc for
details on how to implement ref.
 
F

Florian Gross

why said:
Florian said:
So far, the cons are two:

1. The current model doesn't support it.
2. The performance would be poor:

[...] but maybe that statement ("ruby doesn't
work that way") is enough to stop any further improvement.

I disagree. I think there are some core principles of Ruby that make it
Ruby. These should not change, especially not if there are no good
sample situations that would require the change to work correctly.

Disagreement here as well. I've needed Object#become quite a bit in my
travels and I think Ruby could support it without incurring cost. It's
as simple as a memcpy of an RStruct.

Actually, it isn't. Have a look at the evil-ruby project. There is a lot
of cases that can lead to segfaults and endless loops with such a naive
implementation.

It's especially important that the RStructs are compatible meaning you
can not use it generally anyway.

I don't quite see how the two things (introducing variable-by-ref
semantics) and Object#become are related. Plus I was sort of arguing
against the stuff I quoted, e.g. not wanting to implement a feature in
the general case.
I only have one use case: I'm building a complex Ruby object, when I find
a point of recursion or transformation which requires me to retrace my
steps and replace a node farther back in the tree.

If it's a tree then there will usually only be one place that refers to
your Object. It ought to be possible to replace it even without #become.

As said: Note that I'm not against toying around with ideas or
implementing well tested ideas that match up with the languages core
philosophy without introducing too much new complexity.
 

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,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top