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

Re: Why would I use .namespace.myvar?



On Sun, Mar 10, 2024 at 5:14 AM Stephane Chazelas <stephane@xxxxxxxxxxxx> wrote:
>
> 2024-03-09 14:58:10 -0800, Bart Schaefer:
> [...]
> > > except with things like:
> > >
> > >   typeset -p ${(kM)parameters:#.*}
> >
> > Also "typeset -pm pattern"
>
> Thanks, that makes it significantly easier to list variables in
> a namespace.

I note in passing that "typeset -pm" does unexpected things if the
GLOBALEXPORT option is NOT set ... I'll start another -workers thread
when I have a better idea what's going on.

> Would it be correct to say that the main goal for introducing
> namespaces then would be to tidy-up the output of typeset -p/set
> for all the subsystems of zsh written in zsh (completion,
> zle...) and third party plugins?

No, actually, my main goal for introducing namespaces was to be able
to write the zsh/ksh93 module, and because lack of parameter names
containing a dot has popped up several times (at widely scattered
intervals) over the past multiple years.  "Invisible" parameters was
an unexpected benefit, I didn't even know ksh did that until I was
mostly done with the rest.

It would be nice to make function names starting with a dot
"invisible" as well, but that needs wider discussion.

> Wouldn't having the .space.var variables and namespace {...} in
> two separate releases be counter-productive [for] plugin authors

I'm a little more concerned with internal uses like zsh/hlgroup than
with shell-code plugins.  After all if you've once changed shell code
to use .myplugin.myglobal there's no requirement to rewrite it with
"namespace".  And you can do something along the lines of:

   typeset -g .myplugin.myglobal .myplugin.otherglobal
   typeset -nu mygobal=.myplugin.myglobal otherglobal=.myplugin.otherglobal
   myglobal=whatever
   otherglobal=something

and then replace those two typesets with "namespace myglobal { ... }" later.

Implementing the "namespace" keyword means a bunch of fairly deep
changes, including adding more wordcode elements as the output of new
parsing routine besides figuring out the logic for inserting the
current namespace (at both definition and expansion) and trying again
without it (at expansion).  I'm not (yet at least) familiar enough
with the wordcode implementation to attempt the first part, and I'd
rather have any kinks worked out of the underlying syntactic
implementation before trying the rest.

> Like if we allow ${.space} and ${.space.1} now but we find that
> it prevents adding namespace {...} in the future, it will be
> harder then to say "oh you can't do that anymore".

There shouldn't be any clash with ${.space} because anything declared
with the "namespace" keyword will get dots both before and after.  If
you attempt either of

  namespace newspace { .space=value }
or
  namespace newspace { .otherspace.place=value }

-- I believe (given the ban on nested namespaces) that both of those
would simply skip prefixing with ".newspace." during
assignment/reference.

The potential clash with ${.space.1} is in practice I think also a
non-issue, because ksh doesn't allow a direct assignment "1=one"
anyway, so there's no incompatibility in declaring positional
parameters exempt from auto-prefixing the same way that ${.space} is
exempt.  If you want ${.space.1} you have to always write that out.

There are a bunch of questions to be resolved about how namespaces
actually work.  Ksh doc says "Commands and functions ... that modify
variables or create new ones, create a new variable" -- does "modify"
there mean that if I do --

  namespace foo { PATH="/usr/local/bin:${PATH}"; }

-- that I now have a (useless, as it doesn't affect path search?) new
global variable ${.foo.PATH}?  Alternately, does that mean that we now
have to alter the environment PATH by copy of ${.foo.PATH} and restore
again, on every entry/exit of any subsequent "namespace foo" block?

What about locals?  Do they get auto-prefixed with the namespace too?
What about:

  inner() { local foo; bar=$1; ... }
  namespace outer { inner whatever; ... }

Is "inner" now implicitly using ${outer.foo} during that call?  Did it
create global ${.outer.bar} rather than (as the writer of "inner" may
have expected) creating an actual global ${bar}?  How could the writer
of "inner" protect the function from this effect?  E.g., would/should
using "typeset -g bar=$1" be different?

Given all this uncertainty and that we're already more than 2 years
past the 5.9 release, I'd rather get the tractable parts out there
sooner.




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