zsh-users
 help / color / mirror / code / Atom feed
* Load autoloadable function, but only in enclosing function scope
@ 2022-03-24 16:12 Zach Riggle
  2022-03-24 16:29 ` Mikael Magnusson
  0 siblings, 1 reply; 7+ messages in thread
From: Zach Riggle @ 2022-03-24 16:12 UTC (permalink / raw)
  To: Zsh Users

[-- Attachment #1: Type: text/plain, Size: 144 bytes --]

Is there a way to

myfunc() {
    autoload foo && foo
}

Such that foo and any other functions it declares are local-scope only?

*Zach Riggle*

[-- Attachment #2: Type: text/html, Size: 425 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Load autoloadable function, but only in enclosing function scope
  2022-03-24 16:12 Load autoloadable function, but only in enclosing function scope Zach Riggle
@ 2022-03-24 16:29 ` Mikael Magnusson
  2022-03-24 17:05   ` Peter Stephenson
  0 siblings, 1 reply; 7+ messages in thread
From: Mikael Magnusson @ 2022-03-24 16:29 UTC (permalink / raw)
  To: Zach Riggle; +Cc: Zsh Users

On 3/24/22, Zach Riggle <zachriggle@gmail.com> wrote:
> Is there a way to
>
> myfunc() {
>     autoload foo && foo
> }
>
> Such that foo and any other functions it declares are local-scope only?

Functions are never scoped at all, so no. You can manually unfunction
it afterwards (if there was already a function with a conflicting
name, autoload returned success and you ran the wrong function
anyway). If you don't need any other side effects from myfunc, you can
run the whole thing in a subshell of course.

-- 
Mikael Magnusson


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Load autoloadable function, but only in enclosing function scope
  2022-03-24 16:29 ` Mikael Magnusson
@ 2022-03-24 17:05   ` Peter Stephenson
  2022-03-24 17:51     ` Bart Schaefer
  0 siblings, 1 reply; 7+ messages in thread
From: Peter Stephenson @ 2022-03-24 17:05 UTC (permalink / raw)
  To: Zsh Users

> On 24 March 2022 at 16:29 Mikael Magnusson <mikachu@gmail.com> wrote:
> On 3/24/22, Zach Riggle <zachriggle@gmail.com> wrote:
> > Is there a way to
> >
> > myfunc() {
> >     autoload foo && foo
> > }
> >
> > Such that foo and any other functions it declares are local-scope only?
> 
> Functions are never scoped at all, so no. You can manually unfunction
> it afterwards (if there was already a function with a conflicting
> name, autoload returned success and you ran the wrong function
> anyway). If you don't need any other side effects from myfunc, you can
> run the whole thing in a subshell of course.

With that key limitation --- if you've already got functions with the
names of the ones you're creating, you're stuffed --- you can automate
it like this.

fn() {
  local -a oldfuncs=(${(k)functions})
  {
    # as a working example --- "autoload subfunc" would work fine
    subfunc() { print This is subfunc; }
    subfunc
  } always {
    local -a funcs=(${(k)functions:|oldfuncs})
    (( ${#funcs} )) && unfunction $funcs
  }
}

Note that this won't unfunction subfunc even if it was previously
marked for autoload, but not actually loaded.  (In any case
you'd probably want to mark it for autoload again, to be consistent,
so that's an exercise for the reader.)

If your functions are all being autoloaded, and your only interest
is in getting rid of functions that you've autoloaded specially for
this function --- so there's no actual name clash, you just might have
already marked the function for autoload and it'll stay loaded ---
that might be good enough.

pws


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Load autoloadable function, but only in enclosing function scope
  2022-03-24 17:05   ` Peter Stephenson
@ 2022-03-24 17:51     ` Bart Schaefer
  2022-03-24 18:34       ` Bart Schaefer
  2022-03-24 19:52       ` Peter Stephenson
  0 siblings, 2 replies; 7+ messages in thread
From: Bart Schaefer @ 2022-03-24 17:51 UTC (permalink / raw)
  To: Zsh Users

On Thu, Mar 24, 2022 at 10:06 AM Peter Stephenson
<p.w.stephenson@ntlworld.com> wrote:
>
> With that key limitation --- if you've already got functions with the
> names of the ones you're creating, you're stuffed --- you can automate
> it like this.
>
> fn() {
>   local -a oldfuncs=(${(k)functions})

It actually can be even shorter than that, depending on how carefully
the context needs to be preserved.  Peter's example keeps the
definitions of any functions that were previously defined, even if
those definitions were replaced (by autoload execution or explicit
redefinition).  The example below restores all the function
definitions to their previous state, even when replaced.  (Native zsh
mode semantics assumed below.)

foo() { print original foo }
bar() {
  local funcs=(${(kv)functions}
  {
    foo() { print the bar foo }
    foo
  } always {
    functions=($funcs)
  }
}

% foo; bar; foo
original foo
the bar foo
original foo

This does have side-effects for autoloaded functions; they become
defined with "builtin autoload -X" as the body, which doesn't always
work the same way as a true autoload.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Load autoloadable function, but only in enclosing function scope
  2022-03-24 17:51     ` Bart Schaefer
@ 2022-03-24 18:34       ` Bart Schaefer
  2022-03-24 19:52       ` Peter Stephenson
  1 sibling, 0 replies; 7+ messages in thread
From: Bart Schaefer @ 2022-03-24 18:34 UTC (permalink / raw)
  To: Zsh Users

On Thu, Mar 24, 2022 at 10:51 AM Bart Schaefer
<schaefer@brasslantern.com> wrote:
>
> On Thu, Mar 24, 2022 at 10:06 AM Peter Stephenson
> >
> > With that key limitation --- if you've already got functions with the
> > names of the ones you're creating, you're stuffed --- you can automate
> > it like this.
>
> It actually can be even shorter than that, depending on how carefully
> the context needs to be preserved.

Copy-paste error, I missed the closing paren on this assignment:

  local funcs=(${(kv)functions})

One more note after re-reading the original request more closely:

On Thu, Mar 24, 2022 at 9:13 AM Zach Riggle <zachriggle@gmail.com> wrote:
>
> myfunc() {
>     autoload foo && foo
> }
>
> Such that foo and any other functions it declares are local-scope only?

If "foo" is already defined, it has to be removed with "unfunction
foo" before "autoload foo" will have any effect.  The "&&" there
doesn't help, because autoload is a silent but status-zero no-op for
functions that are already defined.  "autoload -R foo && foo" would
solve that.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Load autoloadable function, but only in enclosing function scope
  2022-03-24 17:51     ` Bart Schaefer
  2022-03-24 18:34       ` Bart Schaefer
@ 2022-03-24 19:52       ` Peter Stephenson
  2022-03-25  0:27         ` Bart Schaefer
  1 sibling, 1 reply; 7+ messages in thread
From: Peter Stephenson @ 2022-03-24 19:52 UTC (permalink / raw)
  To: zsh-users

On Thu, 2022-03-24 at 10:51 -0700, Bart Schaefer wrote:
> On Thu, Mar 24, 2022 at 10:06 AM Peter Stephenson
> <p.w.stephenson@ntlworld.com> wrote:
> > 
> > With that key limitation --- if you've already got functions with the
> > names of the ones you're creating, you're stuffed --- you can automate
> > it like this.
> > 
> > fn() {
> >   local -a oldfuncs=(${(k)functions})
> 
> It actually can be even shorter than that, depending on how carefully
> the context needs to be preserved.  Peter's example keeps the
> definitions of any functions that were previously defined, even if
> those definitions were replaced (by autoload execution or explicit
> redefinition).  The example below restores all the function
> definitions to their previous state, even when replaced.  (Native zsh
> mode semantics assumed below.)
> 
> foo() { print original foo }
> bar() {
>   local funcs=(${(kv)functions}
>   {
>     foo() { print the bar foo }
>     foo
>   } always {
>     functions=($funcs)
>   }
> }
> 
> This does have side-effects for autoloaded functions; they become
> defined with "builtin autoload -X" as the body, which doesn't always
> work the same way as a true autoload.

It's got side effects for other fucntions, which is that that the line
numbers recorded no longer match those in the file the function is
autoloaded from (you don't see those unless you're using a debug
prompt or equivalent).

You're also at the mercy of zsh's ability to convert internal structures
into text and back, which is supposed to work, though not particularly
efficiently.

pws



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Load autoloadable function, but only in enclosing function scope
  2022-03-24 19:52       ` Peter Stephenson
@ 2022-03-25  0:27         ` Bart Schaefer
  0 siblings, 0 replies; 7+ messages in thread
From: Bart Schaefer @ 2022-03-25  0:27 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh Users

On Thu, Mar 24, 2022 at 12:52 PM Peter Stephenson
<p.w.stephenson@ntlworld.com> wrote:
>
> You're also at the mercy of zsh's ability to convert internal structures
> into text and back, which is supposed to work, though not particularly
> efficiently.

Extending your previous suggestion, then:

local -a oldfuncs=(${(k)functions})
local autoloads=(${(k)functions[(R)builtin autoload -X*]})
local funcsrc=(${(kv)functions_source})
{
  : ...
} always {
  local funcs=(${(k)functions:|oldfuncs})
  funcs=(${funcs:|autoloads})
  (( $#autoloads )) && unfunction $autoloads
  (( ${#funcs} )) && unfunction $funcs
  local func src
  for func src in $funcsrc; do
    [[ $src = */$func && $functions[$func] == '' ]] &&
      autoload -r $src
  done
}

Handling .zwc files and unusual autoload flags left as an exercise.
Particularly difficult is autoloads from "sticky" option scopes.


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2022-03-25  0:28 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-24 16:12 Load autoloadable function, but only in enclosing function scope Zach Riggle
2022-03-24 16:29 ` Mikael Magnusson
2022-03-24 17:05   ` Peter Stephenson
2022-03-24 17:51     ` Bart Schaefer
2022-03-24 18:34       ` Bart Schaefer
2022-03-24 19:52       ` Peter Stephenson
2022-03-25  0:27         ` Bart Schaefer

Code repositories for project(s) associated with this 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).