dsb has asked for the wisdom of the Perl Monks concerning the following question:

I started playing around with <a href-"http://www.perlmonks.org/index.pl?node=perlfunc%3Ado&lastnode_id=395>do, and the docs say:
Uses the value of EXPR as a filename and executes the contents of the +file as a Perl script. Its primary use is to include subroutines from + a Perl subroutine library. do 'stat.pl'; is just like scalar eval `cat stat.pl`;
So, I made a file named "print" with print "just another perl hacker\n"; in it...and went to work. First I tried:
do ("print"); print $!, "\n" if $!;
Which worked as expected. "just another perl hacker" was the output. Then I tried:
do print; print $!, "\n" if $!;
I expected that the argument to do would be 1, since print with or without arguments evaluates to 1. So I was expecting a No such file or directory error from $!. Didn't happen. "just another perl hacker" was output as if do saw print as a string. Wondering if that was the case, I assigned a value to $_ since print assumes $_ as its argument when none is given:
$_ = 1; do print; print "\n"; print $!, "\n" if $!;
Output was "just another perl hacker". So print is being evaluated as a string I think. Just for kicks I throw some parens around it, thinking it won't matter(since it usually doesn't), but not really knowing what to expect:
$_ = 1; do (print); print "\n"; print $!, "\n" if $!;
Finally, print is evaluated down to 1, and do assigns the long awaited "No such file or directory error" to $!, so the output is:
1
No such file or directory

So, why was print evaluated as a string when not in parens? I was under the impression that Perl would recognize it as a built in function and act accordingly. Instead it acted as if it were a bareword, and there was know pre-defined sub-routine called print. And why, in this case is there a difference in the behavior with/without parentheses?

Thanks in advance.

Amel - f.k.a. - kel

Replies are listed 'Best First'.
Re: The Behavior of 'do'
by trantor (Chaplain) on Jul 26, 2001 at 22:58 UTC

    do is a keyword (like package or use), not a function.

    In your case, print is treated as a bareword . Surely this would not be surprising if you typed

    use print;

    instead :-)

    I presume that Perl behaves in this way because it's more useful for the programmer, being more concise.

    Also rememeber that if it looks like a function call, it is a function call.

    -- TMTOWTDI

      do print;

      will evaluate print as the bareword name of a FILE and execute it.

      do (print);

      will evaluate print as a LIST and evaluate it as an EXPR, executing the print and then returning the result to do as a EXPR of 1.

      do print();

      will evaluate print as a SUBROUTINE and execute it.

      The first two cases are the file-style do, the last is the old subroutine-style do, and the block-style do has not been shown.

Re: The Behavior of 'do'
by PrakashK (Pilgrim) on Jul 26, 2001 at 23:00 UTC
    I am not well versed with the way perl parser works. But I took the help of Deparse backend and this is what it revealed.
    >> perl -MO=Deparse -e 'do ("print")' do 'print'; -e syntax OK >> perl -MO=Deparse -e 'do (print)' do print($_); -e syntax OK >> perl -MO=Deparse -e 'do print' do 'print'; -e syntax OK >> perl -MO=Deparse -e 'do{print}' print $_;; -e syntax OK
    do expects a BLOCK, SUBROUTINE (deprecated) or an EXPR as its argument. So, I am guessing that, when a BLOCK or SUBROUTINE is not passed, it is looking for an expression and probably allowing barewords.
Re: The Behavior of 'do'
by John M. Dlugosz (Monsignor) on Jul 26, 2001 at 23:20 UTC
    To recap, the construct do expression is taking the bareword print as a string, not as a call to the built-in function.

    Even more curiously, do 4; produces 1 as a result with nothing in any of the error variables, as opposed to do '4'; which looks for a file. Ditto for do 2+2 which makes me think that a numeric value is being treated differently. I don't even know what it's doing! Could it be a bug, due to common code in the implementation with use and require, which indeed mean something different with numbers? Update: yes, it is doing exactly that.

    As for barewords, others like do shift; is looking at is as a string, not a function, too.

    My guess is that, contrary to the documentation, a bareword to do is always treated as a string (even under use strict and use warnings!) like with use.

    You may want to try and see if it replaces :: with slash, like require does. It's not assuming the extension, so maybe not. But it sounds like what's happening is do/require/use is implementing some functionality at the do level, or the compiler has more in common with them than is documented.

    Hopefully, a perl porter will investigate this further. I agree, it is not behaving as documented in perlfunc and perldata. My guess: common handling with use/do/require in the parser. I'd say document the "always a string", and fix the numeric context behavior to take it as a string (it's pointless to duplicate require).

    Now, for the parens: That makes it a list. In scalar context, it gives the item count. Anything that's not a bareword is treated as a normal expression, and if non-numeric, the result of the expression names the file. —John

Re: The Behavior of 'do'
by mitd (Curate) on Jul 26, 2001 at 23:18 UTC

    now here's an interesting ditty. When I ran case 4

    $_ = 1; do (print); print "\n"; print $!, "\n" if $!;

    output:

    Perl v49.0.0 required--this is only v5.6.1, stopped at t4.pl line 2.

    'Holy Oyster Farts'

    mitd-Made in the Dark
    'My favourite colour appears to be grey.'

      On http://archive.develooper.com two bug reports (1, 2) show some other cool perl versions I cannot find anywhere on the web. ;) For instance the super cool version 123.0.0:

      # from msg53551.html jeffp@hut [1:00am] ~ #102> perl -w sub foo { print "ok\n"; 123 } do &foo; ok Perl v123.0.0 required--this is only v5.6.0, stopped (did you mean v123.0.0?) at - line 2.
      That is strange indeed. I kept experimenting and it seems when the argument to do is higher than the version of Perl running on the machine(even by fractions), that same type of error is thrown, where the 'required' version number is the same as the argument to do.
      do 5.00504; print "\n"; print $!, "\n" if $!; # output: Perl 5.00504 required--this is only version 5.00503, stopped + at do.pl line 6.
      Update: While using a number the same as the version of Perl, the only error thrown is:
      No such file or directory
      do 5.00503; print "\n"; print $!, "\n" if $!; # output: No such file or directory
      But it's good to see that a bug has been reported on that.

      Amel - f.k.a. - kel