> Wiggins d Anconia said:

<snip>

> >
> > sub links {
> >    my ($base_url, @list) = @_;
> >    foreach my $element (@list) {
> >        print .....
> >    }
> >    return;
> > }
> 
> Doesn't this still get the scalar and array from what I defined at the
top?
> 

No, note that I have changed the names (on purpose) so that they are
defined specifically to the sub (as your other email mentioned).  Since
I have given them new names they are essentially copies of the original
data, but since the variables are within the scope of the sub I can now
take the sub and drop it into a library and it will still work, though
the calling syntax has to be different (see summary below).

> Also, why do you assign them to @_, can't we use that when iterating
@list?
> 

I am not assigning them *to* @_, but *from* @_. In other words, when the
subroutine is called it automatically stuffs the arguments given to it
in @_.  Then within the subroutine I want to pull those arguments back
out of @_ and use them to do something (you don't really have to give
them new names, but accessing into @_ as $_[0], $_[1], etc. gets
annoying).  Of course that is where hashes come into play :-)...

> Why wouldn't it accept it's arguments?

In your case you were not using the @_ values so it was not expecting
(or using) the arguments, and your calling syntax of C<links()>
indicates that no arguments are being passed.

> 
> >> -----------------
> >>
> >> I would normally call the subroutine like &links; but I want to put the
> result into a variable in order to stick it into an e-mail. I have been
> trying all day reading all my perl books and it's time to ask for help.
> >>
> >
> > Note that we don't want to call C<&links> that is better written as
> C<links()>.
> >
> > What is the result?  In your case you are printing the links, so there
> is no real result.
> 
> That is what I want, but I can't figure how to but the list into the
> e-mail message.

See summary below...


> 
> > You need to decide what the return value of the sub
> > will be, maybe the list of urls?
> 
> A list of urls.

Ok.

> 
> > a bool? undef for positive or an
> > exception for failure?  In the case of the list you should be C<push>ing
> the values to list and then returning the list.  In this last case we
> can call the sub such as,
> >
> > my @ahrefs = links($website, @pics);
> 
> I get this part.
> 
> > foreach my $link (@ahrefs) {
> >   print "$link<br />\n";
> > }
> 
> Isn't the above the same as my subroutine?
> 

Sort of, except I have broken the different functional components apart
and can now reuse C<links()> as a sub to build a list rather than to
*print* a list.  But in some cases I want to print a list, so I just
print it afterwards.

> > For instance.
> >
> >> Thanks.
> >>
> >
> > Give it a shot, see if this helps, if not come back and ask more.
> 
> Much appreciated. I will be re-reading Ch2-4 of the Lama tonight.
> 

The llama is excellent.

Ok so for the summary,

Starting over with your sub that breaks encapsulation by not accepting
arguments, and not returning a value, and has the less portable benefit
of always printing the values (despite the fact that sometimes we might
want them returned to us).

my @pics = (list);
my $website = 'url';
links();

sub links {
       foreach (@pics) {
           print "<a href=\"$website/$_\">$website/$_</a>\n";
       }
}

So in the above your sub *assumes* @pics and $website exist. We want to
switch it so that the sub assumes nothing and accepts all of the info it
needs as arguments. So we get,

my @pics = (list);
my $website = 'url';
links($website, @pics);

sub links {
       my ($url, @list) = @_;
       foreach my $element (@list) {
           print "<a href=\"$url/$_\">$url/$_</a>\n";
       }
}

Notice that the call to the sub changed, and that it now doesn't use
either of @pics, or $website, which means that it could be a list of
anything and the $website is really just a base url.  But we are still
stuck with it just printing to STDOUT, so lets make it return a value
instead making it more useful for other things...

my @pics = (list);
my $website = 'url';
my @piclinks = links($website, @pics);

# now @piclinks is just a list that we could put in an email instead
print for @piclinks;  

sub links {
       my ($url, @list) = @_;
       my @return;
       foreach my $element (@list) {
           push @return, "<a href=\"$url/$_\">$url/$_</a>\n";
       }
       return @return;
}

So again I changed the call to now catch what the sub returns, and
stopped the sub from printing the links.  Inside of the sub I built a
temporary list and returned it so that the caller could catch it and use
it. (I have specifically left out the syntactic sugar of editing the
elements in place, etc. for clarity since we are discussing subs not
shortening of code.)

So why is this better, still does the same thing?  Mostly because it is
reusable now. For instance,

my @piclist1 = (list);
my @piclist2 = (a different list);
my $website = 'url';

my @email_list = links($website, @piclist1);
my @db_list = links($website, @piclist2);

# send an email with @email_list

# store to a database with @db_list

Now your sub is generic, it doesn't rely on the specific names, @pics
and $website, and doesn't cause data to be printed when you might not
want it to.  Obviously this is a contrived example but as things get
more complex it becomes absolutely critical.

HTH,

http://danconia.org

-- 
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