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

Re: autoload -X inside an anonymous function

On Sep 18,  4:12am, Oliver Kiddle wrote:
} The error message is not really what you would expect:
} (eval):1: parse error near `"$@"'

Hm.  The odd bit is that it got that far.  I would have expected it
to fail because there [presumably] is no file named '(anon)' in your
$fpath.  However, looking at the code again ...

} Furthermore, running:
}   which '(anon)'
} shows that I also now have a named function named (anon).

When the -X option is passed, autoload first creates the placeholder
function definition [as if "autoload $0"] and then calls the function
[eval $0 "$@"] to trigger the actual autoload.  So the error really
is that $0 expands to "(anon)" in that context.

It's important to note that although the placeholder function appears
in "functions" output to have a body consisting of "autoload -X", that
is a convenient fiction -- functions marked for autoloading jump right
to loadautofn() without executing their body.  (The eval trick would
be an infinite loop if this were not the case.)

} The reason for the (eval) error message is that bin_eval is called to
} run the function. This looks a bit of a hack with "$@" being passed as
} an argument but also has other effects; most notable is another round
} of alias expansion but you also get '(eval)' in $funcstack.

This is a case of the implementation of autoload -X falling behind as
other changes occurred around it, though I think the only way to set
this off would be to run it from an anoynmous function as you did.
If scriptname had remained empty in anonymous functions instead of
being forced to '(anon)' for debugging/error message purposes, the
call to autoload -X would have failed with "invalid option(s)" before
reaching eval_autoload().

Aside mostly to PWS:  Is there any way to detect that you are in the
anonymous function?  (!scriptname) means you aren't in any function at
all, which is what bin_functions() is testing for.  Using strcmp() is
not ideal, since one actully is permitted to create a function named
'(anon)' [though it would be ugly/confusing to call it].

IIRC the extra pass of alias expansion was discounted because by the
time you invoke "autoload -X" you presumably have alreay reached the
function via a name that isn't an alias.

OTOH this allows for some games to be played:

--- 8< --- Put this in "autoload-from" in your normal FPATH
  local fp=$1 fn=$2
  shift 2
  builtin alias $0=$fn
  FPATH=$fp\:$FPATH builtin autoload -X
} always {
  builtin unalias $0
--- 8< ---

Now you can say stuff like

    autoload-from ~/zsh/other my_func some arguments

Of course this is just longhand for

   FPATH=~/zsh/other:$FPATH my_func some arguments

and whether it's a good idea to allow such games is entirely another

} While looking at that relevant bits of code, I also wonder whether
} the second call to eval_autoload is reachable code: no builtin using
} bin_functions allows both the -m and -X options.

It definitely is not reachable because of the test at about line 2686 in
builtin.c -- the second eval_autoload likely is there for completeness
(in case somebody later adds a builtin that allows a mass autoload).
I've on sometimes wished that "autoload -X something" would immediately
load the body of the function from the file but NOT execute it, which
would translate directly into "autoload -m -X \*" causing all the
functions that are marked for autoloading to populate themselves.

(In fact I think OPT_MINUS(ops,'X') && OPT_ISSET(ops,'m') is impossible
at line 2686 too, but redundant error-checking almost never hurt anyone.)
} Trying to think of uses for an explicitly defined call to autoload -X,
} it seems a pity you can't make it autoload a function from a differently
} named file, either by first assigning to ARGV0 or passing a parameter
} to autoload -X.

Per my remark above, I'd rather that passing arguments to -X had a bit
of a different interpretation if it has any at all, and ARGV0 needs to
retain its connection to the name of the shell itself.  However, when
the function_argzero option is set, I don't see any reason why assigning
to $0 could not change the scriptname, which would then propagate to
autoload -X.  But you want to associate a function foo with a file whose
basename is bar, whereas simply changing scriptname would actually load
bar into a new function named bar ... so we'd need to differentiate the
scriptname and the name used by loadautofn().  Hmm.

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