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

I would like to write a function which takes a a Perl block (not anonymous sub) and evaluates it in a context in which it can access a lexically scoped variable called file. Here is my attempt:
sub x { my $coderef = shift; use Data::Dumper; Data::Dumper->Dump([$coderef],['coderef']); { my $file = 'hoho.txt'; $coderef->(); } } $sub = sub { print "$file.YYY" } x $sub;

I am told "not a CODE reference at line 9" (the line where I attempt to dereference what I had hoped would be a code reference.

Replies are listed 'Best First'.
Re (tilly) 1: passing and processing code references
by tilly (Archbishop) on Oct 11, 2000 at 17:04 UTC
    Why would you like to do this?

    You could take a string and do an eval on it. That will be slow, can lead to an unmaintainable design, etc, but you can.

    However I would strongly prefer using an anonymous function and I am curious why you do not. Remember, focus on what it is that you want to accomplish, not how you want to accomplish it. So make it be an anonymous function, and either use local on $file, or pass it as an argument to the function.

    Personally I would pass it as an argument. If I want flexibility, then pass a hash of arguments...

      What's wrong with a Perl block? grep takes a block. Here's the answer:
      sub x(&) { my $coderef = shift; use Data::Dumper; print Data::Dumper->Dump([$coderef],['coderef']) +; { $_ = 'bumpkin'; $coderef->(); } } x { print "$_.YYY" };
        Several things are wrong wth a Perl block done that way.

        First of all read FMTEYWTK About Prototypes In Perl. Everything in there about prototypes applies. I don't like them, and don't like them for a reason.

        Secondly you now have order of declaration issues. If the prototype is not declared before the code that you use, then it works one way. If it is then it works another.

        Thirdly what happens later when you want to modularize, move code elsewhere and import with Exporter? If you move code from one package to another, then code that had worked through setting a global will break because the global is in the wrong blockpackage (minor fix, sorry). Do you have a guru on staff? Because most people are unlikely to look at that problem and know to check caller and mess with globals in your caller's namespace. (And games like that quickly leads to messes.) Oh, but you tested with $_ (which you didn't localize I note) which is always in package main. So your tests wouldn't pick that up. The moral? Don't use special variable names for testing scoping issues!

        Fourth Tom C mentioned bugs with the & prototype. What kind of bugs you ask? Well there is a deep problem with braces being overloaded. They can be interpreted as a block to be turned into an anon sub, a block to execute inline, or an attempt to produce an anonymous hash. Mix this with disambiguating core functions from user functions and you get quite a mess of potential ambiguities to parse! Yes, I know that some core functions do this already. But the list of ones that do is small, and there is no ambiguity between them being core and user. Like globals, special behaviour is OK in controlled amounts but should not be used throughout your design at risk of insanity.

        Now all of this is what you lose, what do you gain?

        Being able to omit 4 characters. Just type "sub " in front of your block and it works without prototypes. Without parsing ambiguity. Without declaration issues. OK, so if you use globals then you are still in trouble, but an ever-expanding web of globals to keep track of is a sign of a poorly thought through design.

Re: passing and processing code references
by Anonymous Monk on Oct 11, 2000 at 16:50 UTC
    ELABORATION I would like to be able to do this (just like calling Perl's grep function:
    x { print "$file.YYY" }

    I dont want to have to bother with creating an anonymous subroutine.

      I dont want to have to bother with creating an anonymous subroutine.
      This kind of comment always puzzles me. Why would you bother exclude a probably conveninet solution to your problem without any specific reason? In this case what's wrong with anonymous subroutines? If there is a good reason please elaborate. That might give us some food for thought. Otherwise I don't really want to bother going through arbitrary hoops just for the sake of it.

      Just my 0.0229 Euro rant