help / color / mirror / code / Atom feed
From: Bart Schaefer <schaefer@brasslantern.com>
To: Oliver Kiddle <opk@zsh.org>
Cc: Zsh hackers list <zsh-workers@zsh.org>
Subject: Re: [PATCH 1/3]: Add named references
Date: Wed, 8 Feb 2023 20:49:40 -0800	[thread overview]
Message-ID: <CAH+w=7ZZUCqYe6w1ZqZZKR6iLsZH0SDDXyzwgTU93nxx6bmxjQ@mail.gmail.com> (raw)
In-Reply-To: <12608-1675903622.800470@Xj82.e3y1.svhG>

On Wed, Feb 8, 2023 at 4:47 PM Oliver Kiddle <opk@zsh.org> wrote:
> Bart Schaefer wrote:
> > > One ksh feature which this doesn't cover is the special behaviour in ksh
> > > that `typeset -n ref=$1` will use the calling function scope to resolve
> > > the target.
> >
> In ksh you could pass "ref" as a parameter and the nameref would provide
> access to the outside variable despite the name clash.

I think that will start working if I can fix the "invalid self
reference" mentioned in your next message.

> So [in ksh] $1 as the target of a nameref is special. [...] I don't
> think we need to worry about the level of ksh93 compatibility here
> because our default dynamic scoping mean a ksh script will work if
> variable names don't clash.

My general feeling is to be ksh compatible where I don't think ksh is stupid.

> Note that Tcl's uplevel is like a precommand modifier in zsh terms so
> is not limited to defining references.
> However I still prefer the other solution I mentioned with \&.

I have some half-formed thoughts about other ways to accomplish this
... I don't think the \& suggestion by itself gets around the problem
that the positionals are C-local to doshfunc().

> > I'm still not entirely following what problem this solves.
> It solves the problem of name clashes between a function and the calling
> function.

OK, so if
  typeset ref
  () { typeset -n ref=ref }
works / is not a loop, then we don't need any other magic?

> If two functions are developed independently, they shouldn't need
> to worry about the possibility of using the same variable name for
> different purposes. This is the main benefit of private in general.
> An old function like _call_function (updated to use nameref but still
> using local) could be used by someone writing a new function where they
> pass a private variable as the first parameter. If they are treating
> _call_function as a black box, how are they to know that private
> variables are not valid for the passed $1. It'd be an arbitrary
> limitation.

I'm still not seeing that.  The writer of the caller of _call_function
should know that it's a general rule that another function can't
access a private variable.  Why would the writer pass a private name
as an argument to any function, even a blackbox, if not expecting it
to be referenced?  The rule for a private should be that you always
pass its value.

Correct me if I still misunderstand, but I interpret the example above
as implying that

  f2() {
    typeset -n ref=$1
    # ... do stuff to $ref ...
  f1() {
    private var
    f2 var

should work just because the name is passed in a positional?  I would
disagree with that on the grounds that you're making positionals into
a special case, just a different kind of special case from ksh, that
violates the intent of "private".

The case I was asking about (and the only one I so far consider
possibly viable) is

  f1() {
    private var
    typeset -n ref=var
    f2 ref

That is, the reference has to be declared in the scope where var is
"visible", otherwise you hit the privacy wall when "typeset -n" has to

Or perhaps you mean to be tagging on to your other suggestion and it would be
  f2 \&var
which feels like syntactic sugar for my example above, with the
benefit of not needing to declare an extra parameter.  That's an
interesting idea but I would not want this to work:

  f2() {
    typeset -n upref=\&var
    # ... do things to var one level up ...
    typeset -n uptwo=\&\&var
    # ... do things to var two levels up ...

I fear that puts us back to having something magic about positional
parameters, e.g., that unless the "&var" string appears in one of $1,
$2, ... then it's just an invalid name like any other.

Back again to my half-formed thoughts, I can't really elucidate yet.

> Given that you implemented references to array members, being able to
> iterate over array elements with for could be nice. Perhaps something
> like: for ref in 'arr[*]'; do

With a hash that's just:

  typeset -n ref
  for ref in 'hash[(e)'${(k)^hash[(R)?*]}']'; do ...

but since you have to "typeset -n ref" before the for-loop anyway, why not just

  typeset -n ref=hash
  for idx in ${(k)ref}; do ... $ref[$idx] ...

Ordinary arrays are harder because there's no "find all matching
elements" subscript flag.

> On the subject references to array elements, it does seem both powerful and
> dangerous that subscripts are evaluated on reference.

Hm ... I implemented that because ksh93 accepted the syntax, but I
never actually tried it -- in fact (Ubuntu's) ksh93 doesn't actually
expand it to anything sensible and the value of the nameref ends up

> The subscript
> should perhaps be evaluated with the same local level as the array
> itself.

That gets pretty weird, and you can already trivially bypass it with
${(P)...} for many cases.

> And it could be wise to limit what can be done as part of the
> subscript evaluation to avoid a CVE similar to the last one.

validate_refname() is calling parse_subscript() ... would further
examination of the accepted string be sufficient, or something more
needed?  I think the greatest danger is of creating an infinite
recursion, which can't really be caught in advance.

  parent reply	other threads:[~2023-02-09  4:50 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-02-06  2:21 Bart Schaefer
2023-02-08  3:45 ` Oliver Kiddle
2023-02-08  4:59   ` Bart Schaefer
2023-02-08 23:16     ` Bart Schaefer
2023-02-09  0:47     ` Oliver Kiddle
2023-02-09  2:01       ` Oliver Kiddle
2023-02-09  5:45         ` Bart Schaefer
2023-02-09  4:49       ` Bart Schaefer [this message]
2023-02-09 20:49         ` Oliver Kiddle
2023-02-09 23:07           ` Bart Schaefer
2023-02-11  3:04             ` Bart Schaefer
2023-02-11  3:55               ` Bart Schaefer
2023-02-11  5:36                 ` Speaking of dangerous referents Bart Schaefer
2023-02-12  8:00                   ` Oliver Kiddle
2023-02-12  8:34                     ` Bart Schaefer
2023-02-11  7:02               ` [PATCH 1/3]: Add named references Oliver Kiddle
2023-02-11  7:45                 ` Bart Schaefer
2023-02-11 23:43                   ` Bart Schaefer
2023-02-11 23:45                     ` Bart Schaefer
2023-02-12  7:38                     ` Oliver Kiddle
2023-02-12  9:02             ` Oliver Kiddle
2023-02-12 18:59               ` Bart Schaefer
2023-02-12 19:45                 ` PM_* flags in zsh.h (was Re: [PATCH 1/3]: Add named references) Bart Schaefer
2023-02-12 21:01                   ` Oliver Kiddle
2023-02-12 22:54                 ` [PATCH 1/3]: Add named references Oliver Kiddle

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAH+w=7ZZUCqYe6w1ZqZZKR6iLsZH0SDDXyzwgTU93nxx6bmxjQ@mail.gmail.com' \
    --to=schaefer@brasslantern.com \
    --cc=opk@zsh.org \
    --cc=zsh-workers@zsh.org \


* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox


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).