Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Local inner functions



On Wed, Mar 23, 2011 at 4:23 PM, René 'Necoro' Neumann <lists@xxxxxxxxx> wrote:
>
> foo ()
> {
>   bar () { }
> }
>
> Is there some way of making 'bar' to be local to 'foo'? Using the
> 'local' keyword does not work :).

The short answer is "no."  And you can't make local aliases either.

The slightly longer answer is that there are a couple of ways to fudge
it, of varying degrees of hackishness.

The first and least hackish is to use an "anonymous" function (which,
it has been pointed out elsewhere, are slightly misnamed because
they're not true closures):

foo() {
  local x=foo
  () {
    local x=bar
    print "Look, it's a nested scope: $x"
  }
  print "Back in the function scope: $x"
}

However, this only works when the inner scope needs to be called in
only one place, that is, you don't need to refer to it by name or pass
it arguments.  It's called immediately as soon as it's defined.

Alternately, as you mentioned, you can define your functions and then
unfunction them again.  If you employ an "always" block there
shouldn't be any situation where this doesn't work, but it does mean
you have to avoid name clashes.  The following assumes you setopt
FUNCTION_ARG_ZERO:

foo() {
  { # Begin "always" block
    function $0_bar {
      print "A function scope with a fudged name: $0"
    }
    print "Calling..."
    $0_bar
    print "... back in $0"
  } always {
    unfunction -m "$0_*"
  }
}

Now we reach the real hack.  If you don't care what your function is
named, you can hijack signal trapping functions for signals that it's
very unlikely your script will receive.  Examples are USR1, USR2, URG,
PWR, and SYS, but not all platforms have all those signals so in
practice you probably get only USR1 and USR2.

foo() {
  setopt localoptions localtraps
  TRAPUSR1() {
    print "A handler for a signal that never comes"
  }
  print "Calling..."
  TRAPUSR1
  print "... back in function scope"
}

The localtraps option causes the TRAPUSR1 function to be removed
automatically when the function scope ends.  It also does the right
thing if another function defines the same nested function name and
one of the two outer functions calls the other one.

(So theoretically the plumbing is all there to create local nested
functions, but the devil is in the details, as they say.)



Messages sorted by: Reverse Date, Date, Thread, Author