This thought came out of a question I've been puzzling about in my tiny-brained way, and which I mentioned in the CB yesterday. As well as raising my present topic I'm glad to have an excuse to put down the solution to the problem I discussed, just so anyone who was kind enough to offer advice can see that it didn't fall on deaf ears. Thanks again, sibling monks.

I'd also like to crave your indulgence for any foolishness I may commit in the following, as these questions of scope and naming are new to me and I find them quite difficult.

So, my thought. I think it might be nice if there was a way to make a subroutine behave, in regard to naming scopes, exactly the same as if, instead of calling the module, you had cut and pasted the lines of code into your script in place of the subroutine call.

Maybe there is a way to do this. If so, I'd love to know of it. Maybe you think it wd be a dangerous thing. But, whilst being open to persuasion, I don't agree: the variables are still contained within a lexical scope, only it's the lexical scope of the surrounding block. So if the subroutine creates or alters variables in the scope in which it's called, this is only a problem to the extent that one has been careless with one's variables and scoping anyway.

Set against this danger, is the advantage of (A) being able to give the subroutine access to all the variables existing in the calling scope without and (B) being able to pass back not just a return value but a variable (or several vars) which can be manipulated.

On the other hand, if you just don't see why I would be worried about this in the first place, follow the readmore tag...

In the set of scripts I'm working on now I often have to interrogate a database to get three records from three different tables, in the form of three hashrefs, which I then do a wide range of different operations on. The main place for code re-use here is the getting of the data from the db, not what I do with it. Now the problem is, my subroutine needs to return a hashref which I can then use freely after the subroutine is done. One way I tried to do it was:

First I have a module, let's call it booker.pm, which looks like this:
package booker; require Exporter; our @ISA = ("Exporter"); sub Get_Booking_Course_Event { my $BookingID = shift; my $dbh = DBI->connect("DBI:mysql:database=foo", "bar", "baz") or +die $DBI::errstr; my $sth; $sth = $dbh->prepare("SELECT * FROM booking WHERE BookingID = $Boo +kingID") or die $dbh->errstr; $sth->execute(); $ref_booking = $sth->fetchrow_hashref; $sth = $dbh->prepare("SELECT * FROM event WHERE EventID = $ref_boo +king->{'EventID'}") or die $dbh->errstr; $sth->execute(); $ref_event = $sth->fetchrow_hashref; $sth = $dbh->prepare("SELECT * FROM course WHERE CourseID = $ref_b +ooking->{'CourseID'}") or die $dbh->errstr; $sth->execute(); $ref_course = $sth->fetchrow_hashref; } our @EXPORT = qw/Get_Booking_Course_Event/; 1;
And use booking; in each of the scripts.

My first attempt at calling this subroutine was
my $ref_booking; my $ref_event; my $ref_course; &Get_Booking_Course_Event($ref->{'BookingID'}); # the arg in this sub cd be one of a number of # things depending on where in the script we are do_stuff_with($ref_booking, $ref_course, $ref_event);
Now, the main problem with that is it doesn't work. Because the three variables I declare before calling the subroutine don't get into the namespace of the subroutine... let alone out of it again with something useful in them.

My next try was to call it without declaring any variables and then use the variables from the module's namespace, with fully-qualified variable names:
&Get_Booking_Course_Event($ref->{'BookingID'}); # the arg in this sub cd be one of a number of # things depending on where in the script we are do_stuff_with($booker::ref_booking, $booker::ref_course, $booker:: +ref_event);
That seems to work. But I still don't totally like it. For one thing, I quite often call this sub more than once in the same script. And even though I have error checking, I'm slightly worried that something might go wrong later on, and then the second time I do my operations with $booker::ref_booking etc, I'm still working on the first ones.

What I'd really like is to be able to localise the variables that the subroutine returns. Or even better, have them returned ready-localised. Which is what finally led me to the desire to be able to make my subroutine be in the same name space as the calling scope. Then I'd declare $ref_booking and the others in the subroutine. And I also wouldn't have to keep creating and destroying my database handle, because I could use one I created earlier, which is in scope at the point where I call the sub.

So that's what I'd like to be able to do. And I don't think I can. So... tell me I can; or tell me I'm crazy to want to.


§ George Sherston

In reply to subroutines and namespace by George_Sherston

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.