Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Comment on

( #3333=superdoc: print w/ replies, xml ) Need Help??
HOW THE CODE WORKS

Part A
All you have to know to answer this accurately is how to run a Perl script---just plug and chug the code. You'll see that the program yields "In the beginning there was , in the end there will be ." Kind of profound, no?

Part B
Part B takes a little more work. From the output, it appears that nothing---and I mean nothing, not 'nothing'---gets passed to the subroutine. Now take a look at line 7. Notice the empty set of parentheses? You could translate the empty set of parentheses in plain english to mean "nothing will get passed to the subroutine". So then, the answer to why we get what we get in Part A is that nothing is getting passed to the subroutine!

Some of you might be wondering why we didn't get "alpha" and "omega" in our output. While a quick perusal of perlsub might lead you to believe this would happen, a closer inspection of the perlsub document explains why it doesn't. I'll just tell you: The reason why "alpha" and "omega" aren't passed to the subroutine is that the "@_" array gets locally scoped. This means that the original contents of "@_" (in this case "alpha and "omega) get temporarily placed into storage while a new "@_" appears on the scene to hold the arguments passed to the subroutine. Once the subroutine finishes, the original contents of "@_" get restored (back to "alpha" and "omega"). A good way to understand what is happening is to think about a Hollywood stunt double. As you probably realize, most movies use a stand-in instead of the "real" actors to do anything even slightly dangerous. In programming jargon, the stunt double gets locally scoped into the movie---he/she replaces the original actor to perform the stunt. Once the stunt is over, the original actor will reappear to act out the rest of scene. Applying this to our bit of code, since no arguments are getting passed to the subroutine, our "stunt variable", "@_", will be empty and this is the complete reason why we get what we get in Part A.

Finally, there may be a question as to what line 6 is doing here. Well, just read what's in the parentheses for the answer: NOTHING and NOTHING. I originally put this line into the code only to add an element of confusion. But to my amazement, and I'm sure even to the amazement of many seasoned Perl programmers, it does come very much into play in Part C. Read on, we're just getting warmed up!

Part C
The first thing to understand is that this code will behave differently depending on whether you are using Perl version 5.005 or 5.6. We'll go over both here.

Version 5.005 Behavior (the version I used)
In my discussion of "stunt" variables, one thing I neglected to tell you is that it is possible to force the "movie star" variable (the original "@_" array) to perform its own stunt. In other words, you can force the subroutine to use whatever was in "@_" before the subroutine was called. To get a clear understanding of what I mean, do the following:
---Change line 7 per the instructions for Part C
---For now, delete line 6. We'll come back to it later.
---Run the program
You should see that the output of the code is now, "In the beginning there was alpha, in the end there will be omega." The important thing to note here is that by adding the ampersand and removing the parentheses, you force the subroutine to accept whatever the contents of "@_" were before the subroutine was called. Back to our Hollywood analogy, the movie star is doing his/her own stunts. Now, will you ever be coding anything like this in the real world? Probably not. But remember, this is just a brainteaser...it's meant only to exercise the Perl muscle in your brain and make it stronger. The better you are at thinking about how Perl behaves, the better Perl programmer you'll be...I think. :-)

Now all we have left is to do is settle the matter of how the code works with line 6 involved. I myself was baffled when I ran the code with the change to line 7 and saw In the beginning there was nothing, in the end there will be nothing. I fully expected line 6 to be ignored (as it was in the original code) and see "alpha" and "omega" in the output. Instead, I created by own Frankenstein and got stumped by my own brainteaser! I'll do my best to explain what's going on. Remember that this applies only to Perl version 5.005.

To understand this mystery, throw in print "@_"; between lines 6 and 7. Ah ha! We now see that the two elements of "@_" are no longer 'alpha' and 'omega' but are 'nothing' and 'nothing'. From this we can only conclude that line 6, $_ = qw(nothing nothing);, is assigning its list to "@_". But how? Why does assigning something to the "$_" scalar variable in line 6 affect the "@_" array variable? Let's see if we can't isolate the problem further:

That "$_" variable is a little scary to me. Who knows what built-in magical functions it might harbor? Let's get rid of it. Keep the last change you made (assuming you did) of adding print "@_"; to the code. Now change line 6 from $_ = qw(nothing nothing); to my $hello = qw(nothing nothing);. Run the program. Interesting! We see that our line 7, print "@_"; still gives us 'nothing' and 'nothing'. From this we can deduce that something funny is going on with the qw function. Hang in there, we're almost home!

This sounds like a case for perldoc to help us solve. So we consult perldoc and get the following on our prime suspect, qw: qw is equivalent to splitting a single-quoted string on whitespace. Ah ha! So qw behaves a little differently than we thought. The qw funtion is really a split function in disguise!!!

So let's consult the perldoc again and see if we can't find out about our new suspect. And there in the second paragraph of the split function "Description" we find: "If split is used not in list context, split returns the number of fields found and splits into the @_ array....The use of implicit split to @_ is deprecated, however, because it clobbers your subroutine arguments." Well, what do you know? "Clobbering" our subroutine argument sounds exactly like what happened to us!

So, in essence, what happened is that when we used qw in a scalar context, it called the split function which returned the number '2' and assigned it to our scalar variable. (You can see this for yourself if you print out the contents of "$_".) The split function, used in this scalar context, also rudely dumped its contents into our "@_" variable. And so this is why we see 'nothing' and 'nothing' popping out of our subroutine. Got it?

Version 5.6 Behavior Version 5.6 makes things a whole lot easier to explain. It appears that the qw function never calls on the split function to do its work. I confirmed this by checking out http://www.perldoc.com/perl5.6/pod/perldelta.html. Indeed, it says the following: The qw// operator is now evaluated at compile time into a true list instead of being replaced with a run time call to split(). This removes the confusing misbehaviour of qw// in scalar context, which had inherited that behaviour from split(). So now, when you run this script under Perl 5.6, you will get:

"In the beginning there was alpha, in the end there will be omega."

And there you have it!


In reply to Re: NEWBIE Brain Teaser #2, by nysus by nysus
in thread NEWBIE Brain Teaser #2, by nysus by nysus

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!
  • 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, 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, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • Outside of code tags, you may need to use entities for some characters:
            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.
  • Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others taking refuge in the Monastery: (10)
    As of 2014-10-20 13:16 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      For retirement, I am banking on:










      Results (76 votes), past polls