Converting Perl scripts to Ruby?

Is there some (semi)automatic way to attempt such a thing? Or does it
have sense at all?

···


Giuseppe “Oblomov” Bilotta

Axiom I of the Giuseppe Bilotta
theory of IT:
Anything is better than MS

Giuseppe Bilotta wrote:

Is there some (semi)automatic way to attempt such a thing? Or does it
have sense at all?

I converted some of my Perl scripts to Ruby and a first attempt which
was more of a transliteration (?) ended up looked like very bad Perl and
even worse Ruby.

Rewriting produced a much better Ruby program. Perl, as she is commonly
written, seperates the data from the logic whereas Ruby merges to two.

This in Perl

for(my $x = 0; $x < scalar(@accounts}; $x++) {
$accounts[$x]->interest = ($accounts[$x]->holding * $interestrate);
}

becomes

accounts.each {| account | account.interest(interestrate)}

Ok there are other ways of writting that loop in Perl but they all
introduce an unnecessary variable such as $x even if it is the implicit $_.

Perl tells you ‘what to do’ whereas Ruby tells you ‘what it is doing’.

A lot of the data that Perl holds externally or at least needs to access
externally (such as $accounts[$x]->holding) is made internal in Ruby and
stays there. Indeed interestrate could be a class variable but that
probably wouldn’t be how I’d do it.

When a program can convert the above Perl into the Ruby then we are all
out of a job.

Even good OO Perl tends to contain much ‘paperwork’ that Ruby handles
for you. You will never have to bless something again.

Besides code invariably gets better the more you rewrite it.

[ the points below are included to clarify
to Ruby users who may not know Perl. ]

Peter Hickman graced us by uttering:
[ snip ]

This in Perl

for(my $x = 0; $x < scalar(@accounts}; $x++) {
$accounts[$x]->interest =
($accounts[$x]->holding * $interestrate);
}

becomes

accounts.each {| account | account.interest(interestrate)}

Why haven’t you created a Perl object for this and defined an
#interest method for it as well?

Ok there are other ways of writting that loop in Perl but they
all introduce an unnecessary variable such as $x even if it is
the implicit $_.

I’m not sure what you’re gripe is here. Ruby’s iterators also
use an extra variable. That’s what appears between the ||'s.

But for the sake of accurate equivalents, let’s use idiomatic
Perl. You’ve neglected to show this much cleaner version:

foreach my $x (@accounts) {
    $x->interest = $x->holding * $interest_rate;
}

And using implicit use of $_:

foreach (@accounts) {
    $_->interest = $_->holding * $interest_rate;
}

or an OO version:

$_->interest($interest_rate) for @accounts;  # see [*]

At the end of all this, Ruby still looks (and works) cleaner than
any Perl example thus far.

[*] ‘for’ and ‘foreach’ are aliases for the same element. Thus,
you can write:

    foreach (my $i; $i < $max; $i++) { ... }

as well as:

    for my $x (@arr_of_stuff) { ... }

[ snip ]

Even good OO Perl tends to contain much ‘paperwork’ that Ruby
handles for you. You will never have to bless something again.

Very true. I can’t say this enough: Perl’s OO model is a
gigantic ball of bovine excrement, even if it does do some nifty
tricks. If the rest of Perl weren’t so useful, I’d have nothing
to do with it.

Correction: Perl5’s OO model sucks popsicles. I’m anxious to see
the improvements on it in Perl6 (as any change to Perl5’s OO
must be an improvement). =)

HTH
Tim Hammerquist

···


If someone stinks, view it as a reason to help them, not a reason to
avoid them.
– Larry Wall in 199702111730.JAA28598@wall.org

Tim Hammerquist wrote:

I’m not sure what you’re gripe is here. Ruby’s iterators also
use an extra variable. That’s what appears between the ||'s.

But for the sake of accurate equivalents, let’s use idiomatic
Perl. You’ve neglected to show this much cleaner version:

foreach my $x (@accounts) {
$x->interest = $x->holding * $interest_rate;
}

And using implicit use of $_:

foreach (@accounts) {
$->interest = $->holding * $interest_rate;
}

For some programmers (myself included) the creation of a surrogate
variable, the implicit $_ or the explicit $x, is a bad thing. It uses up
valuable name real estate and in all honesty only exists because the
language mandates you should have one. Idiomatic Perl is not the same as
idiomatic Ruby. In the Ruby the |account| local variable is not a
surrogate to dereference the account in question, it is the account.

I agree your Perl code is cleaner but I was just hacking something up to
show a point. Unfortunately there’s more Perl code like mine in the
world than there is like yours, mores the pity.

Very true. I can’t say this enough: Perl’s OO model is a
gigantic ball of bovine excrement, even if it does do some nifty
tricks. If the rest of Perl weren’t so useful, I’d have nothing
to do with it.

Perl OO reminds me of C++ written by seasoned C programmers. (mutters
something about old dogs and new tricks)

Peter Hickman graced us by uttering:

Tim Hammerquist wrote:

I’m not sure what you’re gripe is here. Ruby’s iterators also
use an extra variable. That’s what appears between the ||'s.

But for the sake of accurate equivalents, let’s use idiomatic
Perl. You’ve neglected to show this much cleaner version:

foreach my $x (@accounts) {
$x->interest = $x->holding * $interest_rate;
}

And using implicit use of $_:

foreach (@accounts) {
$->interest = $->holding * $interest_rate;
}

For some programmers (myself included) the creation of a
surrogate variable, the implicit $_ or the explicit $x, is a
bad thing. It uses up valuable name real estate and in all
honesty only exists because the language mandates you should
have one.

I’m not sure why you value name real estate so highly. Var names
aren’t like file descriptors. And with a language as robust as
Ruby, space used for variable names can’t possibly be the largest
drain on resources. Namespace real estate can’t be at that much
of a premium either, because in both the Ruby and Perl examples,
the variable goes out of scope as soon as the iteration finishes.

Whatever happens to |account| after:

accounts.each { |account| do_stuff }

finishes also happens to $account at the end of this Perl loop:

foreach my $account (@accounts) { do_stuff }

Idiomatic Perl is not the same as idiomatic Ruby. In the Ruby
the |account| local variable is not a surrogate to dereference
the account in question, it is the account.

How do you mean “surrogate”? And no, the idiomatic styles of
languages is not identical. Where ruby uses #each, perl uses a
foreach loop. But these are the idiomatic equivalents for the
same procedure.

ruby

accounts.each {| account | account.interest(interestrate)}

perl

$_->interest($interest_rate) for @accounts;

In this, $_ becomes the “alias” for each individual element of
@accounts. the ‘->’ notation is a method of accessing elements
in a perl object or reference; this makes each element of
@accounts an object reference, which is aliased to $_ at each
iteration.

However, suppose you had this:

my @arr = ("abc", "def", "ghi");
tr/a-z/A-Z/ for @arr;
print "@arr";
--> ABC DEF GHI

Whether you use the explicit $some_name or the implicit $_, any
changes made to the var are made directly to the element. This
is both very elegant, and very dangerous. If you want a harmless
copy of an element to play with, you must make it yourself.

I agree your Perl code is cleaner but I was just hacking
something up to show a point. Unfortunately there’s more Perl
code like mine in the world than there is like yours, mores the
pity.

Yes, there are quite a few “perl hackers” entirely unfamiliar to
idiomatic perl. This is what gives perl a bad name: perl
programs written in C.

Very true. I can’t say this enough: Perl’s OO model is a
gigantic ball of bovine excrement, even if it does do some
nifty tricks. If the rest of Perl weren’t so useful, I’d have
nothing to do with it.

Perl OO reminds me of C++ written by seasoned C programmers.
(mutters something about old dogs and new tricks)

Yes, C really doesn’t translate well into many other languages.
See above. :wink:

[f-up2 poster]
Tim Hammerquist

···


Windows 98 is NOT a virus - viruses are small and efficient.

Tim Hammerquist wrote:

I’m not sure why you value name real estate so highly. Var names
aren’t like file descriptors. And with a language as robust as
Ruby, space used for variable names can’t possibly be the largest
drain on resources. Namespace real estate can’t be at that much
of a premium either, because in both the Ruby and Perl examples,
the variable goes out of scope as soon as the iteration finishes.

It’s not something as esoteric as namespaces but just the use of
meaningful variable names within code. A lot of the code I come across
might use $x as a loop variable, and then $y (we are talking Perl here
obviously) to hold some intermediate variable. Then a loop appears
inside the first loop with $z and $xx. Before you know it you have many
variables with pointless names that actually do nothing usefull. It is
not that $x is a bad variable name because if you have $loop_counter,
$another_loop_counter, $loop_counter2 and $yet_another_loop_counter you
are really none the wiser.

If a variable exists then it must be named and in my experiance
programmers (myself included) can be very bad at giving meaningful names
to variables especially in code that evolves over time. Then it was just
a single loop then $x was a reasonable variable name, but after a year
or so then $x is meaningless as several loops have been added to the
code. The less variables you have to name the greater the chance of
giving them a meaningfull name.

How do you mean “surrogate”? And no, the idiomatic styles of
languages is not identical. Where ruby uses #each, perl uses a
foreach loop. But these are the idiomatic equivalents for the
same procedure.

A surrogate variable represents nothing by itself but is required to
write the code. For example in basic.

FOR x = 1 TO 10
PRINT “Hello world”
NEXT x

All you want is a loop that runs 10 times but you are forced to create
and name a variable you have no use for. Whereas in Ruby we have

(10).times { puts “Hello world\n” }

No surrogate variable.

Also to swap 2 variables $a and $b.

$c = $a;
$a = $b;
$b = $c;

$c is a surrogate and exists just to facilitate the code.

($a, $b) = ($b, $a)

No surrogate variable.

When you debug or upgrade code you have to take into account every
variable so it helps if the code contains the least number of variables
that it can. With throwaway variables like $c you may find that because
the swap no longer needs it the programmer then reuses it in a longer
term context later in the code and we have a variable suffering multiple
personality disorder.

“Ah yes $x is a loop counter (twice), the total income tax to date and
the id of the highest paid salesman this month”.

It’s a whole world of pain.

Peter Hickman graced us by uttering:

Tim Hammerquist wrote:

How do you mean “surrogate”? And no, the idiomatic styles of
languages is not identical. Where ruby uses #each, perl uses
a foreach loop. But these are the idiomatic equivalents
for the same procedure.

A surrogate variable represents nothing by itself but is
required to write the code. For example in basic.

FOR x = 1 TO 10
PRINT “Hello world”
NEXT x

All you want is a loop that runs 10 times but you are forced to
create and name a variable you have no use for. Whereas in Ruby
we have

(10).times { puts “Hello world\n” }

No surrogate variable.

Also to swap 2 variables $a and $b.

$c = $a;
$a = $b;
$b = $c;

$c is a surrogate and exists just to facilitate the code.

($a, $b) = ($b, $a)

No surrogate variable.

Thank you for explaining. I think I understand what you mean
now. No, I suppose Perl doesn’t have any way to truly perform
anything 10 times without a “surrogate” var. The closest I can
get off the top of my head is:

foreach (1..10) { do_something }

Yes, it sets the implicit $_, but even Ruby’s “(10).times”
creates an anonymous Fixnum.

The biggest waste in the above code is that it creates a
temporary anonymous list of 10 actual integers over which to
iterate, all of which are tossed away, their value never actually
processed.

So, in the end, we still haven’t saved your surrogate var from
existence ($), though even Ruby sets $ transparently with every
call to File::gets. We have, however, saved “valuable name real
estate”.

Like I said, I also believe Ruby to be superior. I just don’t
like making the case using contrived Perl code that uses even
more “surrogate” vars than are necessary.

IOW, when comparing code of different languages, at least compare
good code from each language. :slight_smile:

When you debug or upgrade code you have to take into account
every variable so it helps if the code contains the least
number of variables that it can. With throwaway variables like
$c you may find that because the swap no longer needs it the
programmer then reuses it in a longer term context later in the
code and we have a variable suffering multiple personality
disorder.

Should I deduce from this that you never use the $_ var in Ruby?
In all honestly, I use it very little myself, even with my Perl
background.

“Ah yes $x is a loop counter (twice), the total income tax to
date and the id of the highest paid salesman this month”.

With a name like $x, I’d hope that it were an entirely local and
throw-away var in each context. This is, of course, wishful
thinking in most cases. :wink:

It’s a whole world of pain.

…when people don’t know their own language. :wink:

Cheers!
Tim Hammerquist

···


Usenet is essentially a HUGE group of people passing notes in class.
– R. Kadel

That turns out not to be the case. Constant ranges or lone arrays in
a foreach generate an iterator, so there’s no temporary list. There’s
code to make the ‘fake’ values in the constant range iterator real if
you reference them in ways that would require them persist outside
the foreach block.

···

At 6:23 PM +0900 8/28/02, Tim Hammerquist wrote:

Thank you for explaining. I think I understand what you mean
now. No, I suppose Perl doesn’t have any way to truly perform
anything 10 times without a “surrogate” var. The closest I can
get off the top of my head is:

foreach (1..10) { do_something }

Yes, it sets the implicit $_, but even Ruby’s “(10).times”
creates an anonymous Fixnum.

The biggest waste in the above code is that it creates a
temporary anonymous list of 10 actual integers over which to
iterate, all of which are tossed away, their value never actually
processed.


Dan

--------------------------------------“it’s like this”-------------------
Dan Sugalski even samurai
dan@sidhe.org have teddy bears and even
teddy bears get drunk

Dan Sugalski graced us by uttering:

foreach (1..10) { do_something }

[ snip ]

The biggest waste in the above code is that it creates a
temporary anonymous list of 10 actual integers over which to
iterate, all of which are tossed away, their value never
actually processed.

That turns out not to be the case. Constant ranges or lone
arrays in a foreach generate an iterator, so there’s no
temporary list. There’s code to make the ‘fake’ values in the
constant range iterator real if you reference them in ways that
would require them persist outside the foreach block.

Yet Another Perl Optimization… Cool. Thanks. :slight_smile:

Tim Hammerquist

···

At 6:23 PM +0900 8/28/02, Tim Hammerquist wrote:

As a computer, I find your faith in technology amusing.