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

B

Bill Guindon

This is where I'm looking to get with Ruby and I still reach for Perl
because I don't know Ruby as well. It happened today at work. I needed
to extract some server names from a piece of Perl code (text) that
looked like this:

{ SERVER => "servername1", SHARE = $Default },
{ SERVER => "servername2", SHARE = $Default },
{ SERVER => "servername3", SHARE = $Default },
{ SERVER => "servername4", SHARE = $Default },
{ SERVER => "servername5", SHARE = $Default },
{ SERVER => "servername6", SHARE = $Default },
{ SERVER => "servername7", SHARE = $Default },
{ SERVER => "servername8", SHARE = $Default },

(The server names were more unique than the contrived names above.) In
Perl it was:

perl -e 'while (<>) { /"(\w*)"/; print "$1\n" }' file-snippet.txt

In Ruby? I didn't have the time to figure it out. Which is the
agonizing point. Later, I did the following in Ruby to satisfactory effect:

ruby -e 'ARGF.each { |line| line.scan( /"(\w*)"/ ) { |frag| puts frag }
}' file-snippet.txt

Perhaps someone can refine this while we're at it. It's hard not to
notice that the Perl was more concise. Perhaps my ignorance can be made
right...? Can this be shortened in Ruby? Surely...

ruby -e 'puts ARGF.grep(/"(\w*)"/) {$1}' file-snippet.txt

I'd bet it could be shorter still, but It's all new to me too :)
 
P

Phil Tomson

An incredibly interesting point of view though your justification for it
is somewhat understandable. Pathological mistakes can occur this way
for those that use this, what I would call an incredibly nice feature,
in an undisciplined way. I'm quite disciplined about spiking out my
arguments in Perl at the top of a subroutine.

Did you do this in comments? In my faint recollections of Perl I seem to
recall that there was a way to declare the sub with it's params - but most
people didn't do this (or perhaps my memory is incorrect).
I think your dislike
perhaps has been fueled by people that write subroutines in a "hackish"
sort of way. (I would imagine "hacking" Ruby is just as possible to
accomplish.)


But aside from the undisciplined uses you've pointed out as reason for
eshewing this in Perl, I have to wholy stand by the amazing power this
feature brings. It far outweighs the negatives. It's one of the
"genius" things about Perl. (Always educational, however, to get
someone else's opposite point of view, as you have offered.)

Essentially what you're trying to get is to be able to pass in a variable
number of arguments to a method (err, function in Perlese). Ruby lets
you do that like so:

def foo(*args)

At least in this case you can tell at a glance that foo can take a
variable number of arguments.

In perl you could have:

sub foo {

for(@_) {... do whatever...}

}


In the case of Perl, I've got to actually go and read the body of the
function to know that it can take multiple arguments. I don't like it.

The other thing I don't like about it is that it means that argument
handling in Perl is a do-it-yourself project (like OO Perl)

And to bring this Perl discussion back on topic, in line with your
dislike of this "feature" in Perl, am I not correct in understanding
that in Ruby, one can create methods on the fly in a class? How is this
that much different (conceptually) than unspecified parameters in a Perl
subroutine?

It could present similar problems, however, creating methods on the fly,
while possible, it's relatively unusual compared to what we're talking
about in Perl. Every sub in Perl requires that I read the body of the sub
to determine what the args are and how many. I would also contend that
the 'problem' of creating methods on the fly is not as big because what is
happening is that you're getting some new feature (a new method) created
on the fly (or perhaps you're overriding an old one) that you may not be
aware of - not knowing about a new method won't break anything because
you probably won't call what you don't know about. ;-)
How do you know what methods are there (aside from using
the inspection methods available to every class [unless I am mistaken in
this regard]).

I'll give you a better example for your the point you're trying to make: yield.

In Ruby you can have:


def foo
#...
yield
#...
end

Now there is no indication from looking at the method definition line (the
'def foo' part) that any argument is passed to this method, yet it
requires that a block be passed to it, like so:

foo { puts "Boo!" }

So, it's a bit like the problem I'm talking about with Perl, except that
in practice it's not as bad because usually there is only one yield in a
method - but it can be an issue. That's why it's probably better to do:

def foo(&b)
#...
b.call
#...
end

Because it provides the reader of the code with a clear indication that
the method takes a block. Also, it's usually a good idea if you do use
yield to also call 'block_given?' prior to yielding.


Phil
 
J

James Edward Gray II

Did you do this in comments? In my faint recollections of Perl I seem
to
recall that there was a way to declare the sub with it's params - but
most
people didn't do this (or perhaps my memory is incorrect).

This solid reasoning for this aversion. Prototypes are more than a
little flawed in Perl. They aren't even checked on a method call,
which seriously degrades their usefulness. There are other issues, but
that was the biggie, for me anyway.

James Edward Gray II
 
M

Marcel Molina Jr.

Phil said:
Dick Davies said:
* Phil Tomson <[email protected]> [0909 19:09]:


.... You know all of the methods that will operate on a particular
object of a certain class (or you can easily find out) and there were
more methods available on builtin classes (for example, look at all of
the methods available on Array objects and compare with functions
available in Perl to operate on @list objects).

That's something that shouldn't be overlooked -

when I went back to perldoc after maybe 9 months away from Perl I had
major problebs remembering the right function to do a particular bit
of manipulation on a Hash. perldoc -f isn't much use without a method
name,
and even Google is only useful if can say what you want :)

With Ruby it was just 'ri Hash;ri Enumerable' to see all the methods
that worked on a Hash.


Or in irb:
Array.methods.sort
=> ["&", "*", "+", "-", "<<", "<=>", "==", "===", "=~", "[]", "[]=",
"__id__", "__send__", "all?", "any?", "assoc", "at", "class", "clear",
"clone", "collect", "collect!", "compact", "compact!", "concat", "delete",
"delete_at", "delete_if", "detect", "display", "dup", "each",
"each_index", "each_with_index", "empty?", "entries", "eql?", "equal?",
"extend", "fetch", "fill", "find", "find_all", "first", "flatten",
"flatten!", "freeze", "frozen?", "grep", "hash", "id", "include?",
"index", "indexes", "indices", "inject", "insert", "inspect",
"instance_eval", "instance_of?", "instance_variable_get",
"instance_variable_set", "instance_variables", "is_a?", "join",
"kind_of?", "last", "length", "map", "map!", "max", "member?", "method",
"methods", "min", "nil?", "nitems", "object_id", "pack", "partition",
"pop", "private_methods", "protected_methods", "public_methods", "push",
"rassoc", "reject", "reject!", "replace", "respond_to?", "reverse",
"reverse!", "reverse_each", "rindex", "select", "send", "shift",
"singleton_methods", "size", "slice", "slice!", "sort", "sort!",
"sort_by", "taint", "tainted?", "to_a", "to_ary", "to_s", "transpose",
"type", "uniq", "uniq!", "unshift", "untaint", "values_at", "zip", "|"]

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

I becoming quite glad I've started this discussion. I'm thinking I'm
just about taken in with this. Beautiful.

also if your .irbrc includes "require 'irb/completion'" you can tab
complete methods:

e.g..scan .sort .sub
.select .sort_by .sub!
.send .split .succ
.singleton_methods .squeeze .succ!
.size .squeeze! .sum
.slice .strip .swapcase
.slice! .strip! .swapcase!=> 1492

marcel
 
C

ChrisO

Phil said:
Did you do this in comments? In my faint recollections of Perl I seem to
recall that there was a way to declare the sub with it's params - but most
people didn't do this (or perhaps my memory is incorrect).

No, I usually spike them out at the top of the subroutine. Like this:

sub foo {

## Get parameters.

my $bar = shift; ## Comment variable use here
my $boat = shift; ## Same here

## Return bar and boat concat'd.

"$bar$boat";

}

In general, that's how ALL my Perl subroutines look. It IS a
disciplined approach and I guess I have to say that by doing so I am
implying some rightness in other people's comments here because I
dislike the same loosy-goosy approach in what I call "trash code" that
other people write in Perl. You look at their Perl code, and you can't
make hide nor hair of it without sitting down, marking out variables,
etc. as some have stated.

I guess I'm willing to live with the power at the expense of the
potential for a mess, but it can get messy when it ends up that there
are 50 ways to "pass" the variable(s) in. Some of which I dislike
immensely myself such as this approach:

sub foo {

my( $bar, $boat ) = @_;
"$bar$boat";

}

Still, sometimes those different approaches make sense. In OO modules,
I've been known to do, assuming foo is a method I am defining in an OO
module, the following:

sub foo { "$_[0]$_[1]" }

When I see that, because of all the Perl coding I've done, I know
IMMEDIATELY what's going on. It appears, to my surprise in this NG
(though I'd never really thought about it much until now) that some
people don't like this.

Generally, just because of the way I am "wired" if a language is
somewhat regimented, I like that and can go with it (I recall earlier
days in Pascal, and I considered C somewhat that way as well), and if
the language is "loosy goosy" like Perl, I super-impose my own
regimented, methodical way of coding. I think mainly because I've found
that consistency in approach (to the nth detail) leads to robustness and
maintainability. And how much time does it take to spike out my
variables as I demo'd above versus just slapping them around somewhere
in the body of the subroutine? Or indenting consistently throughout,
etc.? It doesn't take much, and yet there are A LOT of people that
don't, so the comments here have some merit, I do admit.

Incidentally, perhaps the thing you are referring to in Perl, denoting
parameters is the following notation:

sub foo($$) {

## Body of subroutine here.

}

This denotes two parameters are intended. I'm not overly familiar with
this, and I don't use it. It still doesn't spike out parameters as you
all here are advocating.
Essentially what you're trying to get is to be able to pass in a variable
number of arguments to a method (err, function in Perlese). Ruby lets
you do that like so:

def foo(*args)

At least in this case you can tell at a glance that foo can take a
variable number of arguments.

In perl you could have:

sub foo {

for(@_) {... do whatever...}

}


In the case of Perl, I've got to actually go and read the body of the
function to know that it can take multiple arguments. I don't like it.

But the Perl construct you have above is powerful in certain situations
just as you indicate later here concerning Ruby and the block/yield
methodology. Only in Ruby you have the ability to make it more readable
with the foo.call method as you pointed out. But in Perl, the following
is extremely powerful used in the right context:

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

Because the intent is to use all parameters passed until all have been
iterated over. Unfortunately, that same @_ notation can be used in ways
I don't like too. So, I guess I have to say, I do understand somewhat.
The other thing I don't like about it is that it means that argument
handling in Perl is a do-it-yourself project (like OO Perl)

<Sigh> Yep. Which is one of the reasons Ruby is appealing to me. It's
A LOT OF STINKING WORK to create even the simplest Perl OO module, I
have to admit. Versus:

class Foo
attr_reader :bar, :boat

def initialize( bar, boat )
@bar, @boat = bar, boat
end

def concat
@bar + @boat
end
end

foo = Foo.new
p foo.concat
p foo.bar
p foo.boat

Wow. And you have accessors and everything right there. In Perl, the
above is easily 10-20 lines of code and the less lines, the more
ambigious it would be. The above Ruby is just plain nice.
It could present similar problems, however, creating methods on the fly,
while possible, it's relatively unusual compared to what we're talking
about in Perl. Every sub in Perl requires that I read the body of the sub
to determine what the args are and how many. I would also contend that
the 'problem' of creating methods on the fly is not as big because what is
happening is that you're getting some new feature (a new method) created
on the fly (or perhaps you're overriding an old one) that you may not be
aware of - not knowing about a new method won't break anything because
you probably won't call what you don't know about. ;-)

OK, my question was from the vantage of not knowing for sure, so this
explains that wonderment.
How do you know what methods are there (aside from using
the inspection methods available to every class [unless I am mistaken in
this regard]).


I'll give you a better example for your the point you're trying to make: yield.

In Ruby you can have:


def foo
#...
yield
#...
end

Now there is no indication from looking at the method definition line (the
'def foo' part) that any argument is passed to this method, yet it
requires that a block be passed to it, like so:

foo { puts "Boo!" }

So, it's a bit like the problem I'm talking about with Perl, except that
in practice it's not as bad because usually there is only one yield in a
method - but it can be an issue. That's why it's probably better to do:

def foo(&b)
#...
b.call
#...
end

Because it provides the reader of the code with a clear indication that
the method takes a block. Also, it's usually a good idea if you do use
yield to also call 'block_given?' prior to yielding.

Yes, this is a better example of what I was talking about, and yes, you
can provide better indication here in Ruby than in Perl, I have to
admit. So, to see the parallels, I'll bet you see a lot more of the
simple yields in block handling method definitions in classes than you
do in the form of you second example with the spiked out parameter and
the param.call approach. It's disciplined, well constructed code, but
not everyone is like that. Hence the Perl dilemma/diatribe here.

-ceo
 
C

ChrisO

Joel said:
Golf.shoes = "on"

$ ruby -n -e 'puts $1 if /"(\w+)"/' file-snippet.txt
servername1
servername2
servername3
servername4
servername5
servername6
servername7
servername8

Wow. So tonight I learn about the -n switch. Nice. And I didn't think
the $1 would be available as in Perl. So it's good to know that's in
Ruby too. Sweet.

-ceo
 
C

ChrisO

Gavin said:
In that case, I suggest you simply read Pickaxe II for pleasure. It's
a good survey of how to accomplish things in Ruby, and the available
libraries to help you.

By the time you finish, you'll have enjoyed thinking differently and
picked up enough Ruby idioms to know what's going on.

I'll look for it. This thread has been a load of fun and more than
helped me get the perspective I was looking for.

-ceo
 
C

ChrisO

ChrisO said:
<Sigh> Yep. Which is one of the reasons Ruby is appealing to me. It's
A LOT OF STINKING WORK to create even the simplest Perl OO module, I
have to admit. Versus:

class Foo
attr_reader :bar, :boat

def initialize( bar, boat )
@bar, @boat = bar, boat
end

def concat
@bar + @boat
end
end

foo = Foo.new
p foo.concat
p foo.bar
p foo.boat

Wow. And you have accessors and everything right there. In Perl, the
above is easily 10-20 lines of code and the less lines, the more
ambigious it would be. The above Ruby is just plain nice.

Should have been:

foo = Foo.new( "bar", "boat" )

Foo.initialize expects args passed. They were not spiked out with
defaults. As in:

def initialize( bar="bar", boat="boat" )
@bar, @boat = bar, boat
end

I'm tempted to type in the required Perl equivalent code here for the
Foo class above for contrast, only no one here needs convincing. I'm
still shaking my head. I'm certainly pretty much convinced.

-ceo
 
G

Gavin Sinclair

Chris said:
<Sigh> Yep. Which is one of the reasons Ruby is appealing to me. It's
A LOT OF STINKING WORK to create even the simplest Perl OO module, I
have to admit. Versus:

class Foo
attr_reader :bar, :boat

def initialize( bar, boat )
@bar, @boat = bar, boat
end

def concat
@bar + @boat
end
end

foo = Foo.new
p foo.concat
p foo.bar
p foo.boat

Wow. And you have accessors and everything right there. In Perl, the
above is easily 10-20 lines of code and the less lines, the more
ambigious it would be. The above Ruby is just plain nice.


Damn right. It's amazing how after years of programming the simple things
still take ages to properly sink in. I needed a counter for several
indices a few days ago. I only needed it in one place. Instead of using
a hash and managing all the logic inline (where lots of other logic was
taking place), a simple class worked wonders.

#
# Maintains a bunch of indexed counters.
#
# counter = Counter.new
# counter.next('x') # -> 1
# counter.next('y') # -> 1
# counter.next('x') # -> 2
# counter.next('z') # -> 1
# counter.next('y') # -> 2
# counter.next('x') # -> 3
#
class Counter
def initialize
@counters = {}
end

def next(idx)
@counters[idx] ||= 0
@counters[idx] += 1
end
end

My favourite refactoring pattern at the moment is to move all the related
private methods of a class into their own class. It helps to clarify the
real responsibility of the original class, to highlight the relationship
between them, and to test the supporting code more easily. (The difficult
part is thinking of a name for the new class.)

To do all this, you need a language where creating new classes is easy and
intuitive. Having a language that's ball-tearingly powerful doesn't hurt,
either.

Cheers,
Gavin
 
M

Michael Geary

ChrisO said:
I'm tempted to type in the required Perl equivalent code here
for the Foo class above for contrast, only no one here needs
convincing. I'm still shaking my head. I'm certainly pretty
much convinced.

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.

Thanks,

-Mike
 
J

Joel VanderWerf

Gavin said:
$ ruby -ne 'puts $1 if /"(\w+)"/' file-snippet.txt

Easiest game of golf I ever played :)

Heh. I bogied by splitting up the -ne. Was that a "hole in -ne"?

(And that's enough from me tonight!)
 
J

Joel VanderWerf

Charles Mills wrote:
...
Over here in Portland (where there are lots of Ruby jobs and everyone is
happy) we were talking about working on an *enhanced* version of irb
that would support some/all of the stuff you see here:
http://ipython.scipy.org/ (scroll down to Main Features)
Hasn't gone anywhere though, but I am still pretty excited about the idea.
IMHO some type of irb addition which groups statements by blocks instead
of by lines would be nice. So when you press 'up' you cycle through the
blocks in your history rather than the individual lines. (by block I
mean if .... end, do .... end, etc) Seems like it would have to be more
than a drop in readline replacement, since it would have to allow
multiline editing of the blocks in history.

That would be very nice. I've wanted that ever since I started using zsh
in place of bash. I wonder if there is some reusable code in zsh to
replace readline....
 
R

Robert Klemme

I can hack something up pretty quick in Perl, but I stand a better
chance of maintaining it in Ruby so I get it to work in Perl and then
take the design over to Ruby.

Does this work well? I assume I would do many things quite differently
when in Perl and I wouldn't want to port that design to Ruby.

Kind regards

robert
 
R

Robert Klemme

I feel Perl has a slight edge in quick and dirty scripting. Simple
things like having to call to_s() on the integers I print or

Under which circumstances do you need to_s for numbers? What's wrong with
this?
1
=> nil1
=> nilfoo 1 bar
=> nil

Kind regards

robert
 
G

Garance A Drosehn

So the question for any hardcore Perl coders out there that have
converted to Perl (or are fluent in both) is: Is it really worth the
time? Are the paybacks there? And do you feel you've exceeded your
capabilities in Perl using Ruby?

I perceive, from what I've read, that this could be the case.

I learned perl well before ruby. I wouldn't say that I'm a hardcore
perl programmer, but I had written some fairly long perl scripts. And
I still work with perl, because that's what most of the other systems
programmers here are familiar with.

For me, I think it's just a question of "how I think". I usually have
to start out on some script with either no idea what I'm doing, or
with explicit instructions which turn out to be wrong (such as "the
data will always be sorted, and in the correct order" -- only to find
out the incoming data is usually in the exactly-wrong order...). So,
whether ruby or perl, I start out to write one thing, and later find
out that I need to change that considerably. When programming in
perl, I end up with the script getting messier and messier. With ruby
I manage to keep refactoring the problem fairly easy, so the script
keeps looking better the more I have to work on it.

I think this is partially because I used to do a lot with ObjectiveC,
so it is pretty natural for me to use object-oriented tactics, if I
have a language where that's easy to do. While I have done a lot with
perl, I never did quite wrap my mind around how to write
"object-oriented Perl". But writing Ruby seems very straightforward
to me.

YMMV...
[...] in my estimation, the paradigm in Ruby is
entirely different than in just about any other procedural language and
even from the OO aspects of Perl, C++ and Java.

I know some programmers who do a fine job writing OO-perl, and end up
with code that is quite readable. My attempts end up a mess. Maybe
my brain is just wired wrong.

Personally, I find C++ to be horrid. I do not consider it a usable OO
language. That's just my opinion, of course. I have certainly read
through a lot of C++ code where the author has absolutely no idea what
OO programming is about.

Java looks pretty reasonable in my opinion, but in my job I have no
real reason to use it for anything. So, I haven't really tried to
write anything major in it.

The object-oriented language that I had a lot of experience with is
Objective-C, in the days when NeXT Computers was still making hardware
(12 years ago...). The combination of Objective-C and the
InterfaceBuilder goes a long way to guiding the programmer so you
really start to understand what OOP is about. You pick up what you
should be trying to do with objects, and what you gain by doing it
correctly. For me, coming from that Objective-C background, Ruby was
easy to pick up.

I have no background with Smalltalk, but I suspect that programmers
who know that OO language would also find Ruby easy to pick up.
 
D

David A. Black

Hi --

Yes, this is a better example of what I was talking about, and yes, you
can provide better indication here in Ruby than in Perl, I have to
admit. So, to see the parallels, I'll bet you see a lot more of the
simple yields in block handling method definitions in classes than you
do in the form of you second example with the spiked out parameter and
the param.call approach. It's disciplined, well constructed code, but
not everyone is like that. Hence the Perl dilemma/diatribe here.

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.


David
 
C

Curt Hibbs

Gavin said:
My favourite refactoring pattern at the moment is to move all the related
private methods of a class into their own class. It helps to clarify the
real responsibility of the original class, to highlight the relationship
between them, and to test the supporting code more easily. (The difficult
part is thinking of a name for the new class.)

I hadn't thought of this, but it is immediately obvious to me that this can
be very useful. I'm going to try this on the Java project I'm doing for
work!

Thanks,
Curt
 

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

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top