Passing script input as method args always global?

In Perl I used to do this:

print 'Enter data: ';
chomp(my $in = <STDIN>);

sub doit {
   my $data = shift;
   .........
   return $data;
}

doit($in);

In Ruby the equivalent seems to be:

puts 'Enter data: '
in = gets.chomp

def doit(data)
   ........
   return data
end

doit(in)

However, Ruby passes arguments by reference so it seems the variable 'data' is always accessing and changing the file-global variable 'in'. Is there a more Perl-like, way of lexicalising the scope of variables passed as arguments to functions?

gvim

The thing I’ve come to in my own understanding is that since everything is an object in Ruby, that means every variable is actually a pointer to an object in Ruby as well.

So when you pass in to the doit method, you are passing the reference into the local method variable data. Initially, data and in are pointing to the same object. But then you have to be aware of what things you are doing on the data variable. If it’s things with modify the same object originally point to by in, then the object in points to is being changed. Thus it looks like in is changed.

Doing other things can create new objects in ruby, though, so doing something to data that ends up creating a new object also ends up making in look unchanged when doit exits, which is so.

So let’s try this.

def doit2(data)
  data.shuffle
end

According to the docs, shuffle creates a new array. So:

$ pry
[1] pry(main)> start_data = [1,2,3,4,5].freeze
=> [1, 2, 3, 4, 5]
[2] pry(main)> a_ary = start_data
=> [1, 2, 3, 4, 5]
[3] pry(main)> def doit(data)
[3] pry(main)* data.shuffle
[3] pry(main)* end
=> nil
[4] pry(main)> doit(a_ary)
=> [2, 4, 5, 3, 1]
[5] pry(main)> a_ary
=> [1, 2, 3, 4, 5]
[6] pry(main)> a_ary.object_id
=> 70307654300780
[7] pry(main)> doit(a_ary).object_id
=> 70307649978420
[8] pry(main)> doit(a_ary).object_id
=> 70307650161900

So you can see that .shuffle is creating a new object each time.

But remember we froze the source data up there? a_ary is also pointing to the frozen array, so when you change doit to something like this:

[9] pry(main)> def doit(data)
[9] pry(main)* data.shift
[9] pry(main)* end
=> nil
[10] pry(main)> a_ary
=> [1, 2, 3, 4, 5]
[11] pry(main)> a_ary.object_id
=> 70307654300780
[12] pry(main)> b_ary = doit(a_ary)
RuntimeError: can't modify frozen Array
from (pry):12:in `shift’

It fails because we tried to change a frozen object.

Now if we do this:

[13] pry(main)> b_ary = doit(a_ary.dup)
=> 1
[14] pry(main)> a_ary
=> [1, 2, 3, 4, 5]
[15] pry(main)>

doit is working on a new object that isn’t frozen.

···

On Nov 12, 2013, at 7:09 PM, gvim <gvimrc@gmail.com> wrote:

In Perl I used to do this:

print 'Enter data: ';
chomp(my $in = <STDIN>);

sub doit {
my $data = shift;
.........
return $data;
}

doit($in);

In Ruby the equivalent seems to be:

puts 'Enter data: '
in = gets.chomp

def doit(data)
........
return data
end

doit(in)

However, Ruby passes arguments by reference so it seems the variable 'data' is always accessing and changing the file-global variable 'in'. Is there a more Perl-like, way of lexicalising the scope of variables passed as arguments to functions?

gvim

Make a copy of the argument when you call the method:

  doit(in.dup)

···

gvim <gvimrc@gmail.com> wrote:

in = gets.chomp

def doit(data)
  ........
  return data
end

doit(in)

However, Ruby passes arguments by reference so it seems the variable
'data' is always accessing and changing the file-global variable
'in'. Is there a more Perl-like, way of lexicalising the scope of
variables passed as arguments to functions?

Hey guys

How do I unsubscribe? Or reduce the the mailings to a digest?

Thanks

amichai

···


Sent from Mailbox for iPhone

On Wed, Nov 13, 2013 at 3:11 AM, gvim <gvimrc@gmail.com> wrote:

In Perl I used to do this:
print 'Enter data: ';
chomp(my $in = <STDIN>);
sub doit {
   my $data = shift;
   .........
   return $data;
}
doit($in);
In Ruby the equivalent seems to be:
puts 'Enter data: '
in = gets.chomp
def doit(data)
   ........
   return data
end
doit(in)
However, Ruby passes arguments by reference so it seems the variable
'data' is always accessing and changing the file-global variable 'in'.
Is there a more Perl-like, way of lexicalising the scope of variables
passed as arguments to functions?
gvim

In Perl I used to do this:

print 'Enter data: ';
chomp(my $in = <STDIN>);

sub doit {
  my $data = shift;
  .........
  return $data;
}

doit($in);

In Ruby the equivalent seems to be:

puts 'Enter data: '
in = gets.chomp

def doit(data)
  ........
  return data
end

doit(in)

However, Ruby passes arguments by reference so it seems the variable
'data' is always accessing and changing the file-global variable 'in'. Is
there a more Perl-like, way of lexicalising the scope of variables passed
as arguments to functions?

Perl only has pass by reference (the elements of @_ are aliases of the ones
in the caller), and Ruby has only pass by value.

But, Perl has a number of basic types like arrays that you handle directly:

    @a = (1);

is an array, and

    $x = \@a;

is a reference to an array.

In Ruby you basically only have the latter. And since that's the only thing
you have no arrow is needed to dereference, you are always dealing with
reference values so there is no extra syntax. That is, in Ruby

    array[0]

translates to Perl as:

    $arrayref->[0]

Therefore, if you are going to mutate the string in the doit method and do
not want the caller to see the mutation you need to clone the argument:

    def doit(data)
      data = data.dup
      ...
    end

I personally prefer to clone in the method rather than in the caller. My
caller code should not be just paranoid and defensive, on the other hand
doit *knows* he is going to mutate, and *knows* it is not a good practice
to mutate arguments, so he is responsible for cloning in my view.

Xavier

···

On Wed, Nov 13, 2013 at 2:09 AM, gvim <gvimrc@gmail.com> wrote:

Gerald Vim wrote in post #1127142:

   x = x + 1

So a parameter is passed by reference but as soon as you modify it
you've cloned the object?

No, not at all.

``x = x + 1'' breaks down like this:

1. construct an object which is an Integer whose value is 1
2. find the object referred to by the variable named "x"; in this case,
an Integer
3. invoke the method called "+" on that object, passing the newly-minted
Integer as the first/only parameter*
4. update the variable named "x" to refer to the result of that method
invocation (i.e. this is the "=" part)

*Note: the "+" method on an Integer is non-destructive, internally it
creates a new Integer object whose value is the sum of the receiver and
the parameter, and returns that. Integer objects are immutable in ruby.

There are all sorts of other specifics going on (singleton Fixnums for
starters) but this simplification isn't inaccurate. Assignment is an
operation on the *variable* (a reference), and method invocations
(including "+") are operations on the *object* referred to by the
variable.

···

On 13/11/2013 11:32, Carlo E. Prelz wrote:

---

Here is a counter-example, assuming y = "abc", because I like writing
more than necessary:

  y = ( y << "d" )

1. construct an object which is a String whose value is "d"
2. find the object referred to by the variable named "y"; in this case,
our a String
3. invoke the method called "<<" on that object, passing the
newly-minted String as the first/only parameter
4. update the variable named "y" to refer to the result of that method
invocation

In this case the "<<" method on a String *is* destructive; it changes
the value of the Object, by appending the parameter to it. Fortunately
for
us, it also returns the (now updated) receiver. We could have left the
code as:

  y << "d"

... which would have saved us a variable assignment, but both snippets
result in an identical state.

--
Posted via http://www.ruby-forum.com/.

I seem to have misunderstood something. Changing 'data' within the 'doit' method does not seem to alter the 'in' variable even though it is passed as an argument to the method. So it seems args are passed by value after all ..... unless I'm mistaken .... again.

gvim

···

On 13/11/2013 01:57, Eric Wong wrote:

Make a copy of the argument when you call the method:

  doit(in.dup)

I'm beginning to see Ruby's "everything is an object" as a serious barrier to comprehension, epsecially when this object-orientation is dressed up in procedural syntax. Perl seems a lot more natural by comparison.

gvim

···

On 13/11/2013 12:33, Matthew Kerwin wrote:

No, not at all.

``x = x + 1'' breaks down like this:

1. construct an object which is an Integer whose value is 1
2. find the object referred to by the variable named "x"; in this case,
an Integer
3. invoke the method called "+" on that object, passing the newly-minted
Integer as the first/only parameter*
4. update the variable named "x" to refer to the result of that method
invocation (i.e. this is the "=" part)

*Note: the "+" method on an Integer is non-destructive, internally it
creates a new Integer object whose value is the sum of the receiver and
the parameter, and returns that. Integer objects are immutable in ruby.

There are all sorts of other specifics going on (singleton Fixnums for
starters) but this simplification isn't inaccurate. Assignment is an
operation on the *variable* (a reference), and method invocations
(including "+") are operations on the *object* referred to by the
variable.

---

Here is a counter-example, assuming y = "abc", because I like writing
more than necessary:

   y = ( y << "d" )

1. construct an object which is a String whose value is "d"
2. find the object referred to by the variable named "y"; in this case,
our a String
3. invoke the method called "<<" on that object, passing the
newly-minted String as the first/only parameter
4. update the variable named "y" to refer to the result of that method
invocation

In this case the "<<" method on a String *is* destructive; it changes
the value of the Object, by appending the parameter to it. Fortunately
for
us, it also returns the (now updated) receiver. We could have left the
code as:

   y << "d"

... which would have saved us a variable assignment, but both snippets
result in an identical state.

Gerald Vim wrote in post #1127156:

···

On 13/11/2013 12:33, Matthew Kerwin wrote:

4. update the variable named "x" to refer to the result of that method
variable.
our a String

   y << "d"

... which would have saved us a variable assignment, but both snippets
result in an identical state.

I'm beginning to see Ruby's "everything is an object" as a serious
barrier to comprehension, epsecially when this object-orientation is
dressed up in procedural syntax. Perl seems a lot more natural by
comparison.

gvim

If you like, you can rewrite all of the above as:

  x = x.+(1);
  y = y.<<("d");

Everything else is syntactic sugar.

Also, for the record, there's this: x += 1
Which expands out to: x = x.+(1)

--
Posted via http://www.ruby-forum.com/.

I'm beginning to see Ruby's "everything is an object" as a serious barrier

to comprehension, epsecially when this object-orientation is dressed up in
procedural syntax. Perl seems a lot more natural by comparison.

Ruby has a simpler model than Perl in this regard. It is easier in that
sense, but coming from Perl you need to adjust.

In Perl you have values (scalars, arrays, hashes, ...), and references to
values (which are in turn scalars). In Ruby you only have references.

That's the whole story.

In Ruby

    s = "foo"
    t = s

    s << 'bar'
    puts t

prints "foobar". Everything are references, s holds a reference to a
string, t hods the same reference, therefore in-place mutations are seen in
both of them.

···

On Wed, Nov 13, 2013 at 1:39 PM, gvim <gvimrc@gmail.com> wrote:

Quoting gvim (gvimrc@gmail.com):

I'm beginning to see Ruby's "everything is an object" as a serious
barrier to comprehension

barriers to comprehension are made to be overcome. A haiku may be this
one:

class Fixnum
  def +(v)
    self-v
  end
end

val=3
puts val # 3
val=val+1
puts val # what??

Carlo

···

Subject: Re: Passing script input as method args always global?
  Date: mer 13 nov 13 12:39:17 +0000

--
  * Se la Strada e la sua Virtu' non fossero state messe da parte,
* K * Carlo E. Prelz - fluido@fluido.as che bisogno ci sarebbe
  * di parlare tanto di amore e di rettitudine? (Chuang-Tzu)

So it seems args are passed by value after all ..... unless I'm mistaken

.... again.

Args are always passed by reference. When you pass in to doit, data
and inpoint to the same string object.

Without seeing what else goes on inside doit, it’s hard to offer insight on
the behavior you’re seeing.

···

On Tue, Nov 12, 2013 at 9:10 PM, gvim <gvimrc@gmail.com> wrote:

Gerald Vim wrote in post #1127104:

Make a copy of the argument when you call the method:

  doit(in.dup)

I seem to have misunderstood something. Changing 'data' within the
'doit' method does not seem to alter the 'in' variable even though it is
passed as an argument to the method. So it seems args are passed by
value after all ..... unless I'm mistaken .... again.

gvim

No, you were right to start with, ruby passes by reference. However,
Ruby often implements copy-and-modify (as opposed to destructive
modify-in-place) methods; as a general rule: if the method ends with an
exclamation mark ! it modifies the object in place, and if not, it
doesn't (except for some that do).

--- 8< ---
irb(main):001:0> foo = gets.chomp
Hello Matty!
=> "Hello Matty!"
irb(main):002:0> def doit(data) data.gsub!(/(.)\1+/){ $1 }; end
=> nil
irb(main):003:0> doit foo
=> "Helo Maty!"
irb(main):004:0> foo
=> "Helo Maty!"
--- >8 ---

Note how in the `doit' method I called gsub! (which modifies the
receiver in place), and not gsub (which creates a copy first).

There's also a difference between 'modifying the object' and 'updating
the variable to refer to a different object'. If I did:

  def doit(data)
    data = "The data is #{data}"
    #...
  end

that would be creating a new String object, then assigning that to the
variable called `data'. It would not be the same as modifying the
characters inside the original `data' String object.

···

On 13/11/2013 01:57, Eric Wong wrote:

--
Posted via http://www.ruby-forum.com/.

Then I don't get this one:

var = 2

def f(x)
   x = x + 1
   return x
end

puts f(var) #=> 3
puts var #=> 2

gvim

···

On 13/11/2013 02:23, Avdi Grimm wrote:

Args are always passed by reference. When you pass |in| to |doit|,
>data> and |in| point to the same string object.

Without seeing what else goes on inside |doit|, it’s hard to offer
insight on the behavior you’re seeing.

Ruby's beauty is looking increasingly skin-deep to me as I learn more.

gvim

···

On 13/11/2013 12:42, Matthew Kerwin wrote:

If you like, you can rewrite all of the above as:

   x = x.+(1);
   y = y.<<("d");

Everything else is syntactic sugar.

Also, for the record, there's this: x += 1
Which expands out to: x = x.+(1)

I get that but it sets up an expectation that this:

x =2

def f(y)
   y = y + 1
   puts y
end

f(x)

... will mutate x but I now understand, from what others have explained, that it doesn't. It's just counter-intuitive, that's all. This and the various rules about symbols as named arguments have led me to the conclusion that Ruby is an unnecessarily complicated language. Perl is much simpler.

gvim

···

On 13/11/2013 12:47, Xavier Noria wrote:

In Ruby

     s = "foo"
     t = s

     s << 'bar'
     puts t

prints "foobar". Everything are references, s holds a reference to a
string, t hods the same reference, therefore in-place mutations are seen
in both of them.

I'm sure there are many more contortions like this that Ruby facilitates but my months spent learning the language have led me to the conclusion that one can easily get lost in what's going on in the language under the surface. It's surface simplicity and elegance falls apart quite quickly in my experience.

gvim

···

On 13/11/2013 12:53, Carlo E. Prelz wrote:

barriers to comprehension are made to be overcome. A haiku may be this
one:

class Fixnum
   def +(v)
     self-v
   end
end

val=3
puts val # 3
val=val+1
puts val # what??

Carlo

Quoting gvim (gvimrc@gmail.com):

Ruby's beauty is looking increasingly skin-deep to me as I learn
more.

What is happening is that you resist change. What you lose seems to
you of greater value than what you gain.

Which might just as well be in your case. It is up to you to
decide whether to dedicate precious brain-space with Ruby.

Ruby's #1 beauty is for me that it allows you to become an intimate
friend of the OO paradigm without compromises, and with an almost
perfect clarity.

Carlo

···

Subject: Re: Passing script input as method args always global?
  Date: mer 13 nov 13 12:52:47 +0000

--
  * Se la Strada e la sua Virtu' non fossero state messe da parte,
* K * Carlo E. Prelz - fluido@fluido.as che bisogno ci sarebbe
  * di parlare tanto di amore e di rettitudine? (Chuang-Tzu)

... will mutate x but I now understand, from what others have explained,

that it doesn't. It's just counter-intuitive, that's all. This and the
various rules about symbols as named arguments have led me to the
conclusion that Ruby is an unnecessarily complicated language. Perl is much
simpler.

The conclusion you need to reach is that you do not understand pass by
value. You need to understand pass by value, is what the vast majority of
programming languages implement. Perl is the outlier here (not implying it
is worse, I love Perl, just to put things in perspective).

···

On Wed, Nov 13, 2013 at 1:57 PM, gvim <gvimrc@gmail.com> wrote:

Gerald Vim wrote in post #1127166:

I'm sure there are many more contortions like this that Ruby facilitates
but my months spent learning the language have led me to the conclusion
that one can easily get lost in what's going on in the language under
the surface. It's surface simplicity and elegance falls apart quite
quickly in my experience.

Well, Perl does the same unless explicitly told.

    sub f {
        my $y = shift;
        $y = $y + 1;
       return $y;
    }

    my $x = 2;
    print f($x), "\n"; # => 3
    print $x, "\n"; # => 2

Java, in contrast, does not know about pass by value and always does
pass by reference.

The most expressive would be C++ here:

    void f(float x);
    void f_with_sideeffect(float &x);

(And C++ allows to overload operators, too! Have fun with that...)

In general, you'd like to avoid side effects whenever possible.

···

--
Posted via http://www.ruby-forum.com/.