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

I just wanted to make sure that I understood what was going on here...

(these are set up for a win32 shell, change your quotes to single ticks to run on UNIX...)
perl -e "print eval qq/require DBI; DBI::SQL_VARCHAR/ || $@;" >>> prints 'DBI::SQL_VARCHAR' perl -e "print eval qq/require DBI; DBI::SQL_XVARCHAR/ || $@;" >>> prints 'DBI::SQL_XVARCHAR' perl -e "print eval qq/require DBI; DBI::SQL_VARCHAR()/ || $@;" >>> prints '12' perl -e "print eval qq/require DBI; DBI::SQL_XVARCHAR()/ || $@;" >>> prints 'Can't locate auto/DBI/SQL_XVARCHA.al...' perl -e "$it=q/SQL_VARCHAR/; print eval qq/require DBI; DBI::$it/ || $ +@;" >>> prints 'DBI::SQL_VARCHAR' perl -e "$it=q/SQL_VARCHAR/; print eval qq/require DBI; DBI::$it()/ || + $@;" >>> prints '12' perl -e "$it=q/SQL_XVARCHAR/; print eval qq/require DBI; DBI::$it/ || +$@;" >>> prints 'DBI::SQL_XVARCHAR' perl -e "$it=q/SQL_XVARCHAR/; print eval qq/require DBI; DBI::$it()/ | +| $@;" >>> prints 'Can't locate auto/DBI/SQL_XVARCHA.al...'
Since I'm using an eval "" instead of an eval {}, it's a run-time evaluation (and by that I mean that it's parsed at runtime, whereas eval {} has the opportunity to parse some/all of your eval {} statement at compile time).

So, if eval "" finds something in there that doesn't look like a function call or a variable, it appears to treat it as a raw string. (The '()' at the end of the constant will make it look like a function)

I kinda expected it to complain about a bareword, or to actually go resolve the bareword as a constant, though. My only insight to this, is that eval() translates barewords into strings themselves, instead of being left as barewords. In other words,
eval "DBI::SQL_VARCHAR"; # is the same as $it='DBI::SQL_VARCHAR'; eval { $it };
Am I off-base here? Is that the way it works, or is something else going on here?

This seems like a case where DWIM didn't seem work for me... ;)

-Dave

Replies are listed 'Best First'.
Re: runtime eval() and constants
by Abigail-II (Bishop) on Dec 08, 2003 at 16:40 UTC
    I kinda expected it to complain about a bareword,
    You didn't even give perl a -w option, so it's no wonder you don't get warnings. However, be glad Perl won't warn about barewords when the bareword looks like a package name, or otherwise you'd get lots of warnings when constructing objects or calling class methods.
    go resolve the bareword as a constant,
    Note that if you require a module, it won't get executed until run time, so constants won't be made or exported until run time. Hence, if you do:
    eval "require DBI; DBI::SQL_VARCHAR";
    perl will compile DBI::SQL_VARCHAR as being a string before DBI.pm is executed (which will export the DBI::SQL_VARCHAR "constant".

    Note that this isn't anything special about "eval". It just has to do with the order in which things are compiled/run.

    Abigail

      perl will compile DBI::SQL_VARCHAR as being a string before DBI.pm is executed (which will export the DBI::SQL_VARCHAR "constant".
      Ah, yes, that's what I thought was happening.

      Just for reference -- I intentionally used 'require' because eval() will capture the die() generated from a require statement, if it can't find the module. If you eval{ use Blah }, then you don't get the opportunity to capture that die().

      I also discovered that I could have two separate evals, one for the require, and then one for the constant. However, it seemed more efficient to me to put them both into one eval(). It works too, so long as I keep the compliation order in mind...

      Thanks for all of the good feedback :)

      -Dave
Re: runtime eval() and constants (order)
by tye (Sage) on Dec 08, 2003 at 16:38 UTC

    s/require/use/g or move the 'require' outside of the eval and you'll get more of what you expected. BAREWORD only turns into a call to the BAREWORD subroutine if the subroutine is defined when the BAREWORD code is compiled. In your examples, the require and BAREWORD statements are compiled first, then the require is run (which finally defines the BAREWORD() subroutine) -- so the subroutine isn't defined when the BAREWORD statement is compiled.

    Update: And if you want it to complain about barewords, then you need to use strict.

                    - tye
Re: runtime eval() and constants
by holo (Monk) on Dec 08, 2003 at 16:36 UTC

    That's so that you can write:

    package Some::Module;

    instead of:

    package "Some::Module";

    Bow before you ;)

      Eh, no. package and require are special cased - their arguments won't trigger the "unquoted string" warning. But it does matter for method calls:
      $ perl -wce 'require foo' -e syntax OK $ perl -wce 'package foo' -e syntax OK $ perl -wce 'foo -> method' Unquoted string "foo" may clash with future reserved word at -e line 1 +. -e syntax OK $ perl -wce 'Foo -> method' -e syntax OK
      It also matters for filehandles:
      $ perl -wce 'print Foo' Name "main::Foo" used only once: possible typo at -e line 1. -e syntax OK $ perl -wce 'print foo' Unquoted string "foo" may clash with future reserved word at -e line 1 +. Name "main::foo" used only once: possible typo at -e line 1. -e syntax OK

      Abigail

        Note that a bareword before the -> is subject to interpretation as a function call if there is such a function:
        $ perl -we'sub Foo { "Bar" } Foo -> method' Can't locate object method "method" via package "Bar" (perhaps you for +got to load "Bar"?) at -e line 1.
        You can force its interpretation as a class name by saying Bar::->method (no, that doesn't call &Bar:: even if you go out of your way to define such an evilly named sub) or "Bar"->method.

        In a module or in a program using other's modules, you should do this all the time. After all, your code may have done use Some::Module and established a contract with that module, but when you say Some::Module->classmethod you are implicitly making an assumtion about the module Some, which you have no arrangement with.