value by reference

T

trans.

| sure, maybe its difficult for you to see redesign just yet,
| but you'll have to do so in any case. the use of such
| misdesign will just get you further down the well...

Is the "right" design pure by-value? You seem to be pushing in that
direction.
 
M

Mohammad Khan

#!/usr/bin/env ruby

def do_something(a, b, c)
a += 1
b += 2
c += 3
end

def another_do_something(foo=Foo.new)
foo.do_something
end

class Foo
def initialize
@value = 0
end

def value
return @value
end

def value=(val)
@value = val
end

def do_something
@value += 1
@value += 2
@value += 3
end
end

a, b, c = 5, 6, 7
f = Foo.new

# scenario 1
puts "before do_something : #{a.inspect}, #{b.inspect}, #{c.inspect}"
do_something( a, b, c)
puts "after do_something : #{a.inspect}, #{b.inspect}, #{c.inspect}" # a, b, c not changed
#do_something( a.clone, b.clone, c.clone)
#puts "after clone : #{a.inspect}, #{b.inspect}, #{c.inspect}" # can't clone Fixnum

# scenario 2
puts "before : #{f.inspect}"
another_do_something(f)
puts "after with f : #{f.inspect}" # f changed
another_do_something(f.clone)
puts "after with f.clone : #{f.inspect}" # f not changed, it make sense


What is the difference between scenario 1 and scenario 2?
What is making scenario 1 not changed?

If everything is object, Why can't I do
do_something(a.clone, b.clone, c.clone) # I don't want them to be changed
do_something(a, b, c) # change a, b, c like other objects


Hope, I could explain properly what I am trying to understand.

MOhammad
 
A

Alexander Kellett

That's silly. By that line of reasoning, nearly every other language
has got it wrong. Wrong must be pretty good since Ruby is no where near
as popular as those languages that can do this sort of thing.

sure. people who want quick unmaintainable hacks shouldn't use ruby i
guess.

Alex
 
A

Alexander Kellett

| sure, maybe its difficult for you to see redesign just yet,
| but you'll have to do so in any case. the use of such
| misdesign will just get you further down the well...

Is the "right" design pure by-value? You seem to be pushing in that
direction.

yes
i've coded in c++ also in which pass by ref is possible
and abhor it
pass by ref is just plain evil
pass by ref in which the *caller* states that
its a ref, (as in c via a ref and a de-ref of ptrs),
is okay in my books, but implicit anything sucks

Alex
 
M

Mohammad Khan

That's silly. By that line of reasoning, nearly every other language
has got it wrong. Wrong must be pretty good since Ruby is no where near
as popular as those languages that can do this sort of thing.

I think the problem with Ruby is that it _can be done_ if you use
certain _types_ of objects, but not others. That to me goes against the
feather of our friendly duck.
Here, I agree with you.
certain _types_ of object are (probably) : clonable and not clonable

Mohammad
 
A

Alexander Kellett

Here, I agree with you.
certain _types_ of object are (probably) : clonable and not clonable

lets please just end this with a simple word:
performance
this thread has been repeated over and over again
i'd suggest reading the archives rather than
repeating it again.

florian has already suggested a possible solution,
i've suggested a very slow but 2 line solution,
and now its just degraded into the 'possibility'
to fix the hammer when the nail has disappeared
several messages back.

i agree for what its worth, its confusing at
first, but its *right* from a performance aspect
and *not wrong* in forcing you to rethink design.

Alex
 
A

Austin Ziegler

Florian said:
See my earlier posting about the lambda { } and Variable[:name]
ways of doing this.
Sorry, but I can't believe anybody would actually want to use the
lambda styles as proposed. They are ugly and obscure.

The Variable method is useful; I agree about lambda for this bit.
Judging by the frequency that this issue is discussed, it's more
confusing than you suggest.

I disagree. The problem is when it's explained that everything is a
reference. The best description I've seen for this was said a month
ago or so: Ruby's calling semantics are pass by value, but the value
passed is a reference to an object. People *understand* pass by
value and people *understand* pass by reference, but only after it's
been explained to them. This is no different; you have to learn the
calling semantics. It's pass-reference-by-value. Don't think too
much about variables -- they're just names, not memory blocks.
A typical programmers expects call-by-reference to work one way,
and Ruby works differently. Extra confusion results because this
difference is masked by using self-updating methods, but it always
fails for immediate objects, and it eventually fails in a
surprising way for non-immediate objects. I call it surprising
because a typical programmer does not expect the assignment
operator to destroy call-by-reference, but that is exactly what
happens.

This has been a situation where people are applying the concepts of
C/C++ and similar languages (where variables are slots in memory) to
Ruby (where variables are simply labels for object references).
Variables are programmers' tools in Ruby; nothing more, nothing
less.
def inc1(a, i); a += i; end
def inc2(a, i); a = a + i; end
To the naive Ruby programmer, inc1 and inc2 seem to be equivalent,
but Ruby gurus just shake their heads and sigh while they explain,
yet again, that there is a difference. Why is this considered a
good thing? :)

Um. They *are* the same thing.

"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

And these are *not* the same, and never should be considered the
same. The problem again is that people are coming at it from the
wrong perspective.
You might say that the typical programmer has grown accustomed to
a confusing model, and Ruby is better off without that model. But,
that is nigh on saying that Ruby is better off without the typical
programmer. And that would be a shame, since Ruby has much to
offer the hordes of Perl and Python programmers looking for
something better.

Except that Ruby's call model isn't that far from the way that Perl
works. Probably not far from Python's model, either.
Ruby does *not* support call-by-reference, in the traditional
sense of the term. Instead, it is strictly call-by-value, and
formal paremeters are copies of references from the calling scope.
If Ruby had real call-by-reference, then it would be trivial to
define a procedure that updates a variable from its parent's
scope, and inc1 and inc2 above would be equivalent.

Again, inc1 and inc2 are equivalent. However, Ruby doesn't have or
need "real" call-by-reference. Too many risks of bad programming
options, IMO.
Tcl is similar to Ruby, regarding both the style of variable
passing and the resulting confusion among its new adopters, but
Tcl documentation has always stressed the details of this issue,
and the Tcl core has the "uplevel" and "upvar" builtins. I'm not a
huge fan of Tcl, but I do think the Tcl folks handled this issue
in the best way possible.

Right. Now that we've got a way of expressing this clearly (Ruby's
calling semantics are pass-reference-by-value), this should no
longer be a source of confusion as documentation is updated.

-austin
 
F

Florian Gross

Glenn said:
See my earlier posting about the lambda { } and Variable[:name] ways
of doing this.

Sorry, but I can't believe anybody would actually want to use the lambda
styles as proposed. They are ugly and obscure.

They are wordy only when you want to increment multiple variables from
the outside. That does not hold true for simpler cases:

def inc() yield(1) end

inc { |x| var += x }

Or yet simpler:

def inc() yield end
inc { var += 1 }

I've not yet seen any sample code where the existing ways would not be
simple enough. Note that it's possible to write inc(Variable[:x]) when
using variable.rb. The implementation is reasonably straight-forward so
I don't see why something like this has to be included in core Ruby.
Especially not if it seems to be so rarely used in real world code.
(Unless said user is using it as a replacement for something that is
usually done in a simpler way in Ruby.)
Judging by the frequency that this issue is discussed, it's more
confusing than you suggest. A typical programmers expects
call-by-reference to work one way, and Ruby works differently.

Which might be entirely related to Ruby not being like every other
language out there. (And not every other language out there is like
every other language out there either.) Personally, I think Ruby's
semantics when it comes to variables and argument passing are way less
confusing than the ones in Perl and PHP.

If I'm not completely wrong Python, LISP, Smalltalk and JavaScript work
exactly in the same way that Ruby does.
Extra confusion results because this difference is masked by using
self-updating methods

I've not yet seen a language that tries as hard as Ruby to distinguish
between in-place and result-style methods. Other languages usually just
do nothing about the issue at all. In that case you have to read the
documentation to know what is happening. (Frequently operations are
in-place unless the Object is a Value object.)
but it always fails for immediate objects

Of course. How would you change the value of an immutable Object?
and it
eventually fails in a surprising way for non-immediate objects. I call
it surprising because a typical programmer does not expect the
assignment operator to destroy call-by-reference, but that is exactly
what happens.

def inc1(a, i); a += i; end
def inc2(a, i); a = a + i; end

To the naive Ruby programmer, inc1 and inc2 seem to be equivalent, but
Ruby gurus just shake their heads and sigh while they explain, yet
again, that there is a difference. Why is this considered a good
thing? :)

I fear that most people confuse themselves by assuming that Ruby works
like other languages they know. That leads to a confusingly
over-complicated model. Just forget everything you know and get your
knowledge from the Pickaxe. Ruby's model is really quite simple, but
people are constantly making up broken metaphors for themselves which is
not worth the effort at all...

I think the above code is an example of this. I don't see why the two
should be different and unless matz went insane over night they aren't.
You might say that the typical programmer has grown accustomed to a
confusing model, and Ruby is better off without that model. But, that
is nigh on saying that Ruby is better off without the typical
programmer. And that would be a shame, since Ruby has much to offer the
hordes of Perl and Python programmers looking for something better.

There's nothing wrong with being used to model's of other languages, but
it's a bad idea to mix them up when they don't match.

There's not one true model for everyone, but Ruby's certainly makes sense.
Ruby does *not* support call-by-reference, in the traditional sense of
the term. Instead, it is strictly call-by-value, and formal paremeters
are copies of references from the calling scope. If Ruby had real
call-by-reference, then it would be trivial to define a procedure that
updates a variable from its parent's scope, and inc1 and inc2 above
would be equivalent.

I'll still want to explain this differently, to keep confusing at a minimum:

Ruby does not pass references to variables, it passes references to Objects.

(Variables are no shoe boxes in Ruby, they are just names for things.)
Tcl is similar to Ruby, regarding both the style of variable passing and
the resulting confusion among its new adopters, but Tcl documentation
has always stressed the details of this issue, and the Tcl core has the
"uplevel" and "upvar" builtins. I'm not a huge fan of Tcl, but I do
think the Tcl folks handled this issue in the best way possible.

I'm not experienced at Tcl. What do those built ins do?
 
A

Austin Ziegler

That's silly. By that line of reasoning, nearly every other
language has got it wrong. Wrong must be pretty good since Ruby is
no where near as popular as those languages that can do this sort
of thing.

No, it's not silly. Consider that C didn't have reference arguments
until late in life (I don't remember offhand whether it's mentioned
in my K&R'89 covering ANSI C). You had to use pointers -- and
references came about because pointer math was simply asking for
trouble. You needed this because C couldn't return more than one
value from a function (usefully).

Ruby isn't constrained the way that C was, needing pointers and
references the same way.
I think the problem with Ruby is that it _can be done_ if you use
certain _types_ of objects, but not others. That to me goes
against the feather of our friendly duck.

WRONG. Wrong in every way. Some objects permit the in-place
modification of parts of their state. Others do not. Just because
you can do:

a << i

if "a" refers to an Array, String, or other objects where #<< is
defined doesn't make it a special exception. #<< isn't assignment;
it's appending. a += i *is* assignment, and it follows the very
*clear* rules that Ruby has for variables and objects. #+ is
supposed to add two object instances together into a third object,
not modify one of the objects in place.

Convention? You bet. But it's consistent, at least, which is more
than can be said for most of those languages that need call-by-
reference.

It also has NOTHING to do with duck-typing or POLS. Stop misusing
those terms.

-austin
 
F

Florian Gross

Mohammad said:
do_something(a, b, c) # change a, b, c like other objects

Let me give an example:

x, y, z = 1, 2, 3
do_something(x, y, z) # completely equivalent to
do_something(1, 2, 3)

do_something() does not get variables. It gets the values the variables
refer to. (It gets the objects the variables are names for.)

Therefore it can not change the variables, they are nothing physical.

variable.rb lets you turn variables *themselves* into Objects that can
be passed to methods.
 
F

Florian Gross

Michel said:
Hi, David. I know how it works now, that's why it's a proposal. The
idea would be to modify the language to allow that kind of
manipulation. Then, the following methods would be allowed:

a = 'hello world' # String
a.replace(/\w+/) # Regexp
a.replace(35) # Fixnum
a.replace(SomeClass.new) # SomeClass

And then you would be able to add methods like to_s! or to_i!, etcetera.

Something is usually wrong when you want an Object to change classes at
run time. There's certain use cases for this, but at large it's related
to confusing variables with Objects.

E.g. if you expect the above to work you're likely to expect this:

a = /something/
b = a
a.replace "other"
a # => "other"
b # => /something/

But you can not have that. The last line will always result in "other"
as well.

If you don't expect this and if you can live with quite some limitations
you should have a look at the Object#become that evil-ruby implements.
(See evil.rubyforge.org)
 
A

Austin Ziegler

def do_something(a, b, c)
a += 1
b += 2
c += 3
end

def another_do_something(foo = Foo.new)
foo.do_something
end

class Foo
def initialize
@value = 0
end

def value
return @value
end

def value=(val)
@value = val
end

def do_something
@value += 1
@value += 2
@value += 3
end
end
a, b, c = 5, 6, 7
f = Foo.new [...]
If everything is object, Why can't I do
do_something(a.clone, b.clone, c.clone) # I don't want them to
# be changed
do_something(a, b, c) # change a, b, c like
# other objects
Hope, I could explain properly what I am trying to understand.

I don't know why you're not getting this, as it is very simple.

a, b, and c are not objects. They're variables.

When you call Foo#do_something, you're changing the internal state
of an object. When you call Object#do_something, you're passing
three variables that can refer to just about any object.

It's no different than if I defined do_something as:

def do_something(a, b, c)
a += Foo.new
b += Foo.new
c += Foo.new
end

As long as Foo can be added to the values of a, b, and c, I'm going
to get three completely new objects.

Try it with this:

def do_something(a, b, c)
a += "-half"
b += "-thirds"
c += "-fourths"
puts a.id, b.id, c.id
[ a, b, c ]
end

def do_something2(a, b, c)
a << "-half"
b << "-thirds"
c << "-fourths"
puts a.id, b.id, c.id
[ a, b, c ]
end

a = "one"
b = "two"
c = "three"

puts "#{a}<#{a.id}>, #{b}<#{b.id}>, #{c}<#{c.id}>"

x, y, z = do_something(a, b, c)
puts "#{x}<#{x.id}>, #{y}<#{y.id}>, #{z}<#{z.id}>"
puts "#{a}<#{a.id}>, #{b}<#{b.id}>, #{c}<#{c.id}>"

x, y, z = do_something2(a, b, c)
puts "#{a}<#{a.id}>, #{b}<#{b.id}>, #{c}<#{c.id}>"
puts "#{x}<#{x.id}>, #{y}<#{y.id}>, #{z}<#{z.id}>"

This will help you understand. #<< modifies a String in-place. It's
concatenation. += concatenates and creates a new string.

-austin
 
F

Florian Gross

trans. said:
Right. I'm not suggesting that Ruby change this. I'm just wondering if
might be possible to add an extra feature that would allow for the
alternate when passing arguments through methods.

Please, don't. That would actually make all this wrong thinking models
right in certain cases which would make the whole situation vastly more
complex. I like Ruby being a simple and consistent language instead of a
monster like C++.
Personally, I've alwasy thought of variables as containters, so in that
way of thinking, which I think is common, one would expect to be able
to change what's in the container. I don't think Ruby's approach is
always simple for the enduser and it does lead to some surprises --for
example this very thread.

But this is the very source of all this confusion. Variables are names.
I don't know how often I will have to repeat this. :)
Binding.of_caller is useful for meta-programming, but that's bad
business for general use.

It's also needed for wrapping eval() and useful for providing convenient
interfaces to slightly context-sensitive things. (Breakpoints are an
example of that.) I'd like to see it in the language itself, having to
go through a Binding for modifying variables or calling methods in
another context should give you a hint that you should not use it when
you don't need it.
 
F

Florian Gross

trans. said:
That's silly. By that line of reasoning, nearly every other language
has got it wrong. Wrong must be pretty good since Ruby is no where near
as popular as those languages that can do this sort of thing.

No, other languages use other models that need this. They don't work
like Ruby which is why they need it. Ruby needs other features that
those languages don't have in certain cases, but over all I have to say
that Ruby did a good job at being simple and consistent which is one of
the top reasons I like it so much. Everything just makes sense once you
understand the basics.

There's multiple approaches to this, but they should not be mixed.
I think the problem with Ruby is that it _can be done_ if you use
certain _types_ of objects, but not others. That to me goes against the
feather of our friendly duck.

No, it can not be done. You can never modify a variable that appeared in
your method invocation. You can change the Objects that you're methods
gets in case they are value Objects, but that's how OOP works. It makes
sense to be able to have entities that can change their state at run time.
 
M

Mohammad Khan

Let me give an example:

x, y, z = 1, 2, 3
do_something(x, y, z) # completely equivalent to
do_something(1, 2, 3)

do_something() does not get variables. It gets the values the variables
refer to. (It gets the objects the variables are names for.)

I understand that.
But what about scenario 2?
Scenario 2 is not acting as scenario 1, is it because scenario 2 gets
object rather than variable?
Or, Scenario 2 gets clonable object while scenario 1 not?
Thanks, Florian.
 
M

Mohammad Khan

def do_something(a, b, c)
a += 1
b += 2
c += 3
end

def another_do_something(foo = Foo.new)
foo.do_something
end

class Foo
def initialize
@value = 0
end

def value
return @value
end

def value=(val)
@value = val
end

def do_something
@value += 1
@value += 2
@value += 3
end
end
a, b, c = 5, 6, 7
f = Foo.new [...]
If everything is object, Why can't I do
do_something(a.clone, b.clone, c.clone) # I don't want them to
# be changed
do_something(a, b, c) # change a, b, c like
# other objects
Hope, I could explain properly what I am trying to understand.

I don't know why you're not getting this, as it is very simple.

May be I am not that simple!! :p
a, b, and c are not objects. They're variables.
Isn't everything *object* in Ruby?


Now you know, what I am after ?!

--
MOhammad

When you call Foo#do_something, you're changing the internal state
of an object. When you call Object#do_something, you're passing
three variables that can refer to just about any object.

It's no different than if I defined do_something as:

def do_something(a, b, c)
a += Foo.new
b += Foo.new
c += Foo.new
end

As long as Foo can be added to the values of a, b, and c, I'm going
to get three completely new objects.

Try it with this:

def do_something(a, b, c)
a += "-half"
b += "-thirds"
c += "-fourths"
puts a.id, b.id, c.id
[ a, b, c ]
end

def do_something2(a, b, c)
a << "-half"
b << "-thirds"
c << "-fourths"
puts a.id, b.id, c.id
[ a, b, c ]
end

a = "one"
b = "two"
c = "three"

puts "#{a}<#{a.id}>, #{b}<#{b.id}>, #{c}<#{c.id}>"

x, y, z = do_something(a, b, c)
puts "#{x}<#{x.id}>, #{y}<#{y.id}>, #{z}<#{z.id}>"
puts "#{a}<#{a.id}>, #{b}<#{b.id}>, #{c}<#{c.id}>"

x, y, z = do_something2(a, b, c)
puts "#{a}<#{a.id}>, #{b}<#{b.id}>, #{c}<#{c.id}>"
puts "#{x}<#{x.id}>, #{y}<#{y.id}>, #{z}<#{z.id}>"

This will help you understand. #<< modifies a String in-place. It's
concatenation. += concatenates and creates a new string.

-austin
 
F

Florian Gross

Mohammad said:
But what about scenario 2? [methods changes state of an Object that
it gets as an argument] Scenario 2 is not acting as scenario 1, is it
because scenario 2 gets object rather than variable? Or, Scenario 2
gets clonable object while scenario 1 not?

First, let's agree on using the term "mutable" (or "changeable") instead
of "cloneable". (Immutable objects can not be cloned most of the time,
but the both terms are not strictly the same things.)

Scenario 2 changes attributes of an Object. This is something that is
entirely possible. It makes sense for a CarFactory object to be stopped
or running -- it also makes sense that you are able to stop or (re)start
such an object at run time. What can not be done is changing the value
of a variable that appeared in the method invocation because the method
does not know anything about the variable -- it gets the Object. Objects
can have state that can be changed. This can happen via accessors that
are invoked like obj.foo = x or other methods like car_factory.stop.
But while obj.foo looks similar to variable assignment it is something
entirely else.

Why do different things look so similar in Ruby? It's uniform access at
work.

In other languages there usually is the distinction between Object's
fields and methods. Having public fields is usually a bad idea (it
breaks encapsulation) and looks like this:

obj.field += 5

Having methods that modify state looks like this:

obj.setField(obj.getField() + 5)

In Ruby both look like this:

obj.field += 5

Even if obj.field=() or obj.field() do not directly map to an instance
variable at all like in this case:

def obj.radius()
@diameter / 2
end

def obj.radius=(new_radius)
@diameter = new_radius * 2
end

I hope this explains how Ruby works. If there is still anything left
that you don't understand, feel free to ask.
 
A

Andreas Semt

Florian said:
No, other languages use other models that need this. They don't work
like Ruby which is why they need it. Ruby needs other features that
those languages don't have in certain cases, but over all I have to say
that Ruby did a good job at being simple and consistent which is one of
the top reasons I like it so much. Everything just makes sense once you
understand the basics.

There's multiple approaches to this, but they should not be mixed.



No, it can not be done. You can never modify a variable that appeared in
your method invocation. You can change the Objects that you're methods
gets in case they are value Objects, but that's how OOP works. It makes
sense to be able to have entities that can change their state at run time.

A nice discussion.
Florian should write a book! :)

Greetings,
Andreas
 
F

Florian Gross

Mohammad said:
Isn't everything *object* in Ruby?

Now you know, what I am after ?!

Every thing is an Object. Names for things are not Objects because then
it would not be clear whether you are doing something with the name
itself or with the Object it refers to. My variable.rb code lets you
refer to the names themselves instead of their value with the
Variable[:x] syntax.

Perl and PHP IIRC do this with the \$foo syntax (and C# AFAIK uses the
'ref' keyword for this, but don't quote me on this), but I think we
should not have something like that in Ruby.
 
F

Florian Gross

Andreas said:
You can change the Objects that you're
methods gets in case they are value Objects [...]
A nice discussion.
Florian should write a book! :)

Thanks, but I just spotted myself using "you're" instead of "your".
Everything's going downhill for sure.

Can we all pretend that it didn't happen? ;)
 

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,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top