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>