Stuart White [mailto:[EMAIL PROTECTED]
:
: >     When writing a subroutine, think of it as a miniature
: > program. Something is passed in, processed, and output. Some
: > subs only do one or two of those, but many do all three. Try
: > not to process anything that is not local to the sub.
:
: That's how I think of them.  I'd prefer to be able to pass in a
: value, have the sub take that value into it's own variable,
: process it, and then spit it back out into the value back in the
: "main" or parent (in the case that there is a sub within a sub)
: program.  I've tried this the only way I know how, which is to
: declare the subs with the number of arguments they are to take,
: and I believe the type of argument they are to output (like you
: might see in a C program), and then created my variables within
: the sub.  Two things happened, when I couldn't get one of them
: to work and asked for help here, I felt like I got flamed from a
: few people because I was declaring my subroutines with the
: number of arguments. I was told I didn't have to so why bother.

    I'm sorry about that. I didn't mean to flame you. It just
seemed like you were taking the long way around to solve the
problem.


: I did it for two reasons, the only intro programming class I
: took taught in C, that's how it was taught, and I happened to
: like that style because of the organization, AND, in
: 'Beginning Perl' the author writes about doing it that way. This
: was about 8 mos ago before I had to stop working on this to
: study for the LSAT.  I still think of subs that way, but think
: that perhaps Perl is not so much like C, and I get the feeling
: that the Perl community doesn't like the structure of C and
: avoids it, sometimes passing on that sentiment to others.

    That's funny. When I started reading the documentation a few
years ago, I got the distinct impression that only programmers
with a background in C were being invited to the perl party. I
even complained about it on the another beginner email list.


: (I recognize I ranted and went off on a tangent a bit, I hope
: that's not too rude.)

    No. I'm so glad you said all that. It explains a lot. If I had
known this when you first mentioned prototypes, I could have
written a more useful reply.


: > In ParseLineForHomeAndVisitors(), $_ is not local to the sub,
: > neither is @teams. It would be better to pass that value in:
: >
:
: See, it doesn't look like you're passing anything in here. If I
: were to write it, I'd write it like this:
: #sub protype declaration #this would be up at the top,
: #before I even declared any variables
: ParseLineForHomeAndVisitors($);
:
:  sub ParseLineForHomeAndVisitors($line) {
:      my $line  = shift;
:      my @teams = ( $line =~ /([[:alpha:]]+)/g );
:      return @teams;
:  }
:
: which may or may not work, but it seems to follow the
: structure Cozens talks about in his book, 'beginning
: perl', ch 8, page 254.
: Perhaps this is just an internal battle with me not
: understanding the syntax of perl subroutines, and not
: wanting to relinquish the clarity of a C program.

    Okay. In perl everything is passed into the sub with a special
array called @_. Let's call a subroutine named link(). (I'm going
to use list and array interchangeably here. They're not really the
same though.)

print link( '/perl/', 'Learning Perl' );

    Behind the scenes, perl creates a list of the two arguments
'/perl/' and 'Learning Perl' and sets it equal to @_. It then
passes control to link().

    Inside link() we need to access @_ to get to the arguments.
What is declared on the subroutine declaration line is not use by
perl to transfer subroutine arguments. It is only used for type
checking.

    Let's write link():

sub link {
    my( $href, $name ) = @_;
    return qq(<a href="$href">$name</a>);
}

    It is pretty obvious how the we accessed @_ here, but in
ParseLineForHomeAndVisitors() we have this:

sub ParseLineForHomeAndVisitors($line) {
    my $line  = shift;
    my @teams = ( $line =~ /([[:alpha:]]+)/g );
    return @teams;
}

    The second line is accessing @_. 'shift' operates on @_ by
default, so

    my $line  = shift;

    is shorthand for:

    my $line  = shift @_;


    In perl, declaring subs at the top of the script is necessary
when using prototypes. Prototypes in perl do not work the way you
are using them. They do not declare a variable. They restrain the
type of values which can be passed to a subroutine.

    Perl prototyping handles this type checking for the
programmer, but it still uses @_ to pass arguments for the sub. I
have always found prototypes too restrictive. I understand why you
are using them, but I still think life will be easier if you
abandon them.


: > : I tried the same thing with my hash:
: > :
: > : CreateAbbrevAndNicknamesHash();
: > :
: > : and here's the sub:
: > : sub CreateAbbrevAndNicknamesHash()
: > : {
: > : my %AbbrevAndNicknames;
: > : %AbbrevAndNicknames = (
: > :    IND=>  "Pacers",
: > :       .
: > :       .
: > :       .
: > :   );
: > :
: > :
: > : }
: >
: >     The big question here is: Why a subroutine?
:
: Style.  If I had my druthers, I'd write a program with
: nothing but subroutines in the "main" program.  For
: example, to program a robot to pour a glass of milk:
: GoToIcebox();
: OpenDoor();
: LocateMilk();
: GrabMilk();
: RemoveMilkFromIcebox();
: CloseDoor();
: MoveToCounter();
: PutMilkOnCounter();
: ... (I think the point has been made) :)
: PourMilkInGlass();

    I agree. However, that shouldn't be the goal (in perl) for a
beginner. It is possible, but it requires the knowledge you'll
obtain by using some data structures.


: And then below, I'd have a section called sub definitions, where
: I'd define all those subs, and maybe others that made up those
: subs.  Writing like this is easier on my eyes and tells me and
: someone else (given my subs have descriptive names) a very good
: idea of what I want to do.  I write subs for printing out a few
: lines of intro instructions.  It just makes sense to me.  So
: that's why a sub.

    In perl, one problem with using a sub this way is that it
forces the use of global variables. If %AbbrevAndNicknames has not
been declared above the subroutine, how else will you pass it
around the script?


: > If you want to create a hash, create a hash:
: >
: > my %AbbrevAndNicknames = (
: >         IND => 'Pacers',
: >         NJN => 'Nets',
: >         DET => 'Pistons',
:          <snip>
:           PHX => 'Suns',
: > );
: >
: >     I don't see the point of the subroutine. If
: > you want to return a hash from a subroutine,
: > use 'return'. Note that foo() actually returns
: > a list (or is it an array?). We decide to stuff
: > the result into a hash.
: >
:
: I tried using return.  It didn't work.  I thought
: maybe it was because I was trying to return a hash, or
: trying to return the hash to a hash and not a scalar
: (which would have been zero use to me).
:
: >
: > #!/usr/bin/perl
: >
: > use strict;
: > use warnings;
: > use Data::Dumper 'Dumper';
: >
: > my %foo_hash = foo();
: >
: > print Dumper \%foo_hash;
: >
: > sub foo {
: >     return (
: >
:
: I'll try it this way.  I used return at the end of the
: sub, after the ; but before the }.
: Thanks.

    You might want to depend on the documentation that comes with
perl more than the book you are using. 'perlfunc' has a listing of
almost all the the functions you'll see here. Perldoc.com has
handy html documentation for the major versions of perl. 'Perlsub'
does a better, deeper job than me with subroutines.

    Here is a small script to show typical processing of a file in
perl. Instead of opening a file. I'll use the special file handle
DATA, which is everything past the __END__ tag in this script.
Hopefully, it will give you a basis for writing subs in perl.

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper 'Dumper';

# @teams is at file level scope. Perl allows
# it to be used anywhere in this file (script).
# We assume responsibility not to use it as a
# global variable.
my @teams;

# $line is scoped within this while block
# It disappears after the brace ends the block.
while ( defined( my $line = <DATA> ) ) {

    # This goes to the next line unless we get
    # a match for teams.
    next unless $line =~ /^[[:alpha:]]+\s+[[:digit:]]+,/;

    # We have a match, let's fetch the teams
    @teams = fetch_teams( $line );

    # Stop processing the file
    last;
}

# Dumper() provides an easy method to see
# the composition of even complex data structures
print Dumper [EMAIL PROTECTED];

# At this point <DATA> will point to the third
# line '1st Period'

while ( defined( my $line = <DATA> ) ) {
    #
    # process the stats
    #
}

sub fetch_teams {
    my $line = shift;
    return ( $line =~ /([[:alpha:]]+)/g );
}
__END__

Spurs 94, Suns 82
1st Period
(12:00) Jump Ball Robinson vs Williams
(11:41) [PHX] Marion Turnaround Jump: Missed

------------------

    We could also write fetch_teams to process the file handle up
to the point where the teams are defined:

# @teams is at file level scope. Perl allows
# it to be used anywhere in this file (script).
# We assume responsibility not to use it as a
# global variable.
#
# \*DATA is a reference to the glob DATA
#
my @teams = fetch_teams( \*DATA );

print Dumper [EMAIL PROTECTED];

# At this point <DATA> will point to the third
# line '1st Period'

while ( defined( my $line = <DATA> ) ) {
    #
    # process the stats
    #
}

sub fetch_teams {
    my $data = shift;
    while ( defined( my $line = <$data> ) ) {
        next unless $line =~ /^[[:alpha:]]+\s+[[:digit:]]+,/;
        return ( $line =~ /([[:alpha:]]+)/g );
    }

    # this returns undef.
    # It should do error checking
    return;
}
__END__

Spurs 94, Suns 82
1st Period
(12:00) Jump Ball Robinson vs Williams
(11:41) [PHX] Marion Turnaround Jump: Missed

HTH,

Charles K. Clarkson
-- 
Mobile Homes Specialist
254 968-8328


-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
<http://learn.perl.org/> <http://learn.perl.org/first-response>


Reply via email to