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