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

Re: static vs. dynamic scoping

On 11/10/2010 09:50 AM, Bart Schaefer wrote:
> On Nov 9,  3:08pm, Eric Blake wrote:
> }
> } 1. Implementation aspect:
> }   How hard would it be to add static scoping to zsh?
> Just to elaborate on this, as I've been fooling with parameter scopes a
> bit lately (http://www.zsh.org/mla/workers//2010/msg00719.html) ...
> Zsh currently maintains scopes as [what amounts to] a parallel stack
> alongside the function call stack, with scope depth indexed by the
> call stack depth.  A variable expansions finds its object at the
> uppermost frame of the scope stack in which that variable's name has
> been "mentioned" with either typeset/local/declare or undef; if it is
> not found at all, assignment creates it in the global frame.  Note,
> though, that the global frame is simply the bottom of the stack, not
> handled separately except for some special cases for stack depth 0.
> Therefore it's at least moderately difficult to add static scoping.
> }   Is it something that can be added in addition to dynamic scoping, via
> } the use of an option to select the non-default mode (for example, 'local
> } -d' to force dynamic, 'local -s' to force static, and 'local' to go with
> } default scoping)?
> It might be possible to flag a variable in a given frame as static and
> thereby cause it to be skipped when the current call depth does not
> match the stack depth where the variable was "mentioned", but due to
> the details of the implementation [*] I can't think of any reasonable
> way to mark entire frames static or dynamic as implied by having two
> different function styles.  Maybe that doesn't matter as long as all
> undeclared variables in either kind of scope are global, because then
> the state of the frame matters only when "local" is used in that frame.
> [*] Cf. "what amounts to" -- in reality, every variable has its own
> independent stack which comes into being only when the variable is
> "mentioned", so that it's not necessary to walk the stack to find
> the uppermost frame for a given variable.

You are correct that ksh93 currently has two flavors of functions:

POSIX functions 'f () {...}', currently no scoping support
ksh functions 'function f {...}', supports static scoping

But I see no need to standardize on this.  My current thoughts for POSIX
standardization are:

keep a single function syntax (ksh can continue to use 'function' as a
reserved word, and with alternate function syntax, but that would be an
extension and not mandatory; bash can continue to use function as an
alternate spelling for POSIX functions without the split in
functionality used by ksh)

provide the 'typeset' special built-in, which is required to obey XBD
12.2 (that is, it must honor --), so as to allow implementations to
support extensions such as 'typeset -a' for declaring array variables

require that 'typedef' used without options and within a function body
provide a statically scoped local variable.  Possible require a few
other commonly implemented 'typedef -X' options, such as 'typedef -p'
for printing the current set of locally scoped variables (much like
'export -p).

only require static scoping (for ksh93), but additionally allow dynamic
scoping as an extension (this would be the course used by bash and zsh,
to preserve their current user base of tab-completion that expects
dynamic scoping)

continue to allow the ksh extension of reference variables (since ksh
uses this in in lieu of dynamic scoping for exposing local variables to
secondary functions), although I don't see this implemented in bash or zsh

For implementations that want to provide static and dynamic scoping
simultaneously (bash, zsh), I think the following implementation would
do just fine:
 + Create two variants of 'local': 'local -d' for dynamic scoping, and
'local -s' for static scoping (which version was used determines whether
a variable is marked as static on the variable stack).  For backwards
compatibility, 'local' becomes 'local -d'.
 + Make 'typedef' become a synonym for 'local -s' (or keep 'typedef' as
a synonym for 'local', and add a a shell option that determines whether
'local' defaults to 'local -d' or 'local -s', where that option is
auto-set according to posix mode)
 + Within a function, when referencing a variable:
   + if the variable was declared within that function, use it (doesn't
matter whether it was declared with 'local -s' or 'local -d')
   + if the variable was not declared within that function, then travel
up the variable declaration stack to the first instance of the variable
that was not marked static (if the script only uses static scoping, then
this requires traversing the entire stack of variables, but will settle
on the global scope; if the script only uses dynamic scoping, then this
will find the very first variable on the stack)

Eric Blake   eblake@xxxxxxxxxx    +1-801-349-2682
Libvirt virtualization library http://libvirt.org

Attachment: signature.asc
Description: OpenPGP digital signature

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