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

Uses of "anonymous functions"

A few releases ago, zsh introduced what it calls "anonymous functions".
These aren't closures in the sense of anonymous functions in a number
of other languages; rather, they're nameless function scopes that are
executed as soon as they are defined.  It's a lot like writing in Perl:

    &{sub { print "this happens immediately!\n" }};

The most interesting uses of these nameless scopes are to control the
extents of option settings and of local variables.

For example, one issue in zsh has always been how to write a generic [*]
shell function that sets an option in the caller's scope.  If you start
such a function with "emulate zsh", then you set too many options in
the calling scope.  If instead you start with "emulate -L zsh" then
you are prevented from setting any options in calling scope.  With a
nameless scope, you can apply emulation and other options exactly where
you need them:

    if (){ emulate -LR zsh; setopt extendedglob;
           [[ $1 = (#b)no([:IDENT:]##) ]] }
    then unsetopt ${match[1]}

(This doesn't create a function named "if" because "if" is a keyword.)

As another example, suppose you want to read a script file written for
a POSIX shell, but which you know references a variable such as $argv
that has special meaning to zsh.  You don't want to unset argv in the
current scope, because that will have the side-effect of deleting the
values of $* and $@.  Nameless scope to the rescue:

    (){ local argv; unset argv; emulate sh -c '. posix_script' }

Like any shell function, the nameless scope will have the same return
status as the last command it executes, so $? will have the same value
as if ". posix_script" had been executed directly.  The problem does
remain, though, that any "typeset" commands in the posix_script will
create locals in the nameless scope, so keep that in mind.

As a final example, consider the "trap" command.  Signal handlers
defined with "trap" have a number of properties that differ from those
defined by a TRAP* function, most importantly the treatment of their
return status and that "trap" handlers are reset within subshells.  On
the other hand, "trap" handlers execute in the context of their caller.
If you want the former behaviors but not the latter:

    trap '(){ print -l $zsh_eval_context }' ALRM

You can set TMOUT=5 in an interactive shell to see this in action.
Compare to each of:

    TRAPALRM() { print -l $zsh_eval_context }
    trap 'print -l $zsh_eval_context' ALRM

What other good uses of "anonymous functions" have you thought of?

[*] I would say "portable" but what I mean is a function that works in
zsh no matter what setopts the caller has used, not a function that works
in a variety of POSIX-like shells.

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