in reply to Re^2: parse lisp style config
in thread parse lisp style config

nested subs provide some more abstraction ability, I use it always, and I need it, as long as perl still respect scope rule. Though I did not know on which case it can break bad.

Replies are listed 'Best First'.
Re^4: parse lisp style config
by choroba (Cardinal) on Nov 28, 2024 at 14:20 UTC
    It can break bad exactly because of scope. The variables declared in the outer sub are not properly shared to the inner subs (or rather, they are shared only in the first run).
    #!/usr/bin/perl use strict; use warnings; sub outer { my ($x) = @_; sub inner { return $x + 1 } return inner() } print outer(12), "\n"; # 13 print outer(42), "\n"; # 13 !!

    Also, you'll get a warning:

    Variable "$x" will not stay shared at 1.pl line 9.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      I got the warning, if passed by arg, it's ok, thanks for explained the meaning for me.
Re^4: parse lisp style config
by ikegami (Patriarch) on Nov 28, 2024 at 15:42 UTC

    nnested subs provide some more abstraction ability

    Not in Perl.

    Whether nested or not, the following two snippets are equivalent:[1]

    sub foo { ... }
    BEGIN { *foo = sub { ... }; }

    As such,

    • Inner sub aren't scoped to outer sub.
    • It misleadingly appears the inner sub is scoped to the outer sub when they're not.
    • The inner sub can't use lexicals of the outer sub.
    • If the inner sub attempts to use lexicals of the outer sub, you get very weird and useless behaviour.
    • If the inner sub attempts to use lexicals of the outer sub, you get a warning.

    As you can see, you gain no abstraction or other benefits. Everything about it is bad.

    That said, none of this applies to lexical inner subs. This is fine:

    sub outer { ... my sub inner { ... } ... }

    1. Exception: The first has a name attached to the sub itself, while the second doesn't. This difference will affect croak and strack traces. I could have used Sub::Util's set_subname to correct this, but loading the module would introduce a new difference.
      I test to confirm it, Inner sub is not private. The only benefit may be an reminder inner sub will be only called inside.

        Just use already-mentioned my sub name { ... } instead or sub name { ... } and you will have an actual private inner sub without the drawbacks.