Ask a Question related to PERL Beginners, Design and Development.
-
Jan Eden #1
Subroutine interaction
Hi all,
the following structure does not work as intended:
sub read_index {
my $gedicht_path = shift;
my (%author_indexlines, %author_headlines, %gedicht_lines, @author_letters, @gedicht_letters, @alphabet_index);
find (\&read_poem, $gedicht_path);
print %author_indexlines; # nothing is printed out here!
return \(%author_indexlines, %author_headlines, %gedicht_lines, @author_letters, @gedicht_letters, @alphabet_index);
}
sub read_poem {
# scalars to read from the poem page
my ($vorname, $nachname, $title, $namekey, $titlesort_string, $nameletter, $titleletter, $page, $relative_path);
my $pathname = $File::Find::name;
return 0 unless $pathname =~ /\.html$/;
# definition of the file path relative to the $gedicht_path
$relative_path = $pathname;
$relative_path =~ s#$gedicht_path/##; # Perl complains about uninitialized value here
[filling the hashes and arrays declared above]
print %author_indexlines; # the hash is printed correctly here
}
I expect the variable $gedicht_path to be accessible inside the read_poem subroutine, since it is called from within read_index, it is not (I get an 'uninitialized value' error).
Second, I expect the hashes and arrays in declared in read_index to be filled in read_poem. read_poem does not complain about undeclared variables, and I can print the appropriate %author_indexlines etc. from within read_poem, but not from read_index, as intended.
Can anyone point me to the (probably obvious) problem with the locally scoped variables?
Thanks,
Jan
--
Either this man is dead or my watch has stopped. - Groucho Marx
Jan Eden Guest
-
subroutine problem
Hi all, I have recently started to learn perl. After reading Randal Schwartz’s Learning perl, I decided to give my first program a whirl. Upon... -
undefined subroutine
I'm doing a php to pl migration and having a little trouble. Help appreciated! Undefined subroutine &main::fopen called at... -
how to trace a subroutine?
I have a subroutine "foo" in a file "my.pl". I invoke it by: require "my.pl"; &foo; This has worked fine for a while. Now I try to make... -
reference to a subroutine in @INC
Hi, I am trying to package a perl script and the modules it uses , in a tar file. When untarred on any machine, the modules can be found in a known... -
Subroutine as a new Task
Hello, how can I start a soubroutine as a new task. The main script should run on until the end is reached. But the subroutine should run in... -
Jeff 'Japhy' Pinyan #2
Re: Subroutine interaction
On Jan 28, Jan Eden said:
The only way that hash can get populated outside of this function is if it>sub read_index {
> my $gedicht_path = shift;
> my (%author_indexlines, %author_headlines, %gedicht_lines, @author_letters, @gedicht_letters, @alphabet_index);
> find (\&read_poem, $gedicht_path);
> print %author_indexlines; # nothing is printed out here!
you pass it by reference to another function, and populate it THERE. A
my() variable is scoped lexically -- that is, physically. It only exists
here, inside this block of code, unless you send its reference to another
scope.
You're not filling the same hashes and arrays; you're filling GLOBAL> return \(%author_indexlines, %author_headlines, %gedicht_lines, @author_letters, @gedicht_letters, @alphabet_index);
>}
>
>sub read_poem {
>
> # scalars to read from the poem page
> my ($vorname, $nachname, $title, $namekey, $titlesort_string, $nameletter, $titleletter, $page, $relative_path);
>
> my $pathname = $File::Find::name;
> return 0 unless $pathname =~ /\.html$/;
>
> # definition of the file path relative to the $gedicht_path
> $relative_path = $pathname;
> $relative_path =~ s#$gedicht_path/##; # Perl complains about uninitialized value here
> [filling the hashes and arrays declared above]
hashes and arrays that happen to have the same name. If you were using
'strict', you'd be told about that.
It's not, because it exists ONLY in the read_index() function.> print %author_indexlines; # the hash is printed correctly here
>}
>
>I expect the variable $gedicht_path to be accessible inside the read_poem
>subroutine, since it is called from within read_index, it is not (I get
>an 'uninitialized value' error).
What warnings about undeclared variables are you expecting? Unless you>Second, I expect the hashes and arrays in declared in read_index to be
>filled in read_poem. read_poem does not complain about undeclared
>variables, and I can print the appropriate %author_indexlines etc. from
>within read_poem, but not from read_index, as intended.
have 'strict' on, Perl doesn't stop you from saying, out of the blue,
push @foo, 'this';
One way you can fix your situation is to use a closure -- an anonymous>Can anyone point me to the (probably obvious) problem with the locally
>scoped variables?
code block created inside read_index():
sub read_index {
my $gedicht_path = shift;
my (%author_indexlines, %author_headlines, %gedicht_lines,
@author_letters, @gedicht_letters, @alphabet_index);
my $read_poem = sub { # notice, no NAME for the sub
# scalars to read from the poem page
my ($vorname, $nachname, $title, $namekey, $titlesort_string,
$nameletter, $titleletter, $page, $relative_path);
my $pathname = $File::Find::name;
return 0 unless $pathname =~ /\.html$/;
# definition of the file path relative to the $gedicht_path
$relative_path = $pathname;
$relative_path =~ s#$gedicht_path/##;
# do stuff with hashes and arrays
};
find ($read_poem, $gedicht_path);
print %author_indexlines; # now it'll work
# return whatever
}
--
Jeff "japhy" Pinyan [email]japhy@pobox.com[/email] [url]http://www.pobox.com/~japhy/[/url]
RPI Acacia brother #734 [url]http://www.perlmonks.org/[/url] [url]http://www.cpan.org/[/url]
<stu> what does y/// stand for? <tenderpuss> why, yansliterate of course.
[ I'm looking for programming work. If you like my work, let me know. ]
Jeff 'Japhy' Pinyan Guest
-
Rob Dixon #3
Re: Subroutine interaction
Jan Eden wrote:
Hi Jan.>
> the following structure does not work as intended:
>
> sub read_index {
>
> my $gedicht_path = shift;
> my (%author_indexlines, %author_headlines, %gedicht_lines, @author_letters, @gedicht_letters, @alphabet_index);
> find (\&read_poem, $gedicht_path);
> print %author_indexlines; # nothing is printed out here!
> return \(%author_indexlines, %author_headlines, %gedicht_lines, @author_letters, @gedicht_letters, @alphabet_index);
> }
>
>
> sub read_poem {
>
> # scalars to read from the poem page
> my ($vorname, $nachname, $title, $namekey, $titlesort_string, $nameletter, $titleletter, $page, $relative_path);
>
> my $pathname = $File::Find::name;
> return 0 unless $pathname =~ /\.html$/;
>
> # definition of the file path relative to the $gedicht_path
> $relative_path = $pathname;
> $relative_path =~ s#$gedicht_path/##; # Perl complains about uninitialized value here
> [filling the hashes and arrays declared above]
> print %author_indexlines; # the hash is printed correctly here
> }
>
> I expect the variable $gedicht_path to be accessible inside the read_poem
> subroutine, since it is called from within read_index, it is not (I get an
> 'uninitialized value' error).
>
> Second, I expect the hashes and arrays in declared in read_index to be filled
> in read_poem. read_poem does not complain about undeclared variables, and I
> can print the appropriate %author_indexlines etc. from within read_poem, but
> not from read_index, as intended.
>
> Can anyone point me to the (probably obvious) problem with the locally scoped
> variables?
Lexical ('my') variables are accessible only within the innermost block or
file in which they are declared. As the body of a subroutine is a block
things like your $gedicht_path are accessible only within &read_index.
You need to declare the list of hashes and arrays /before/ and /outside/
any subroutine that needs them. Like this:
my (%author_indexlines, %author_headlines, ... );
sub read_index {
:
}
sub read_poem {
:
}
Also, think carefully about whether you need so much common data. I would
expect to see the sort of thing you're using contained within a single hash.
Without knowing more about what you're doing I can't help any further.
HTH,
Rob
Rob Dixon Guest
-
Jan Eden #4
Re: Subroutine interaction
Jeff 'japhy' Pinyan wrote:
Yes, that's what I suspected. But I was tricked because ...>On Jan 28, Jan Eden said:
>>>>sub read_index {
>>my $gedicht_path = shift; my (%author_indexlines, %author_headlines,
>>%gedicht_lines, @author_letters, @gedicht_letters, @alphabet_index);
>>find (\&read_poem, $gedicht_path); print %author_indexlines; #
>>nothing is printed out here!
>The only way that hash can get populated outside of this function is
>if it you pass it by reference to another function, and populate it
>THERE. A my() variable is scoped lexically -- that is, physically.
>It only exists here, inside this block of code, unless you send its
>reference to another scope.
>... I *did* use strict in my main script. I did not within the module the subs reside in, though. Since the main script never saw the subroutines, its strict pragma did not notice my error. Doh!>
>You're not filling the same hashes and arrays; you're filling GLOBAL
>hashes and arrays that happen to have the same name. If you were
>using 'strict', you'd be told about that.
>
Thank you! I will try this as soon as possible.>>>Can anyone point me to the (probably obvious) problem with the
>>locally scoped variables?
>One way you can fix your situation is to use a closure -- an
>anonymous code block created inside read_index():
>
Learning more and more,
Jan
--
How many Microsoft engineers does it take to screw in a lightbulb? None. They just redefine "dark" as the new standard.
Jan Eden Guest
-
Rob Dixon #5
Re: Subroutine interaction
Jan Eden wrote:
Just as it should be :)>
> Learning more and more
Well done,
Rob
Rob Dixon Guest
-
R. Joseph Newton #6
Re: Subroutine interaction
Jan Eden wrote:
Hi Jan,> Hi all,
>
> the following structure does not work as intended:
>
> sub read_index {
>
> my $gedicht_path = shift;
> my (%author_indexlines, %author_headlines, %gedicht_lines, @author_letters, @gedicht_letters, @alphabet_index);
> find (\&read_poem, $gedicht_path);
> print %author_indexlines; # nothing is printed out here!
> return \(%author_indexlines, %author_headlines, %gedicht_lines, @author_letters, @gedicht_letters, @alphabet_index);
> }
>
>
> sub read_poem {
>
> # scalars to read from the poem page
> my ($vorname, $nachname, $title, $namekey, $titlesort_string, $nameletter, $titleletter, $page, $relative_path);
>
> my $pathname = $File::Find::name;
> return 0 unless $pathname =~ /\.html$/;
>
> # definition of the file path relative to the $gedicht_path
> $relative_path = $pathname;
> $relative_path =~ s#$gedicht_path/##; # Perl complains about uninitialized value here
> [filling the hashes and arrays declared above]
> print %author_indexlines; # the hash is printed correctly here
> }
>
> I expect the variable $gedicht_path to be accessible inside the read_poem subroutine, since it is called from within read_index, it is not (I get an 'uninitialized value' error).
I'm afraid that this represents a basic misunderstanding of the purpose of subroutines. Subroutines and other containment tools protect and simplify problems by reducing the number of variables that may aggect the outcome. If they freely had access to each other's
data, there could be no such assurance.
Your code as posted show at least two of the three essential front doors for moving data in and out of subroutines. I havent looked closely enough yet to see if any of your arguments are references--that would be a third. Your function both take in arguments or
agument lists through the @_ array. This is the appropriate way to get values into a function. The first one also returns a value, the classic means for getting information out of "returned from" an array If you need to affect some object or variable from within
the function, you can pass a reference as an argument, and access the original through the reference.
The power of subroutines comes from requiring you to explicitly decide, and thus be aware of, what information is being passed i and out, and why.
perldoc perlref> Second, I expect the hashes and arrays in declared in read_index to be filled in read_poem. read_poem does not complain about undeclared variables, and I can print the appropriate %author_indexlines etc. from within read_poem, but not from read_index, as intended.
perldoc perlreftut
Would be good places to start.
It is not a problem. It is the most powerful tool that we, as programmers, have in making complex problems manageable. The problems arise when variables can be accessed, and corrupted by any code anywhere in a program.>
>
> Can anyone point me to the (probably obvious) problem with the locally scoped variables?
Joseph>
>
> Thanks,
>
> Jan
R. Joseph Newton Guest
-
Jan Eden #7
Re: Subroutine interaction
Rob Dixon wrote:
That's the way I had done it before. But I thought I'd fiddle around with returning references to the hashes and arrays from read_index to write_index(for learning purposes, not for efficieny).>You need to declare the list of hashes and arrays /before/ and
>/outside/ any subroutine that needs them. Like this:
>
>my (%author_indexlines, %author_headlines, ... );
>
>sub read_index {
>:
>}
>
>sub read_poem {
>:
>}
>
I am not sure if I could store all this in one hash:>Also, think carefully about whether you need so much common data. I
>would expect to see the sort of thing you're using contained within
>a single hash. Without knowing more about what you're doing I can't
>help any further.
%author_indexlines contains the author's name as a key and a line with author name and a link as its value
% author_headlines contains the same keys and the author's name with an anchor for the respective link in %author_indexlines as its value
%gedicht_lines contains the same keys and an array of poems for the respective author
@author_letters and @gedicht_letters contain the letters for the navigationbar on top of the index page. I did (A..Z) in an earlier version of the script, but then I'd have a Q entry everywhere even if there was no poem title or author beginning with Q.
@alphabet_index contains the content of all the arrays from the %gedicht_lines hash. In this case, I could really put it into the &write_index subroutine since it's used nowhere else.
But I have no idea how to merge the other variables without loosing track of how to access which part. Please have a look at the index files produced at
<http://jan-eden.de/public/literatur/maerchen/index.html>
<http://jan-eden.de/public/literatur/maerchen/index2.html>
if you are interested. I'd be happy to improve the script further. The closure did a great job, and I noticed that everything I needed to know is right here in both Programming Perl and the Perl Cookbook. Sometimes I find it,sometimes I need this list.
Thanks again to Rob and Japhy,
Jan-->
>HTH,
>
>Rob
>
>
>
How many Microsoft engineers does it take to screw in a lightbulb? None. They just redefine "dark" as the new standard.
Jan Eden Guest
-
James Edward Gray II #8
Re: Subroutine interaction
On Jan 29, 2004, at 2:18 AM, Jan Eden wrote:
I bet you can. I'm an optimist. ;)> I am not sure if I could store all this in one hash:
I haven't been following this thread too closely, but let's just think
about it in the general sense. What you basically has is a lot of
information about specific authors, right? Can we shove an author in a
hash? Sure:
my %author = (
Name => 'Whatever',
Indexline => 'Whatever',
Headline => 'Whatever',
Gedicht_lines => [ 'Poem1', 'Poem2', 'PoemN' ]
# etc... You get the idea.
};
Again, I haven't been following too closely, so forgive me if I don't
have your format right.
From there, it's a very small leap to a global hash:
# assuming a previously defined %authors...
$authors{$author{Name}} = \%author;
Well, hopefully that'll give you some new ideas.
James
James Edward Gray II Guest
-
Jan Eden #9
Re: Subroutine interaction
James Edward Gray II wrote:
I do not have much information about a single author, it's basically just his first and last name (which is used in different orders - John Doe and Doe, John). I used two hashes for the authors because I am lazy.>On Jan 29, 2004, at 2:18 AM, Jan Eden wrote:
>>>> I am not sure if I could store all this in one hash:
>I bet you can. I'm an optimist. ;)
>
>I haven't been following this thread too closely, but let's just think
>about it in the general sense. What you basically has is a lot of
>information about specific authors, right? Can we shove an author in a
>hash? Sure:
>
But I agree that I could use a single %authors hash instead of %authors_indexlines and %authors_headlines, where the keys consist of a combination of first and last name (converted to 7-bit without white space, as I have it now). The values would consist of references to two-element hashes (first and last name).
Putting my @alphabet_index into the write subroutine, I'd be down to four variables (%authors, %gedichte, @gedicht_letters and @author_letters).
The lasst two arrays are necessary and I doubt that my script would be moreefficient when merging the %authors and %gedichte. But I'll fiddle some more.
Always grateful for your help,>Well, hopefully that'll give you some new ideas.
>
jan
--
Common sense is what tells you that the world is flat.
Jan Eden Guest



Reply With Quote

