Ex-Perl coders: Howz it feel to convert to Ruby?

N

Nate Smith

Under which circumstances do you need to_s for numbers? What's wrong with
this?

1
=> nil
1
=> nil
foo 1 bar
=> nil

Try

print "a" + 1

Won't work -- you have to do

print "a" + 1.to_s


Nate
 
J

James Edward Gray II

Newsbeitrag


Under which circumstances do you need to_s for numbers? What's wrong
with
this?

It's usually when I'm doing something like:

puts "Total: " + 12345

James Edward Gray II
 
C

Chris

Michael said:
I don't need convincing, but I'd be interested in seeing the equivalent Perl
code just for the sake of comparison. I find it educational to see how
different languages approach a problem.

I actually wrote it anyway right after I posted the message above, just
to see what the difference would be:

#!/usr/bin/perl

package Foo;

use strict;
use warnings qw( all );

sub new {

my $class = shift;
my $self = {};

$self->{__bar} = shift || 'bar';
$self->{__boat} = shift || 'boat';

bless $self, $class;

}

sub bar { $_[0]->{__bar} }
sub boat { $_[0]->{__boat} }
sub concat { $_[0]->{__bar} . $_[0]->{__boat} }

package main;

use strict;
use warnings qw( all );

my $foo = Foo->new( @ARGV );

puts(
$foo->concat(),
$foo->bar(),
$foo->boat(),
);

sub puts { for (@_) { print "$_\n" } }

__END__

The accessors could be handled by AUTOLOAD, but I doubt it would have
shortened the code that much. This is written with two packages
(namespaces) in one file, which IMO more closely mirrors the equiv. Ruby
code, but isn't as common in the Perl world (in my experience anyway).

-ceo
 
A

Austin Ziegler

It's usually when I'm doing something like:

puts "Total: " + 12345

You're really better off using interpolation there:

@total = 12345
puts "Total: #{@total}"

Now, you don't have to know whether @total is a Fixnum, String, Float,
or even a hypothetical Money class.

-austin
 
J

James Edward Gray II

I don't need convincing, but I'd be interested in seeing the
equivalent Perl
code just for the sake of comparison. I find it educational to see how
different languages approach a problem.

#!/usr/bin/perl

use strict;
use warnings;

package Foo;

sub new {
my $class = shift;
my %object = ( bar => "default",
boat => "values",
@_ );

return bless \%object, $class;
}

sub bar { return shift->{bar}; }

sub boat { return shift->{boat}; }

sub concat {
my $self = shift;

return $self->{bar} . $self->{boat};
}

package main;

my $foo = Foo->new(bar => "bar", boat => "boat");
print $foo->concat, "\n";
print $foo->bar, "\n";
print $foo->boat, "\n";

# minor example of code difference
$foo->{bar} = "Not Private!";
print "\n", $foo->bar, "\n";

__END__

Hope that helps.

James Edward Gray II
 
J

James Edward Gray II

You're really better off using interpolation there:

@total = 12345
puts "Total: #{@total}"

Now, you don't have to know whether @total is a Fixnum, String, Float,
or even a hypothetical Money class.

An excellent point. Thanks for the tip.

James Edward Gray II

P.S. As I said in the original post, most of my issues probably come
from my lack of familiarity.
 
R

Robert Klemme

Nate Smith said:
Try

print "a" + 1

Won't work -- you have to do

print "a" + 1.to_s

I prefer to use #{} in those cases (see above, no. 3). Gives you more
control.

Of course, your example can be written much easier:

print "a", 1

Kind regards

robert
 
A

Andrew Johnson

I actually wrote it anyway right after I posted the message above, just
to see what the difference would be:

Alternatively (tmtowtdi and all that ...):

#!/usr/bin/perl -w
use strict;

my $foo = Foo->new('the');
print $foo->concat, "\n";
$foo->bar = 'Das';
$foo->boat = 'Boot';
print $foo->concat, "\n";

{
package Foo;
my(%bar, %boat);
sub new {
my $self = bless {}, shift;
$self->$_ = shift || $_ for ('bar','boat');
$self;
}
sub bar : lvalue { $bar {$_[0]}}
sub boat : lvalue { $boat {$_[0]}}
sub concat { $_[0]->bar . $_[0]->boat }
}
__END__

regards,
andrew
 
J

James F. Hranicky

So I'm looking for feedback from those that have converted, esp. from a
hardcore Perl perspective.

Recently it dawned on me that one of the reasons I like Ruby so much is
method chaning. Why? At first, I thought it was because the program
flow went left to right, just like reading. But then it occurred to me
that being able to do something like this:

`ypcat -k amd_cise`.map { |line|
line.match(/rhost:=([^;]+)/).captures[0] rescue next
}.compact.sort.uniq.each { |server|
...

is just like using Unix pipes. When I used perl, and I needed to process
the output of a command like the above, I would generally do all the
work with a regular Unix pipeline. With ruby, the processing is very
similar already. You have to do a little more work, like catching
exceptions and things like nil elements, but the program flow is so
natural there's no need to exec the extra programs.

I recently tried hacking on some Perl (I've written thousands of lines
over the years), and I can barely even remember what to do, which is
fine, really :->

Jim
 
R

Robert Klemme

James F. Hranicky said:
So I'm looking for feedback from those that have converted, esp. from a
hardcore Perl perspective.

Recently it dawned on me that one of the reasons I like Ruby so much is
method chaning. Why? At first, I thought it was because the program
flow went left to right, just like reading. But then it occurred to me
that being able to do something like this:

`ypcat -k amd_cise`.map { |line|
line.match(/rhost:=([^;]+)/).captures[0] rescue next
}.compact.sort.uniq.each { |server|
...

is just like using Unix pipes. When I used perl, and I needed to process
the output of a command like the above, I would generally do all the
work with a regular Unix pipeline. With ruby, the processing is very
similar already. You have to do a little more work, like catching
exceptions and things like nil elements, but the program flow is so
natural there's no need to exec the extra programs.

The only caveat here being to remember that typically with method chaining
you build up one collection before the next step starts; in cases of mass
data this can be rather impractical, whereas pipes only need limited temp
storage (sort and other programs that need to see the whole input are an
exception here).

But otherwise: yes, well observed!
I recently tried hacking on some Perl (I've written thousands of lines
over the years), and I can barely even remember what to do, which is
fine, really :->

:)

robert
 
K

Karl von Laudermann

Robert Klemme said:
Under which circumstances do you need to_s for numbers?

I can't speak for James, but coming from Java I'm used to using the
concatenation operator, like so:

print "foo" + 1;

This causes an error; you have to call to_s on the number. I find it
unintuitive that specifying multible arguments to the print method is
a way of concatenating them, so I rarely think to use it. I also find
it unintuitive that you don't have to call to_s when passing a
non-string argument by itself, but you do when concatenating. Perhaps
String#+ should be modified to call to_s on its arguments?

BTW, one actual benefit of using concatenation vs. multiple arguments
is that you can use puts instead of print to get a "\n" for free at
the end, but not in between each component of your string.
 
C

Chris

Andrew said:
I actually wrote it anyway right after I posted the message above, just
to see what the difference would be:


Alternatively (tmtowtdi and all that ...):

#!/usr/bin/perl -w
use strict;

my $foo = Foo->new('the');
print $foo->concat, "\n";
$foo->bar = 'Das';
$foo->boat = 'Boot';
print $foo->concat, "\n";

{
package Foo;
my(%bar, %boat);
sub new {
my $self = bless {}, shift;
$self->$_ = shift || $_ for ('bar','boat');
$self;
}
sub bar : lvalue { $bar {$_[0]}}
sub boat : lvalue { $boat {$_[0]}}
sub concat { $_[0]->bar . $_[0]->boat }
}
__END__

regards,
andrew

Oooooo... Aaaaaah...! lvalues... You don't see folks using them very
much. I don't use them much myself.

-ceo
 
M

Martin DeMello

ChrisO said:
More "Wow!" You can't do this in Perl (unless you call in another CPAN
module to pick apart another module. Hardly compariable.)

Another useful trick is to do Array.methods - Object.methods (array
subtraction - gotta love it); that removes all the common methods Array
inherited from Object.

martin
 
P

Phil Tomson

Hi --



There's nothing wrong with doing this the way Phil has, but there's
also nothing wrong or undisciplined about using yield. Let's not
stigmatize people who use yield (for example, Matz and many of the
other authors of the Ruby standard library) as undisciplined. It's
not a test of character; it's a programming idiom. You can work
around it if you don't like it, as Phil has shown, or you can use it,
as others have shown, in the course of writing perfectly good and
clear code.
When you supply a block to a method, you need to know how the block is
going to be called -- which means you'll probably either have written
the method yourself, or consulted some documentation that explains how
the method works. So in practical terms, the use of yield vs. calling
the block explicitly probably doesn't matter too much too often. You
can use whichever semantics you like.

I agree totally. I did not intend to stigmatize people for using 'yield'.
In fact, I tend to use 'yield' as often as the alternative. I think I
sometimes prefer yield because even though it tends to make the arguments
to the method somewhat ambiguous, the intent can sometimes seem clearer in
the body of the method (vs the 'call').


Phil
 
D

David A. Black

Hi --

I agree totally. I did not intend to stigmatize people for using 'yield'.
In fact, I tend to use 'yield' as often as the alternative. I think I
sometimes prefer yield because even though it tends to make the arguments
to the method somewhat ambiguous, the intent can sometimes seem clearer in
the body of the method (vs the 'call').

I was referring mainly to Chris's characterization of yield users as
different from people who write disciplined, well-constructed code. I
suspect that Chris didn't really mean it as a slam to yield users
either, but it kind of read that way. (And I'm at least a frequent
yield user myself :)


David
 
M

Markus

Is there any way to change an outside-scoped object inside a proc? Such
as:

a = "Foo"
b = "bar"
proc = Proc.new { |val1, val2| val1, val2 = "boo", "baz" }
proc.call( a, b )

# a and b are still "Foo" and "bar"

I don't believe this is possible.. but would be very nice for creating a
collect! method for a user-defined object. Thanks

I suspect you are right (that it isn't possible), at least without
going through some rather extreme contortions. Over all, I'm _glad_
that this is the case (though I must admit I've past parameters in "var"
with wild abandon in other languages).

Why do you think this is needed (or nice) for writing a collect!
method? Why cant you just write something like:

class My_collection_class
def [](k)
:
end
def []=(k,v)
:
end
def each_key
:
end
def collect!
each_key { |k| self[k] = yield(self[k]) }
end
end

-- MarkusQ
 
M

Mauricio Fernández

I was referring mainly to Chris's characterization of yield users as
different from people who write disciplined, well-constructed code. I
suspect that Chris didn't really mean it as a slam to yield users
either, but it kind of read that way. (And I'm at least a frequent
yield user myself :)

And you can be "disciplined" by Chris' criteria while using yield:

def foo(arg, &block)
yield
end
 
L

Lennon Day-Reynolds

Nate,

You have to use mutable objects. Variables in Ruby, whether in blocks
or elsewhere, are references, not pointers. If you reassign a
variable, you're just changing which object it refers to, rather than
updating the value of a memory location.

Luckily, Ruby strings are mutable, so at least for your example, you
could do the following:

a = "Foo"
b = "Bar"
myproc = Proc.new {|val1, val2| # note: I try to avoid shadowing a
built-in like 'proc'
val1[1..-1] = "boo" # with a variable name
val2[1..-1] = "baz"
}
proc.call(a, b)

It might be interesting to define something like Common Lisp's 'setf'
function, which is a sort of generic setter. So, mutable objects like
strings, arrays, hashes, etc., could all support a 'value=' or
'replace' method which would make them destructively update their
value.
 
C

Chris

David said:
Hi --




I was referring mainly to Chris's characterization of yield users as
different from people who write disciplined, well-constructed code. I
suspect that Chris didn't really mean it as a slam to yield users
either, but it kind of read that way. (And I'm at least a frequent
yield user myself :)

Yeah, my rhetoric kinda made it sound that way. I'm not in a position
yet to critique Ruby coding technique. But I do see a lot of
undisciplined use of Perl syntax, and that was my main point. I just
carried it over a little too far. Phil's point that the foo.call method
*may* make things stand out a little better is still a noteworthy point
however. But I don't think he was saying 'yield' was undisciplined coding.

-ceo
 
L

Lennon Day-Reynolds

This only works as long as the variables and block params have the
same name. If you want to be able to pass the variables to be updated
to proc, as the original poster requested, then it won't work.

It is a great way to really confuse the hell out of someone reading
your code, though; the variable/parameter scoping issues surrounding
blocks are one of the few things I really consider to be a "wart" in
the core Ruby language.
 

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,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top