* static vs. dynamic scoping @ 2010-11-09 22:08 Eric Blake 2010-11-10 11:10 ` Peter Stephenson ` (2 more replies) 0 siblings, 3 replies; 9+ messages in thread From: Eric Blake @ 2010-11-09 22:08 UTC (permalink / raw) To: zsh-workers [-- Attachment #1: Type: text/plain, Size: 2383 bytes --] On the Austin Group mailing list, David Korn (of ksh93 fame) complained[1] that bash's 'local' uses dynamic scoping, but that ksh's 'typeset' uses static scoping, and argued that static scoping is saner since it matches the behavior of declarative languages like C and Java (dynamic scoping mainly matters in functional languages like lisp): [1] https://www.opengroup.org/sophocles/show_mail.tpl?CALLER=show_archive.tpl&source=L&listname=austin-group-l&id=14951 I'm trying to standardize the notion of local variables for the next revision of POSIX, but before I can do so, I need some feedback on two general aspects: 1. Implementation aspect: How hard would it be to add static scoping to zsh? 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)? If both scoping forms are supported, is it worth making the default scoping dependent on posix compliance (for example, 'local' means dynamic scoping for 'emulate zsh' but static scoping for 'emulate sh'), or should it be the same default for both modes? 2. User aspect: Is anyone aware of a script that intentionally uses the full power of dynamic scoping available through 'local' which would break if scoping switched to static? Here's a sample shell script that illustrates the difference between the two scoping methods. $ ksh -c 'function f1 { typeset a=local; f2; echo $a; }; function f2 { echo $a; a=changed; }; a=global; f1; echo $a' global local changed $ zsh -c 'function f1 { typeset a=local; f2; echo $a; }; function f2 { echo $a; a=changed; }; a=global; f1; echo $a' local changed global In static scoping, function f2 does not shadow a declaration of a, so references to $a within f2 refer to the global variable. The local variable a of f1 can only be accessed within f1; the behavior of f2 is the same no matter how it was reached. In dynamic scoping, function f2 looks up its call stack for the closest enclosing scope of a variable named a, and finds the local one declared in f1. Therefore, the behavior of f2 depends on how f2 is called. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 619 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: static vs. dynamic scoping 2010-11-09 22:08 static vs. dynamic scoping Eric Blake @ 2010-11-10 11:10 ` Peter Stephenson 2010-11-10 16:50 ` Bart Schaefer 2010-11-10 17:22 ` Bart Schaefer 2 siblings, 0 replies; 9+ messages in thread From: Peter Stephenson @ 2010-11-10 11:10 UTC (permalink / raw) To: zsh-workers I might as well copy what I sent to the Austin group list this morning for the majority not following that... The "other" matters referred to are, to summarise very briefly, basically whether foo="a b" export x=$foo causes x to be set to "a b". Currently POSIX implies it doesn't. From: Peter Stephenson <pws@csr.com> To: austin-group-l@opengroup.org Subject: Re: Word splitting in 'export' arguments and adding local Date: Wed, 10 Nov 2010 10:13:20 +0000 On Tue, 09 Nov 2010 22:34:22 -0500 Chet Ramey <chet.ramey@case.edu> wrote: > Bash uses dynamic scoping and, as I have existing users and scripts > that take advantage of it, I have no intention of changing that. I > know zsh uses dynamic scoping and there are scripts that make > extensive use of it. That's correct about zsh: the completion functions supplied with the shell rely (very) heavily on dynamic scoping and we certainly wouldn't be changing that. I can't see any likelihood of writing a completely different additional implementation of local variables with static scoping for POSIX mode. It might be possible as an option to hide and uncover variables when entering nested functions to simulate static scoping without a complete rewrite, but I really haven't thought it through and it's not likely to be a high priority. It might also be worth reminding people that POSIX support was rather an afterthought for zsh but we try to keep that mode working where possible. I don't think any of the other matters being discusses here are a big issue for zsh in POSIX mode, however. If you happen to be investigating this in zsh, the following options are relevant: SH_WORD_SPLIT turn on splitting of substitutions as done by default in other shells KSH_TYPESET turn off argument splitting on assignments for typeset, local, etc. if SH_WORD_SPLIT is on. Note this is not turned on automatically in POSIX mode (for reasons anyone following this thread will realise). MAGIC_EQUAL_SUBST ~-expansion (and zsh-specific =-expansion, if applicable) are active after all "=", and also after following :, regardless of the command. The example in the manual is echo foo=~/bar:~/rod expands both ~'s. The effect of this option has expanded somewhat during the life of zsh. (I'm not suggesting this would ever be POSIX-compatible.) pws Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: static vs. dynamic scoping 2010-11-09 22:08 static vs. dynamic scoping Eric Blake 2010-11-10 11:10 ` Peter Stephenson @ 2010-11-10 16:50 ` Bart Schaefer 2010-11-10 17:28 ` Eric Blake 2010-11-10 17:22 ` Bart Schaefer 2 siblings, 1 reply; 9+ messages in thread From: Bart Schaefer @ 2010-11-10 16:50 UTC (permalink / raw) To: Eric Blake, zsh-workers 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. } If both scoping forms are supported, is it worth making the default } scoping dependent on posix compliance (for example, 'local' means } dynamic scoping for 'emulate zsh' but static scoping for 'emulate sh'), } or should it be the same default for both modes? As it'd probably be controlled by an option, this probably doesn't change the difficulty either way. ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: static vs. dynamic scoping 2010-11-10 16:50 ` Bart Schaefer @ 2010-11-10 17:28 ` Eric Blake 2010-11-10 17:43 ` Eric Blake 2011-05-29 6:38 ` Thorsten Glaser 0 siblings, 2 replies; 9+ messages in thread From: Eric Blake @ 2010-11-10 17:28 UTC (permalink / raw) To: Bart Schaefer; +Cc: zsh-workers, austin-group-l [-- Attachment #1: Type: text/plain, Size: 5025 bytes --] 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@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 619 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: static vs. dynamic scoping 2010-11-10 17:28 ` Eric Blake @ 2010-11-10 17:43 ` Eric Blake 2011-05-29 6:38 ` Thorsten Glaser 1 sibling, 0 replies; 9+ messages in thread From: Eric Blake @ 2010-11-10 17:43 UTC (permalink / raw) Cc: Bart Schaefer, zsh-workers, austin-group-l [-- Attachment #1: Type: text/plain, Size: 736 bytes --] On 11/10/2010 10:28 AM, Eric Blake wrote: > 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). 'typeset', not 'typedef', throughout that paragraph. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 619 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: static vs. dynamic scoping 2010-11-10 17:28 ` Eric Blake 2010-11-10 17:43 ` Eric Blake @ 2011-05-29 6:38 ` Thorsten Glaser 1 sibling, 0 replies; 9+ messages in thread From: Thorsten Glaser @ 2011-05-29 6:38 UTC (permalink / raw) To: Eric Blake; +Cc: Bart Schaefer, zsh-workers, austin-group-l Eric Blake dixit: >require that 'typedef' used without options and within a function body >provide a statically scoped local variable. Possible require a few I'd very much like to avoid changing the scoping model of mksh, and request that this not be standardised on. This is both from an implementors and users point of view. Thanks, (and thanks to pgas for pointing out this thread) //mirabilos -- 22:20⎜<asarch> The crazy that persists in his craziness becomes a master 22:21⎜<asarch> And the distance between the craziness and geniality is only measured by the success 18:35⎜<asarch> "Psychotics are consistently inconsistent. The essence of sanity is to be inconsistently inconsistent ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: static vs. dynamic scoping 2010-11-09 22:08 static vs. dynamic scoping Eric Blake 2010-11-10 11:10 ` Peter Stephenson 2010-11-10 16:50 ` Bart Schaefer @ 2010-11-10 17:22 ` Bart Schaefer 2010-11-10 17:30 ` Eric Blake 2 siblings, 1 reply; 9+ messages in thread From: Bart Schaefer @ 2010-11-10 17:22 UTC (permalink / raw) To: Eric Blake, zsh-workers One additional thought on this ... Zsh does have the "-g" option of "typeset" to allow one declare or to change the properties of a variable that is not in the scope of the current function. However, "-g" doesn't really mean "global"; it means only "the nearest dynamic scope where this variable is already declared" which is the global scope if the parameter has never been declared, but might even be the current scope if there has previously been a "local" delcaration of the variable. Does ksh93 have any mechanism for explicitly declaring a variable to be global from inside a function scope? -- ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: static vs. dynamic scoping 2010-11-10 17:22 ` Bart Schaefer @ 2010-11-10 17:30 ` Eric Blake 2010-11-10 18:01 ` Bart Schaefer 0 siblings, 1 reply; 9+ messages in thread From: Eric Blake @ 2010-11-10 17:30 UTC (permalink / raw) To: Bart Schaefer; +Cc: zsh-workers [-- Attachment #1: Type: text/plain, Size: 1291 bytes --] On 11/10/2010 10:22 AM, Bart Schaefer wrote: > One additional thought on this ... > > Zsh does have the "-g" option of "typeset" to allow one declare or > to change the properties of a variable that is not in the scope of > the current function. However, "-g" doesn't really mean "global"; > it means only "the nearest dynamic scope where this variable is > already declared" which is the global scope if the parameter has > never been declared, but might even be the current scope if there > has previously been a "local" delcaration of the variable. > > Does ksh93 have any mechanism for explicitly declaring a variable to > be global from inside a function scope? I'm not that familiar with ksh93; you'd have to ask David Korn for precise details. But my understanding is that with static scoping, every variable reference which was not explicitly declared local is inherently global, because there are no other scopes to worry about. That is (assuming ksh were to support local scoping with posix syntax functions): f () { a=1 # modify the global variable a typeset a; a=2 # modify the function-local a } a=0; f; echo $a # outputs 1 -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 619 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: static vs. dynamic scoping 2010-11-10 17:30 ` Eric Blake @ 2010-11-10 18:01 ` Bart Schaefer 0 siblings, 0 replies; 9+ messages in thread From: Bart Schaefer @ 2010-11-10 18:01 UTC (permalink / raw) To: Eric Blake; +Cc: zsh-workers On Nov 10, 10:30am, Eric Blake wrote: > > I'm not that familiar with ksh93; you'd have to ask David Korn for > precise details. But my understanding is that with static scoping, > every variable reference which was not explicitly declared local is > inherently global, because there are no other scopes to worry about. Right, and that works fine for simple assignments and for expansion. I'm curious about what happens when you want to declare something not-static but also not a simple scalar, e.g. f() { # Is there any way to make these global? typeset -i4 an_int typeset -u all_upper } ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2011-05-29 6:51 UTC | newest] Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2010-11-09 22:08 static vs. dynamic scoping Eric Blake 2010-11-10 11:10 ` Peter Stephenson 2010-11-10 16:50 ` Bart Schaefer 2010-11-10 17:28 ` Eric Blake 2010-11-10 17:43 ` Eric Blake 2011-05-29 6:38 ` Thorsten Glaser 2010-11-10 17:22 ` Bart Schaefer 2010-11-10 17:30 ` Eric Blake 2010-11-10 18:01 ` Bart Schaefer
Code repositories for project(s) associated with this public inbox https://git.vuxu.org/mirror/zsh/ This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).