From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 19209 invoked by alias); 24 Mar 2011 02:05:17 -0000 Mailing-List: contact zsh-users-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Users List List-Post: List-Help: X-Seq: 15885 Received: (qmail 906 invoked from network); 24 Mar 2011 02:05:15 -0000 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.1 Received-SPF: none (ns1.primenet.com.au: domain at brasslantern.com does not designate permitted sender hosts) MIME-Version: 1.0 In-Reply-To: <4D8A810A.3050300@necoro.eu> References: <4D8A810A.3050300@necoro.eu> Date: Wed, 23 Mar 2011 18:41:46 -0700 Message-ID: Subject: Re: Local inner functions From: Bart Schaefer To: Zsh Users Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable On Wed, Mar 23, 2011 at 4:23 PM, Ren=E9 'Necoro' Neumann = wrote: > > foo () > { > =A0 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=3Dfoo () { local x=3Dbar 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.)