velocitymodel has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks,

I am still struggling with sub routines. I have used a dummy variable again to see where my code is failing and it seems to fail at the end of my sub routine events. Why is it doing this? I tried using last, next, and until functions but these do not seem to fix the error

use strict; use warnings; my $fin = "SELECTDAT2"; my $fout = "myfile"; open my $ih, '<', $fin or die "cannot open $fin for reading, $!"; open my $oh, '>', $fout or die "cannot open $fout for writing, $!"; sub events { my @tokens = split; my @list = @tokens[0,3,4,7,8]; push @list; } while (<$ih>) { chomp; my @tokens = split; my @records = @tokens [3,4,5,6,10,11]; push @records; my $y = $tokens[0]; my $m = $tokens[1]; my $d = $tokens[2]; my $h = $tokens[3]; events; last; } print $oh events, "\n", @$_ for sort {$a->[3] <=> $b->[3]} @records; close ($oh); close ($ih);

Replies are listed 'Best First'.
Re: Sub routines
by davido (Cardinal) on Mar 30, 2011 at 05:41 UTC

    All of your problems are related to not understanding lexical scope, lexical variables, and the concepts of outter scopes being masked by inner scoped variables of the same name.

    There's no need to declare 'my @list;' on line 7 (ie, outside the loop). This lexical variable is masked by the version of @list that exists within the sub, and that's the only time you use that variable anyway.

    Your declaration on line 8 of @records gets masked by the new @records declaration within the while() loop. Then when the loop terminates, you get the original @records back, empty because it is not the same variable you were using within the while() loop.

    You're pushing onto @list a reference to @list. And then returning @list. Yet inside your sub @list will never have more than one element. If that's really what you want, just return \@list. But that's probably not what you really want anyway. You probably want @list to not be passing in and out of scope every time you call your sub. But what's not what you need. You need to use lexical scoping correctly.

    @records will never contain more than one element at the end of each iteration of your while() loop. And then it passes out of scope and disappears.

    Any lexical declared within your while() loop will cease to exist at the end of each loop iteration. So there is nothing to print from @records. The @records being used inside the while() loop is a different variable from @records declared outside the while loop.

    As mentioned in other posts, it's a bad habit to absorb values into a subroutine without passing them explicitly. That even applies to lexical filehandles.

    Your biggest challenge seems to be in gaining an understanding of lexical scoping. perlsub is a good first step in understanding. But I'd actually recommend you pick up a copy of Learning Perl, from Randall Schwartz. Most of the problems you're having will disappear after you read through that book.


    Dave

      Thank you for your advice and help. I do have that book and I am slowly working through it. Thanks again.

Re: Sub routines
by JavaFan (Canon) on Mar 30, 2011 at 08:13 UTC
    On top of what's already mentioned, also note that each iteration of your loop, you process three lines:
    1. The guard of the while reads a line, puts it in $_. This line is processed (by chomp and split).
    2. A line is assigned to $nextline. Which is then unused.
    3. Inside events, another line is read, assigned to another $nextline. This one remains unused as well.
Re: Sub routines
by wind (Priest) on Mar 30, 2011 at 05:56 UTC

    Your code is pretty much impossible for me to decipher its purpose. You've posted questions here multiple times, and each time monks have attempted to figure out you're trying to do to little avail:

    I've read each of those, and nowhere do you try to explain your project in English.

    Anytime someone is coding something, they should be able to explain it in words before they dive into coding. It would really help us if you were to explain what you're code is trying to accomplish. What is your data and how are you trying to process it?

      Sorry about the confusion. I will definitely try and work that out in for myself. Thanks for the advice.

        Hi Mate,

        My advice is not that you go and just solve your own problem. It's that you try to explain to us what you're doing before showing us code. You've been working on this "project" for a while now so it's apparent that you're trying to accomplish something. However, given the number of consistent errors in your code even without knowing what it's doing, maybe it's time to start over?

        Share a description of your project in english, and let us guide you toward the right way of accomplishing it.

Re: Sub routines
by choroba (Cardinal) on Mar 31, 2011 at 08:48 UTC
    open my $ih, '<', $fin or die "cannot open $fin for reading, $!"; $ih =~ s/\n+/\n/g;
    Substitution on a filehandle? It does not execute the substitution on the file content, though. You can verify it with
    $ih =~ s/\n+/\n/g or warn "No subst\n";