Re: sub functions return array's
by tilly (Archbishop) on Mar 02, 2009 at 15:16 UTC
|
The biggest bug I see is that you are calling readdir multiple times in list context, but it will only return the directory once. If you want to iterate through it multiple times you should call it once and store that in an array. The second biggest potential cause of problems is that you are returning a reference to an array rather than the array directly, which could be a problem depending on how you are calling it.
However that said, virtually every line has "room for improvement". Here is a list of specifics:
- Get rid of the () in your function declaration. Prototypes in Perl almost certainly don't do what you think they do, and are likely to cause confusion for maintenance programmers. Consider them and idea that didn't work out and drop them.
- These days instead of saying DIR you can say my $dir and have a private variable. Private variables are good.
- You are passing in the directory to read as a global variable named $logSite. Decades of experience backed up by much research says that using global variables like this is poor practice. Perl has a perfectly good way of passing arguments to functions - use it.
- While you are at it add the directory and the error you got to the error message. You know, like perlstyle tells us to. This makes debugging problems much easier.
- Your use of foreach $pattern (@ARGV) { strongly suggests that you are not using strict.pm. Using that pragma will catch a lot of your bugs immediately, so it is well worth the little bit of declaration effort to make it work properly.
- Again using @uploads without declaring it private means that you are using a global variable with all of the resulting ability to accidentally overwrite global data. It also means that if you call your function twice, you will get bad data.
- If a file matches multiple patterns it will be in your array multiple times. Is that really what you want?
- There is no need to close the directory if you are not checking for errors. (Theoretically checking for errors there is a good idea. I am willing to be sloppy there though because the odds of an error are so low.)
- I would return @uploads rather than \@uploads to reduce potential surprise depending on how it is called.
Here is a rewritten version of your function. I have left your naming convention and indentation style alone because they are reasonable if different from my usual:
sub getfiles
{
my ($dirName, @patterns) = @_;
opendir(my $dir, $dirName) or die "Can't open '$dirName': $!";
my @return;
for my $file (readdir($dir))
{
for my $pattern (@ARGV)
{
if ($file =~ /$pattern/)
{
push @return, $file;
# This avoids having the file in the result twice
last;
}
}
}
return @return;
}
And then you call it like this:
my @uploads = getfiles($logSite, @ARGV);
| [reply] [d/l] [select] |
Re: sub functions return array's
by hbm (Hermit) on Mar 02, 2009 at 14:57 UTC
|
You are returning a reference to the array, not the array itself. That is a fine thing to do, but then you want to dereference it at the receiving end. Something like this:
sub getfiles()
{
opendir DIR,$logSite or die "Unable to open Directory, please try ag
+ain";
foreach $pattern (@ARGV)
{
push (@uploads, grep /$pattern/, readdir(DIR));
}
closedir DIR;
return \@uploads;
}
my $aref = &getfiles;
print @$aref; # or whatever
| [reply] [d/l] |
Re: sub functions return array's
by Bloodnok (Vicar) on Mar 02, 2009 at 14:55 UTC
|
You might want to try declaring @uploads outside the scope of the foreach loop, i.e.
sub getfiles()
{
opendir DIR,$logSite or die "Unable to open Directory, please try ag
+ain";
my @uploads;
foreach $pattern (@ARGV)
{
push (@uploads, grep /$pattern/, readdir(DIR));
}
closedir DIR;
return \@uploads;
}
Using strictures (use warnings; use strict;) would've helped enormously.
A user level that continues to overstate my experience :-))
| [reply] [d/l] [select] |
Re: sub functions return array's
by bellaire (Hermit) on Mar 02, 2009 at 14:57 UTC
|
It would be helpful to see the calling syntax, in this case you are passing back an array reference (a scalar), which must be utilized as such by the caller. That is, if you want to use the list you must dereference it.
my $uploads = getfiles();
for my $uploaded_file (@$uploads) {
print "Filename: $uploaded_file\n";
}
Alternatively you can actually return a list of values (don't use backslash to create a reference before returning):
...snip...
return @uploads;
}
my @uploads = getfiles()
| [reply] [d/l] [select] |
Re: sub functions return array's
by cdarke (Prior) on Mar 02, 2009 at 15:01 UTC
|
Hard to say without your full code, but a few comments:
You are using an empty prototype with sub getfiles() - why?
Where are your variables coming from? use warnings; use strict
Are you capturing the reference being returned correctly?
The following works for me: #!/usr/bin/perl
use strict;
use warnings;
sub getfiles
{
my ($logSite) = @_;
my @uploads;
opendir DIR,$logSite or die "Unable to open Directory, please try ag
+ain";
foreach my $pattern (@ARGV)
{
push (@uploads, grep /$pattern/, readdir(DIR));
}
closedir DIR;
return \@uploads;
}
my $ref = getfiles('.');
print "@$ref\n";
| [reply] [d/l] [select] |
Re: sub functions return array's
by CountZero (Bishop) on Mar 02, 2009 at 16:03 UTC
|
| [reply] [d/l] |
Re: sub functions return array's
by jethro (Monsignor) on Mar 02, 2009 at 14:56 UTC
|
No, nothing wrong here. It might be better to have a 'my @uploads;' before the loop so that you don't use the global variable, but that shouldn't prevent it from working.
Please post the code where you access the returned array.
| [reply] |
Re: sub functions return array's
by cdarke (Prior) on Mar 02, 2009 at 16:38 UTC
|
You changed the original question, which is a bit confusing. Anyway, as most (all?) of the answers to your previous question said, you are returning a reference, which is what the ARRAY(HEX numbers) is. You need to dereference it, for example: my $ref = getfiles();
my @uploads = @$ref;
Alternatively do not return a reference, just return a list. This can be done by ommiting the \:return @aref;
| [reply] [d/l] [select] |