in reply to Perl scoping not logical...?

I'm afraid my post will be full of don'ts.

First, don't use subroutine prototypes! They are NOT what you seem to think they are. Prototypes are NOT designed to let you specify and test the number of parameters passed to a subroutine, they are designed to let you instruct the parser to parse the code in a different way, to emulate the behaviour of some builtins or add something that looks like statements instead of normal functions. Drop them! And especialy do drop them when declaring unamed subroutines, they can't ever mean anything there.

Second, don't put one named subroutine inside another! If you need two subroutines to share a variable, you should do it like this:

{ my $shared; sub foo { ... $shared++; .. } sub bar { ... print "Foo called $shared times.\n"; } }
In this case keep in mind that all, even recursive invocations of the subroutines share the same variable(s)!

If you do want a subroutine that has access to the current invocation's lexical variables, you have to use an unnamed subroutine.

Imagine this:

sub foo { my $i = shift; return if $i <= 0; sub printFoo { print "The \$i=$i\n"; } printFoo(); foo($i-1); }
Now, which $i should the printFoo access? Keep in mind that if you call foo(4), then the first $i gets set to 4, the foo(3) gets called, another $i is set to 3, foo(2) is called ... so at some point you have 5 different $i variables! Also, the named procedure, even though it was written inside the curlies of another subroutine is NOT local to that subroutine! So what $i do you want to use when I call printFoo() directly?

BTW, why do you even bother declaring the do_pkg_need_from_Dist() subroutine if you call it just once? If you did declare it outside the process_need_from_Dist() I could understand that you want to simplify the code by extracting and naming one part of it, but since the body of the do_pkg_need_from_Dist() is inside the process_need_from_Dist(), this can't be the reason.

Replies are listed 'Best First'.
Re^2: Perl scoping not logical...?
by perl-diddler (Chaplain) on Apr 28, 2008 at 00:08 UTC
    ...You ask why declaring if I call once...it *IS* to simplify it.

    What I wanted (and have used in other languages) is lexically scoped, named subroutines. That' perl makes all named subs global is related to it coming from being an unstructured, 'batch' language with no subroutines, and only global variables. We have lexically named variables, but sub's starting from a more primitive place than variables did (vars at least existed, while subs didn't), aren't yet at the place where one can use lexically named subs.

    For *me*, (and this is for me), having the subroutine internal to the only subroutine that is using it makes it more clear. I know -- unquestionably, that the routines are intimately related and shouldn't be considered for separate use unless they are further refined. At a glance, I can see what routines are only used by 1 routine.

    Normally when one makes a change in a large program, you need to be sure that the changes you are making to a subroutine won't cause some other place in the code to break because they had different expectations about what the sub was to return or "do". I don't do it as often in perl (because I have to go through the var->anonsub(args) ) and don't normally have the luxury of so finally tuning code at that level.

    But you can't argue that that local-subs aren't more clear unless you also want to argue that locally declared variables are not better (for the same clarity reason, among others) than global variables.

    I've used (and use) the structure you mentioned about having multiple subs in outer layers of braces. But in some instances, (like this one), the subroutine came from inline in the same routine -- and wasn't envisioned as a "co-routine", but a sub-function that I desire to be both named and treated as a lexical variable. As I replied elsewhere, above, something like a my sub foobar() {....}; that has the same lexical rules as variables in the same scope. So...yeah... I currently *can't* have lexical named subs, but that doesn't mean that this is a "good" thing. :-) It is possible for perl5 to evolve beyond where it's at now isn't it?

    As for the types -- I think they catch my typing errors when I'm writing my code before the typing information is stripped off and thrown away by making the calls indirect. And I rely on them altering the code in some places (though not in the code snipplet posted). But it's hard to write a "push" operator that doesn't use "\@" as its first parameters. Beyond that, even though I know the types aren't used on funcs I create as objects, I find the prototypes useful, at least during development, as documentation.

    In fact I find it quite annoying that there isn't an _option_ for stronger typing -- in the same way that many people would be upset if the "-w" flag and "use strict" were no longer around. But that's just me -- and not every program nor all the time...but sometimes it's annoying.

    It's inconvenient that the types that exist are so disparaged that common modules like "Exporter" don't even work right with typed modules without some special handling. So of course types become more of a problem because no one uses them or tests to see that their code could work with them. So that types "cause problems" becomes a self-created and self-fulfilling prophecy. Oh well... :-/

      But you can't argue that that local-subs aren't more clear unless you also want to argue that locally declared variables are not better (for the same clarity reason, among others) than global variables.

      Sure you can, unless you're in the habit of writing to global subs. Global state isn't the problem. Mutable global state is the problem.

      Localy declared subroutines might make the code clearer if they were visualy separated from the rest of the code of the subroutine and if they were used more than once within the subroutine.

      Otherwise they just confuse the flow.

      If you need another variable scope, a block is enough. In Perl lexical (my) variables are block scoped, not subroutine scoped. And if you want to "name" the block, use a comment.

      Subroutine prototypes are NOT subroutine types! Please read When to use Prototypes? and Far More Than Everything You've Ever Wanted to Know about Prototypes in Perl.

      I understand the desire to test types of variables and subroutines at compile time, but it's not possible in Perl5. Mostly.