zsh-workers
 help / color / mirror / code / Atom feed
* Bug with unset variables
@ 2020-11-11 15:57 Felipe Contreras
  2020-11-11 16:13 ` Roman Perepelitsa
  0 siblings, 1 reply; 53+ messages in thread
From: Felipe Contreras @ 2020-11-11 15:57 UTC (permalink / raw)
  To: zsh-workers

Hello,

It's obvious what this code should do:

  foo () {
    typeset var
    echo "var: '${var-other}'"
  }

However, zsh throws an empty string.

I tried different emulations, like ksh, and the same thing happens,
even though in ksh the right output (other) is shown.

I also tried with the other unnamable shell, and the correct output is shown.

Only zsh does something different.

My version is zsh 5.8.

Cheers.

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-11 15:57 Bug with unset variables Felipe Contreras
@ 2020-11-11 16:13 ` Roman Perepelitsa
  2020-11-11 16:56   ` Felipe Contreras
  0 siblings, 1 reply; 53+ messages in thread
From: Roman Perepelitsa @ 2020-11-11 16:13 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Zsh hackers list

On Wed, Nov 11, 2020 at 4:57 PM Felipe Contreras
<felipe.contreras@gmail.com> wrote:
>
> Hello,
>
> It's obvious what this code should do:
>
>   foo () {
>     typeset var
>     echo "var: '${var-other}'"
>   }

When foo is invoked, based on the documentation for typeset, I would
expect it to print "var: ''".

    Except as noted below for control flags that change the behav-
    ior, a parameter is created for each name that does not already
    refer to one.

And indeed that's how foo behaves when I invoke it in zsh 5.8.

> I also tried with the other unnamable shell, and the correct output is shown.

I confirm that in bash 5.0.17 function foo prints "var: 'other'".
However, I'm not sure whether this behavior agrees with the
documentation.

From `help declare`:

    Declare variables and give them attributes.

    [...]

    When used in a function, `declare' makes NAMEs local, as with the `local'
    command.

From `help local`:

    Create a local variable called NAME, and give it VALUE.

As far as I can tell, there is no indication anywhere in the
documentation that omitting =VALUE will cause `local` to not create a
variable in bash.

Do you believe the behavior of bash is expected while zsh behaves
incorrectly? If so, why?

Roman.


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

* Re: Bug with unset variables
  2020-11-11 16:13 ` Roman Perepelitsa
@ 2020-11-11 16:56   ` Felipe Contreras
  2020-11-11 17:02     ` Roman Perepelitsa
  2020-11-11 17:02     ` Peter Stephenson
  0 siblings, 2 replies; 53+ messages in thread
From: Felipe Contreras @ 2020-11-11 16:56 UTC (permalink / raw)
  To: Roman Perepelitsa; +Cc: Zsh hackers list

On Wed, Nov 11, 2020 at 10:13 AM Roman Perepelitsa
<roman.perepelitsa@gmail.com> wrote:
>
> On Wed, Nov 11, 2020 at 4:57 PM Felipe Contreras
> <felipe.contreras@gmail.com> wrote:
> >
> > Hello,
> >
> > It's obvious what this code should do:
> >
> >   foo () {
> >     typeset var
> >     echo "var: '${var-other}'"
> >   }
>
> When foo is invoked, based on the documentation for typeset, I would
> expect it to print "var: ''".

My main concern is not the documentation of typeset, but useful code.

The primary reason for why typeset exists is to set the scope of a
variable. Especially so when using "local".

If I actually do something on the foo() function:

  typeset var
  [[ -n "$1" ]] && var=$1
  echo "var: '${var-other}'"

I would expect two things: 1) var is not set when I exit the function,
and 2) var is not set until I specifically set it.

I can get both in ksh and bash, but not in zsh. In zsh I have to
choose either 1) with typeset, or 2) by removing typeset.

How do you suggest I get both in zsh?

>     Except as noted below for control flags that change the behav-
>     ior, a parameter is created for each name that does not already
>     refer to one.
>
> And indeed that's how foo behaves when I invoke it in zsh 5.8.

It is possible to "create" a parameter without value (indeed that's
what happens in other shells), the documentation doesn't say anything
about assigning it a default empty string as value.

> > I also tried with the other unnamable shell, and the correct output is shown.

> From `help local`:
>
>     Create a local variable called NAME, and give it VALUE.
>
> As far as I can tell, there is no indication anywhere in the
> documentation that omitting =VALUE will cause `local` to not create a
> variable in bash.

The documentation makes it obvious that:

  local name

Creates a local variable called "name".

And:

  local name=value

Creates a local variable called "name", and gives it "value" as its value.

If you omit the value, then it doesn't assign it any value. As is the
case in countless languages; declaring a variable without specifying
any value assigns it the value of null (or "unset" in shell lingo).

> Do you believe the behavior of bash is expected while zsh behaves
> incorrectly? If so, why?

Yes, and ksh also behaves correctly.

As stated above, it's the only behavior that makes sense.

Otherwise you cannot declare a local variable that is unset.

Cheers.

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-11 16:56   ` Felipe Contreras
@ 2020-11-11 17:02     ` Roman Perepelitsa
  2020-11-11 18:03       ` Felipe Contreras
  2020-11-11 17:02     ` Peter Stephenson
  1 sibling, 1 reply; 53+ messages in thread
From: Roman Perepelitsa @ 2020-11-11 17:02 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Zsh hackers list

On Wed, Nov 11, 2020 at 5:56 PM Felipe Contreras
<felipe.contreras@gmail.com> wrote:
>
> If I actually do something on the foo() function:
>
>   typeset var
>   [[ -n "$1" ]] && var=$1
>   echo "var: '${var-other}'"
>
> I would expect two things: 1) var is not set when I exit the function,
> and 2) var is not set until I specifically set it.
>
> I can get both in ksh and bash, but not in zsh. In zsh I have to
> choose either 1) with typeset, or 2) by removing typeset.
>
> How do you suggest I get both in zsh?

Add `unset var` right after `typeset var`.

Roman.


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

* Re: Bug with unset variables
  2020-11-11 16:56   ` Felipe Contreras
  2020-11-11 17:02     ` Roman Perepelitsa
@ 2020-11-11 17:02     ` Peter Stephenson
  2020-11-11 18:05       ` Felipe Contreras
  1 sibling, 1 reply; 53+ messages in thread
From: Peter Stephenson @ 2020-11-11 17:02 UTC (permalink / raw)
  To: Zsh hackers list


> On 11 November 2020 at 16:56 Felipe Contreras <felipe.contreras@gmail.com> wrote:
> If I actually do something on the foo() function:
> 
>   typeset var
>   [[ -n "$1" ]] && var=$1
>   echo "var: '${var-other}'"
> 
> I would expect two things: 1) var is not set when I exit the function,
> and 2) var is not set until I specifically set it.

If you want the variable to be regarded as both local in scope and
unset, you can

typeset var
unset var

and the scope stays local, so this is safe.

(I thought we already did something like this in emulation but I may
not be remembering correctly.)

pws


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

* Re: Bug with unset variables
  2020-11-11 17:02     ` Roman Perepelitsa
@ 2020-11-11 18:03       ` Felipe Contreras
  2020-11-11 18:16         ` Roman Perepelitsa
  2020-11-11 18:36         ` Bart Schaefer
  0 siblings, 2 replies; 53+ messages in thread
From: Felipe Contreras @ 2020-11-11 18:03 UTC (permalink / raw)
  To: Roman Perepelitsa; +Cc: Zsh hackers list

On Wed, Nov 11, 2020 at 11:02 AM Roman Perepelitsa
<roman.perepelitsa@gmail.com> wrote:
>
> On Wed, Nov 11, 2020 at 5:56 PM Felipe Contreras
> <felipe.contreras@gmail.com> wrote:
> >
> > If I actually do something on the foo() function:
> >
> >   typeset var
> >   [[ -n "$1" ]] && var=$1
> >   echo "var: '${var-other}'"
> >
> > I would expect two things: 1) var is not set when I exit the function,
> > and 2) var is not set until I specifically set it.
> >
> > I can get both in ksh and bash, but not in zsh. In zsh I have to
> > choose either 1) with typeset, or 2) by removing typeset.
> >
> > How do you suggest I get both in zsh?
>
> Add `unset var` right after `typeset var`.

And what is the reason why this is not the default?

Not only does this behavior differ from all other shells, but
basically all languages.

Either way, if "emulate ksh" is supposed to emulate ksh, then it's not
working properly in this instance.

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-11 17:02     ` Peter Stephenson
@ 2020-11-11 18:05       ` Felipe Contreras
  0 siblings, 0 replies; 53+ messages in thread
From: Felipe Contreras @ 2020-11-11 18:05 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

On Wed, Nov 11, 2020 at 11:02 AM Peter Stephenson
<p.w.stephenson@ntlworld.com> wrote:
>
>
> > On 11 November 2020 at 16:56 Felipe Contreras <felipe.contreras@gmail.com> wrote:
> > If I actually do something on the foo() function:
> >
> >   typeset var
> >   [[ -n "$1" ]] && var=$1
> >   echo "var: '${var-other}'"
> >
> > I would expect two things: 1) var is not set when I exit the function,
> > and 2) var is not set until I specifically set it.
>
> If you want the variable to be regarded as both local in scope and
> unset, you can
>
> typeset var
> unset var
>
> and the scope stays local, so this is safe.
>
> (I thought we already did something like this in emulation but I may
> not be remembering correctly.)

OK. But why isn't zsh doing this by default?

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-11 18:03       ` Felipe Contreras
@ 2020-11-11 18:16         ` Roman Perepelitsa
  2020-11-11 20:42           ` Felipe Contreras
  2020-11-11 18:36         ` Bart Schaefer
  1 sibling, 1 reply; 53+ messages in thread
From: Roman Perepelitsa @ 2020-11-11 18:16 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Zsh hackers list

On Wed, Nov 11, 2020 at 7:03 PM Felipe Contreras
<felipe.contreras@gmail.com> wrote:
>
> And what is the reason why this is not the default?

I don't know, I'm fairly new to zsh myself. All I can say is that the
behavior of zsh feels more natural to me.

> Not only does this behavior differ from all other shells, but
> basically all languages.

All languages? That seems exaggerated. How about this?

  int var;

How many languages will set `var` to null here? Is it all of them?

In the morally-equivalent shell code, bash does but zsh doesn't:

  typeset -i var
  echo $var

I don't know which of these languages conforms to the majority opinion
but neither can claim to do what *all* languages do.

FWIW, I rely on this behavior of zsh in my code (namely, that `typeset
-i var` sets `var` to 0).

Roman.


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

* Re: Bug with unset variables
  2020-11-11 18:03       ` Felipe Contreras
  2020-11-11 18:16         ` Roman Perepelitsa
@ 2020-11-11 18:36         ` Bart Schaefer
  2020-11-11 21:08           ` Felipe Contreras
  1 sibling, 1 reply; 53+ messages in thread
From: Bart Schaefer @ 2020-11-11 18:36 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Roman Perepelitsa, Zsh hackers list

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

On Wed, Nov 11, 2020 at 10:04 AM Felipe Contreras <
felipe.contreras@gmail.com> wrote:

>
> And what is the reason why this is not the default?
>

Remember that doc Daniel quoted?

30 years-ish ago, when implementing zsh as a new shell from scratch, that
documentation was used to decide the behavior.  At that point the other
shells that supported "typeset" were not freeware -- they required
expensive licenses or were bundled with commercial operating systems.  So
the implementation followed the doc (sometimes, it followed a
misunderstanding of the doc, which is why for example zsh syntax to specify
integer bases differs from ksh) without examples to which to compare.

Zsh development has always followed a principle of NOT arbitrarily breaking
past usage without an extremely good reason (something I wish other APIs
would have taken to heart over the years ... IMO there would be much less
abandonware sitting in metaphorical dustbins ... but I digress).  So by the
time anyone noticed, the behavior you see now was standard practice for zsh
in its default modes.

Your original example can use ${var:-other} if empty string has no explicit
meaning in context.

Either way, if "emulate ksh" is supposed to emulate ksh, then it's not
> working properly in this instance.
>

Despite the name, "emulate ksh" is not supposed to perfectly emulate ksh.
All it does is change the values of "setopt" to match ksh as closely as
possible.  A more complete emulation is achieved by actually starting zsh
from a symlink named "ksh" (or one of a few equivalent ways).  Same goes
for "sh" and "bash" (although there is little difference for those two).

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

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

* Re: Bug with unset variables
  2020-11-11 18:16         ` Roman Perepelitsa
@ 2020-11-11 20:42           ` Felipe Contreras
  2020-11-12  0:20             ` Mikael Magnusson
  2020-11-12  8:45             ` Roman Perepelitsa
  0 siblings, 2 replies; 53+ messages in thread
From: Felipe Contreras @ 2020-11-11 20:42 UTC (permalink / raw)
  To: Roman Perepelitsa; +Cc: Zsh hackers list

On Wed, Nov 11, 2020 at 12:17 PM Roman Perepelitsa
<roman.perepelitsa@gmail.com> wrote:
>
> On Wed, Nov 11, 2020 at 7:03 PM Felipe Contreras
> <felipe.contreras@gmail.com> wrote:
> >
> > And what is the reason why this is not the default?
>
> I don't know, I'm fairly new to zsh myself. All I can say is that the
> behavior of zsh feels more natural to me.

Why would

  typeset var

feel natural to be the same as

  typeset var=""

?

If I wanted the second, I would type the second.

Why does it feel natural to assign a value of a certain type, when no
value was specified?

> > Not only does this behavior differ from all other shells, but
> > basically all languages.
>
> All languages? That seems exaggerated. How about this?
>
>   int var;

You are specifying a type. I obviously meant all languages where you
can do the equivalent of "declare var" (without a type).

That being said, the most similar to shell's "declare var" in C is
"char *var" which defaults to null on most systems.

> How many languages will set `var` to null here? Is it all of them?

Pretty much, yeah. Do you want me to investigate and list them? Would
the result of that investigation change the view of zsh developers?

> In the morally-equivalent shell code, bash does but zsh doesn't:
>
>   typeset -i var
>   echo $var

In this case it might make sense to initialize to 0, since that's the
only sensible default for an integer, but consider these:

  typeset -i int
  typeset -a array
  typeset -A hash
  typeset -F float

In all these it should be obvious what would be the sensible default, but this:

  typeset var

Does not specify any type (or any value), so why would you assign a
value of a possibly wrong type?

It becomes more obvious when you print the declaration at each step:

  typeset var
  typeset -p var
  var=()
  typeset -p var

In bash, we get something sensible:

  declare -- var # no type specified
  declare -a var=()

Not so in zsh:

  typeset var='' # why a string?
  typeset -a var=(  )

Not only is it inconsistent superficially, but also internally, since
strings are considered "scalar", but that is just another word for
"variable". An integer is also a scalar. So the word "scalar" doesn't
really explain any type (only that it is a single value).

> I don't know which of these languages conforms to the majority opinion
> but neither can claim to do what *all* languages do.

It is the most sensible thing to do, so I bet at least 99.9% of
languages do this.

It is also good, desirable, and consistent, that this:

  typeset var
  typeset -p var

is a roundtrip, which happens in bash, but not so in zsh.

> FWIW, I rely on this behavior of zsh in my code (namely, that `typeset
> -i var` sets `var` to 0).

That may make sense, because you are specifying a type, but "typeset
var" doesn't specify a type. Apples and oranges.

Cheers.

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-11 18:36         ` Bart Schaefer
@ 2020-11-11 21:08           ` Felipe Contreras
  0 siblings, 0 replies; 53+ messages in thread
From: Felipe Contreras @ 2020-11-11 21:08 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Roman Perepelitsa, Zsh hackers list

On Wed, Nov 11, 2020 at 12:36 PM Bart Schaefer
<schaefer@brasslantern.com> wrote:
> On Wed, Nov 11, 2020 at 10:04 AM Felipe Contreras <felipe.contreras@gmail.com> wrote:

>> And what is the reason why this is not the default?
>
> Remember that doc Daniel quoted?
>
> 30 years-ish ago, when implementing zsh as a new shell from scratch, that documentation was used to decide the behavior.  At that point the other shells that supported "typeset" were not freeware -- they required expensive licenses or were bundled with commercial operating systems.  So the implementation followed the doc (sometimes, it followed a misunderstanding of the doc, which is why for example zsh syntax to specify integer bases differs from ksh) without examples to which to compare.
>
> Zsh development has always followed a principle of NOT arbitrarily breaking past usage without an extremely good reason (something I wish other APIs would have taken to heart over the years ... IMO there would be much less abandonware sitting in metaphorical dustbins ... but I digress).  So by the time anyone noticed, the behavior you see now was standard practice for zsh in its default modes.

This is *in general* a good principle to follow, and it does indeed
salvage plenty of projects from the dustbin, but that doesn't mean the
rule must be necessarily unquestionably followed.

I argue there almost always is a sweet spot. While almost always it's
bad to break APIs, not changing them ever also sends projects to the
dustbin.

The biggest mistake projects make isn't breaking API, but *how* they
do it. There are few disadvantages of setting a flag to turn on the
new behavior so that people can try it, then enabling the flag by
default, while always leaving the possibility to turn the flag off for
the people that prefer the old behavior.

Doing this once say every 10 years seems like a sensible thing to do.
Just have a list of all these proposed changes so they don't get lost.
That's what major versions are for.

> Your original example can use ${var:-other} if empty string has no explicit meaning in context.

I know, but it does have meaning. It is a suffix, so I want to use a
space by default "${sfx- }", but only $sfx is unset, it can be set
with an empty value, in which case I don't want any suffix.

And it's not even my code, it's bash code I'm trying to emulate and
leverage from zsh.

>> Either way, if "emulate ksh" is supposed to emulate ksh, then it's not
>> working properly in this instance.
>
> Despite the name, "emulate ksh" is not supposed to perfectly emulate ksh.  All it does is change the values of "setopt" to match ksh as closely as possible.  A more complete emulation is achieved by actually starting zsh from a symlink named "ksh" (or one of a few equivalent ways).  Same goes for "sh" and "bash" (although there is little difference for those two).

Right, but if virtually all shells do this, and it is a known
discrepancy, and I'd argue it's the behavior that makes the most
sense, I think it makes sense to have a flag for it.

Cheers.

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-11 20:42           ` Felipe Contreras
@ 2020-11-12  0:20             ` Mikael Magnusson
  2020-11-12  1:10               ` Felipe Contreras
  2020-11-12  8:45             ` Roman Perepelitsa
  1 sibling, 1 reply; 53+ messages in thread
From: Mikael Magnusson @ 2020-11-12  0:20 UTC (permalink / raw)
  To: Zsh hackers list

On 11/11/20, Felipe Contreras <felipe.contreras@gmail.com> wrote:
> On Wed, Nov 11, 2020 at 12:17 PM Roman Perepelitsa
> <roman.perepelitsa@gmail.com> wrote:
>> > Not only does this behavior differ from all other shells, but
>> > basically all languages.
>>
>> All languages? That seems exaggerated. How about this?
>>
>>   int var;
>
> You are specifying a type. I obviously meant all languages where you
> can do the equivalent of "declare var" (without a type).
>
> That being said, the most similar to shell's "declare var" in C is
> "char *var" which defaults to null on most systems.

This is certainly not true, just for the record. Variables in global
or static scope are initialized to 0 regardless of type, whereas
others are uninitialized (meaning they contain garbage, not that they
magically know that they haven't been assigned to).

-- 
Mikael Magnusson


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

* Re: Bug with unset variables
  2020-11-12  0:20             ` Mikael Magnusson
@ 2020-11-12  1:10               ` Felipe Contreras
  0 siblings, 0 replies; 53+ messages in thread
From: Felipe Contreras @ 2020-11-12  1:10 UTC (permalink / raw)
  To: Mikael Magnusson; +Cc: Zsh hackers list

On Wed, Nov 11, 2020 at 6:20 PM Mikael Magnusson <mikachu@gmail.com> wrote:
> On 11/11/20, Felipe Contreras <felipe.contreras@gmail.com> wrote:

> > That being said, the most similar to shell's "declare var" in C is
> > "char *var" which defaults to null on most systems.
>
> This is certainly not true, just for the record. Variables in global
> or static scope are initialized to 0 regardless of type, whereas
> others are uninitialized (meaning they contain garbage, not that they
> magically know that they haven't been assigned to).

The C standard says accessing an uninitialized variable results in
*undefined* behavior, it doesn't say the variable *must* contain
garbage. The variable *may* contain garbage, but not necessarily so.

However, "static char *var" is *always* initialized to null.

Either way, what *never* happens is var pointing to an empty string.

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-11 20:42           ` Felipe Contreras
  2020-11-12  0:20             ` Mikael Magnusson
@ 2020-11-12  8:45             ` Roman Perepelitsa
  2020-11-12 10:47               ` Peter Stephenson
  2020-11-12 18:46               ` Felipe Contreras
  1 sibling, 2 replies; 53+ messages in thread
From: Roman Perepelitsa @ 2020-11-12  8:45 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Zsh hackers list

On Wed, Nov 11, 2020 at 9:42 PM Felipe Contreras
<felipe.contreras@gmail.com> wrote:
>
> >   typeset -i var
> >   echo $var
>
> In this case it might make sense to initialize to 0, since that's the
> only sensible default for an integer, but consider these:
>
>   typeset -i int
>   typeset -a array
>   typeset -A hash
>   typeset -F float
>
> In all these it should be obvious what would be the sensible default, but this:
>
>   typeset var

Both bash and zsh are consistent. Regardless of the presence or
absence of a storage specifier, bash leaves the variable unset while
zsh sets it to the "natural" value of the parameter's storage type. By
natural I mean neutral w.r.t. +=. If `typeset -i var` was setting
`var` to zero while `typeset var` was leaving it unset, that would be
inconsistent. In my opinion this would be worse than the behavior of
bash and zsh.

The fact that unset parameters are also called "null" in ksh/bash/zsh
invites confusion when comparing them to languages that can have
parameters with null *values*. Those null values are first-class
citizens. You can pass them as arguments to functions, store them in
arrays, etc. Shells don't have null *values*, they just have unset
parameters.

Most languages (in fact, all languages I know) either don't have the
notion of an unset variable with function scope, or automatically give
all declared variables values. The closest equivalent to ksh/bash/zsh
I'm aware of is elisp because it also has dynamic typing and dynamic
scope. elisp has the same notion of an unset variable as ksh/bash/zsh
(they are called void in elisp). You can declare local variables with
`let` and unset them with `makunbound`. These behave like `typeset`
and `unset` in zsh -- in order to create an unset variable with
function scope, you need to declare it and then unset. Declaring the
variable without value won't do.

In sum, what zsh does makes sense to me and feels natural and
consistent with other languages I know. That isn't to say that I
consider the behavior of ksh/bash incorrect. It's a bit surprising but
sensible. I could definitely get used to it. The strongest argument
for changing zsh is consistency with ksh and bash. The strongest
argument against it is that it'll break a lot of existing zsh code.
It's not my call but to me this looks like a no-go.

Roman.


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

* Re: Bug with unset variables
  2020-11-12  8:45             ` Roman Perepelitsa
@ 2020-11-12 10:47               ` Peter Stephenson
  2020-11-12 18:48                 ` Bart Schaefer
  2020-11-12 19:49                 ` Felipe Contreras
  2020-11-12 18:46               ` Felipe Contreras
  1 sibling, 2 replies; 53+ messages in thread
From: Peter Stephenson @ 2020-11-12 10:47 UTC (permalink / raw)
  To: Zsh hackers list

With some trepidation, let me see if I can try and sum up.

fn() {
   typeset foo
   # foo is regarded as set (in the sense "not unset") here.
}

Other shells would treat foo as unset at that point.

This is a long standing feature of zsh, so the default behaviour
is not going to change.  Almost certainly there was no direct
thought at the time zsh was implemented about the details
of this case, so it was probably  not a formal syntactical
decision.

It is a bug when emulating other shells (although note that there
are plenty of such bugs --- emulation is never complete).  I
said I thought we'd done something about this, but I don't see any
evidence, so I was probably wrong.  There is definitely scope for
improvement.

Given that all shells would treat $foo as an empty string in
the context above, the practical impact is limited to a few
edge cases --- granted that can be infuriating (and more)
when you hit one, so I am not dismissing such cases.  That's why
this issue doesn't often come up despite its long-standing
nature.

For the same reason, that $foo will reliably substitute as
an empty string, I don't see any *overriding* reason for
the behaviour of other shells.  That absolutely doesn't
mean I see no arguments for that behaviour, all of
which I think have now been rehearsed.

Hope that's useful.
pws


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

* Re: Bug with unset variables
  2020-11-12  8:45             ` Roman Perepelitsa
  2020-11-12 10:47               ` Peter Stephenson
@ 2020-11-12 18:46               ` Felipe Contreras
  2020-11-12 19:10                 ` Roman Perepelitsa
  2020-11-12 19:26                 ` Bart Schaefer
  1 sibling, 2 replies; 53+ messages in thread
From: Felipe Contreras @ 2020-11-12 18:46 UTC (permalink / raw)
  To: Roman Perepelitsa; +Cc: Zsh hackers list

On Thu, Nov 12, 2020 at 2:46 AM Roman Perepelitsa
<roman.perepelitsa@gmail.com> wrote:
> On Wed, Nov 11, 2020 at 9:42 PM Felipe Contreras
> <felipe.contreras@gmail.com> wrote:

> > In all these it should be obvious what would be the sensible default, but this:
> >
> >   typeset var
>
> Both bash and zsh are consistent. Regardless of the presence or
> absence of a storage specifier, bash leaves the variable unset while
> zsh sets it to the "natural" value of the parameter's storage type. By
> natural I mean neutral w.r.t. +=. If `typeset -i var` was setting
> `var` to zero while `typeset var` was leaving it unset, that would be
> inconsistent. In my opinion this would be worse than the behavior of
> bash and zsh.

No. Zsh is not consistent. I did not type /typeset var=''/, I typed
/typeset var/.

> The fact that unset parameters are also called "null" in ksh/bash/zsh
> invites confusion when comparing them to languages that can have
> parameters with null *values*. Those null values are first-class
> citizens. You can pass them as arguments to functions, store them in
> arrays, etc. Shells don't have null *values*, they just have unset
> parameters.

This is distinction without a difference, like saying we are not lost,
we just don't know where we are. Conceptually it is the same thing,
you are just using a different word for it. It's wordplay.

An unset variable is for all intents and purposes a variable with a null value.

> Most languages (in fact, all languages I know) either don't have the
> notion of an unset variable with function scope, or automatically give
> all declared variables values. The closest equivalent to ksh/bash/zsh
> I'm aware of is elisp because it also has dynamic typing and dynamic
> scope. elisp has the same notion of an unset variable as ksh/bash/zsh
> (they are called void in elisp). You can declare local variables with
> `let` and unset them with `makunbound`. These behave like `typeset`
> and `unset` in zsh -- in order to create an unset variable with
> function scope, you need to declare it and then unset. Declaring the
> variable without value won't do.

So you don't know JavaScript (one of the most popular languages today)?

  > var v
  > typeof v
  'undefined'

Even in Python and Ruby the way you "declare" variables without a type
is by setting them to the equivalent of the null value. This has
*exactly* the same effect as "local x". Once again it's a distinction
without a difference.

In Swift you can declare a variable with the type "Any", and by
default it has the nil value.

Virtually all languages have a way of declaring a variable with a
local scope, and *all* of them (including shell) have an idiom to do
it without assigning an empty string (except zsh).

> In sum, what zsh does makes sense to me and feels natural and
> consistent with other languages I know.

Carrying luggage without wheels also felt natural.

Humans can get used to anything.

You cannot tell me that if I originally have this:

  func () {
    [[ -n "$1" ]] && var=$1
    dosomething ${var-other}
  }

And I want to change the scope of the variable, so it's not set
globally (which can be done in plenty of languages), and then I do
this:

  func () {
    typeset var
    [[ -n "$1" ]] && var=$1
    dosomething ${var-other}
  }

It makes sense to *change* the behavior of the code.

Can you?

> That isn't to say that I
> consider the behavior of ksh/bash incorrect. It's a bit surprising but
> sensible. I could definitely get used to it. The strongest argument
> for changing zsh is consistency with ksh and bash. The strongest
> argument against it is that it'll break a lot of existing zsh code.
> It's not my call but to me this looks like a no-go.

This is a false dichotomy.

Adding a setopt option for the new behavior doesn't break a lot of
existing zsh code.

Cheers.

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-12 10:47               ` Peter Stephenson
@ 2020-11-12 18:48                 ` Bart Schaefer
  2020-11-12 19:49                 ` Felipe Contreras
  1 sibling, 0 replies; 53+ messages in thread
From: Bart Schaefer @ 2020-11-12 18:48 UTC (permalink / raw)
  To: Zsh hackers list

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

On Thu, Nov 12, 2020 at 2:48 AM Peter Stephenson <
p.w.stephenson@ntlworld.com> wrote:

>
> This is a long standing feature of zsh, so the default behaviour
> is not going to change.  Almost certainly there was no direct
> thought at the time zsh was implemented about the details
> of this case, so it was probably  not a formal syntactical
> decision.
>

If we go back far enough, to the original Bourne shell, there's no such
thing as local variables, no variable type except string, and no variable
that can both exist and be unset.  Everything is either in the exported
global environment as a string, or it doesn't exist at all.

The next step is variables that can exist in the global environment but are
not exported.  But they still always have to either be a (possibly empty)
string, or not exist at all.

Zsh preserves that behavior, then adds that you can explicitly unset a
variable and zsh will remember its "type" as long as the variable is in the
same scope.

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

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

* Re: Bug with unset variables
  2020-11-12 18:46               ` Felipe Contreras
@ 2020-11-12 19:10                 ` Roman Perepelitsa
  2020-11-12 21:08                   ` Felipe Contreras
  2020-11-12 19:26                 ` Bart Schaefer
  1 sibling, 1 reply; 53+ messages in thread
From: Roman Perepelitsa @ 2020-11-12 19:10 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Zsh hackers list

On Thu, Nov 12, 2020 at 7:47 PM Felipe Contreras
<felipe.contreras@gmail.com> wrote:
>
> This is distinction without a difference, like saying we are not lost,
> we just don't know where we are. Conceptually it is the same thing,
> you are just using a different word for it. It's wordplay.
>
> An unset variable is for all intents and purposes a variable with a null value.

Only in languages where variables cannot have null values, and only
because you can declare "null" to be a synonym for "unset" in this
case.

> JavaScript

In JavaScript you unset a variable with `delete foo` and you assign it
a "null" value (in quotes because javascript has another null) with
`foo = undefined`. These are not equivalent.

Note that these two snippets have different effect:

  var foo

and

  var foo
  delete foo

Just line in zsh, and unlike ksh/bash.

> Python

Same thing but `del var` and `var = None`.

Et cetera. ksh and bash are rather exceptional in this regard.

Roman.


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

* Re: Bug with unset variables
  2020-11-12 18:46               ` Felipe Contreras
  2020-11-12 19:10                 ` Roman Perepelitsa
@ 2020-11-12 19:26                 ` Bart Schaefer
  2020-11-12 21:48                   ` Felipe Contreras
  1 sibling, 1 reply; 53+ messages in thread
From: Bart Schaefer @ 2020-11-12 19:26 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Roman Perepelitsa, Zsh hackers list

On Thu, Nov 12, 2020 at 10:47 AM Felipe Contreras
<felipe.contreras@gmail.com> wrote:
>
> No. Zsh is not consistent. I did not type /typeset var=''/, I typed
> /typeset var/.

At the global level you cannot write

VAR

to create a variable named "VAR".

VAR=

both creates a variable and assigns it empty string.

So now we have to decide what to do when with local variables.  They
can either have a totally new semantic, or we can follow the semantic
for globals.  Guess which one makes more sense when you are adding
local scope to a language which previously had only two possible
conceptions of variables (exist and are empty, or do not exist at
all).

That said ...

> Adding a setopt option for the new behavior doesn't break a lot of
> existing zsh code.

It probably wouldn't break any _scripts_ even to modify the behavior
of KSH_TYPESET for this.  Whether we can cleanly perform an implicit
unset in the C code structure, and (if not) whether cobbling this in
is worthwhile, I haven't investigated or formed an opinion.


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

* Re: Bug with unset variables
  2020-11-12 10:47               ` Peter Stephenson
  2020-11-12 18:48                 ` Bart Schaefer
@ 2020-11-12 19:49                 ` Felipe Contreras
  1 sibling, 0 replies; 53+ messages in thread
From: Felipe Contreras @ 2020-11-12 19:49 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

On Thu, Nov 12, 2020 at 4:48 AM Peter Stephenson
<p.w.stephenson@ntlworld.com> wrote:
>
> With some trepidation, let me see if I can try and sum up.
>
> fn() {
>    typeset foo
>    # foo is regarded as set (in the sense "not unset") here.
> }
>
> Other shells would treat foo as unset at that point.
>
> This is a long standing feature of zsh

It's not a bug, it's a feature!

Never heard that one before.

> It is a bug when emulating other shells (although note that there
> are plenty of such bugs --- emulation is never complete).  I
> said I thought we'd done something about this, but I don't see any
> evidence, so I was probably wrong.  There is definitely scope for
> improvement.

Indeed, I've been looking at the code, and there doesn't seem to be
anything similar. It's making too many assumptions about the starting
state of a parameter.

> Given that all shells would treat $foo as an empty string in
> the context above, the practical impact is limited to a few
> edge cases --- granted that can be infuriating (and more)
> when you hit one, so I am not dismissing such cases.  That's why
> this issue doesn't often come up despite its long-standing
> nature.

Absence of evidence is not evidence of absence.

Perhaps a considerable amount of people have hit this issue, but they
haven't bothered to contact the mailing lists. Most people just make
it work on their code, and move on.

> For the same reason, that $foo will reliably substitute as
> an empty string, I don't see any *overriding* reason for
> the behaviour of other shells.  That absolutely doesn't
> mean I see no arguments for that behaviour, all of
> which I think have now been rehearsed.

There is a difference between a variable that contains an empty
string, and an unset variable, this is an undeniable fact about the
shell language.

There is a reason why people use ${foo+set} instead of $foo when they
want to check if a variable is set, as opposed to empty.

The fact that most code doesn't care about the difference doesn't mean
there isn't some code that does.

Cheers.

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-12 19:10                 ` Roman Perepelitsa
@ 2020-11-12 21:08                   ` Felipe Contreras
  2020-11-13  8:51                     ` Roman Perepelitsa
  0 siblings, 1 reply; 53+ messages in thread
From: Felipe Contreras @ 2020-11-12 21:08 UTC (permalink / raw)
  To: Roman Perepelitsa; +Cc: Zsh hackers list

On Thu, Nov 12, 2020 at 1:11 PM Roman Perepelitsa
<roman.perepelitsa@gmail.com> wrote:
>
> On Thu, Nov 12, 2020 at 7:47 PM Felipe Contreras
> <felipe.contreras@gmail.com> wrote:
> >
> > This is distinction without a difference, like saying we are not lost,
> > we just don't know where we are. Conceptually it is the same thing,
> > you are just using a different word for it. It's wordplay.
> >
> > An unset variable is for all intents and purposes a variable with a null value.
>
> Only in languages where variables cannot have null values, and only
> because you can declare "null" to be a synonym for "unset" in this
> case.

No. Intents and purposes don't depend on the language you cherry-pick.

> > JavaScript
>
> In JavaScript you unset a variable with `delete foo` and you assign it
> a "null" value (in quotes because javascript has another null) with
> `foo = undefined`. These are not equivalent.
>
> Note that these two snippets have different effect:
>
>   var foo
>
> and
>
>   var foo
>   delete foo
>
> Just line in zsh, and unlike ksh/bash.

No. That code doesn't even work in JavaScript:

  > var foo
  undefined
  > delete foo
  false

Delete foo returns false because it didn't do anything.

  > var foo="test"
  undefined
  > delete foo
  false
  > foo
  'test'

The variable is still there with type and value.

If you turn on the strict mode you get: "SyntaxError: Delete of an
unqualified identifier in strict mode."

The delete operator is there to handle properties of objects, not
variables [1]. The closest to unset is assigning a value of
"undefined".

But the important thing is that foo is *never* an empty string.

> > Python
>
> Same thing but `del var` and `var = None`.
>
> Et cetera. ksh and bash are rather exceptional in this regard.

This is a false equivalence. You are talking about two different
concepts as if they were the same thing. They are not.

  foo="global"

  func () {
    typeset foo
    unset foo
    foo="local"
    echo $foo
  }

  func
  echo $foo

In this example unset does not do the same thing as the del statement
in Python. The scope of "foo" is not changed. The equivalent of "unset
foo" is "foo = None".

A real equivalence is undefined in JavaScript:

  var foo="global";

  function func() {
    var foo;
    foo = undefined;
    foo = "local";
    console.log(foo);
  }

  func();
  console.log(foo);

In both cases "unset foo" and "foo = undefined" do *exactly* the same
thing, which is return the variable to its original state.

And in both cases if you remove "typeset foo" or "var foo" the effect
is *exactly* the same; modifying foo inside the function modifies the
global variable.

If you compare apples to apples the equivalence is obvious.

In JavaScript "var foo" does not set foo to an empty string.

Cheers.

[1] http://ecma-international.org/ecma-262/11.0/#sec-delete-operator

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-12 19:26                 ` Bart Schaefer
@ 2020-11-12 21:48                   ` Felipe Contreras
  2020-11-13 22:17                     ` Bart Schaefer
  0 siblings, 1 reply; 53+ messages in thread
From: Felipe Contreras @ 2020-11-12 21:48 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Roman Perepelitsa, Zsh hackers list

On Thu, Nov 12, 2020 at 1:26 PM Bart Schaefer <schaefer@brasslantern.com> wrote:
>
> On Thu, Nov 12, 2020 at 10:47 AM Felipe Contreras
> <felipe.contreras@gmail.com> wrote:
> >
> > No. Zsh is not consistent. I did not type /typeset var=''/, I typed
> > /typeset var/.

> So now we have to decide what to do when with local variables.

Which is probably the main purpose of typeset (i.e. local).

> They
> can either have a totally new semantic, or we can follow the semantic
> for globals.

Syntax is not semantics.

  var=
  typeset var=

These two have a very similar syntax, so it makes sense that the
semantics are the same. But there's no previous equivalent of "typeset
var".

> Guess which one makes more sense when you are adding
> local scope to a language which previously had only two possible
> conceptions of variables (exist and are empty, or do not exist at
> all).

There's a third conception; a non-empty value.

  var=
  typeset var=

  var="foo"
  typeset var="foo"

These are obvious. The only thing that is left is deciding what
"typeset var" does. These are the options:

1. Errors
2. Nothing
3. Changes the scope
4. Changes the scope and sets an empty value
5. Changes the scope and sets an arbitrary value

Obviously 1 and 2 are not useful options. 5 doesn't really make sense,
and 4 is a subset of 5. More importantly; there's already ways to do 4
and 5.

So why not do a) something useful, b) something that isn't arbitrary,
and c) something that can't be done in other ways?

> That said ...
>
> > Adding a setopt option for the new behavior doesn't break a lot of
> > existing zsh code.
>
> It probably wouldn't break any _scripts_ even to modify the behavior
> of KSH_TYPESET for this.  Whether we can cleanly perform an implicit
> unset in the C code structure, and (if not) whether cobbling this in
> is worthwhile, I haven't investigated or formed an opinion.

I have already started some experiments.

At first glance there doesn't seem to be any straight-forward way of
doing this, but I'm not familiar with the code either, so it would
take a while for me to reach any conclusion.

Either way it seems clear to me reorganizing the code to make it at
least possible will remove many of the weird checks and corner cases
scattered all over, or at least make them more understandable.

We'll have to see.

Cheers.

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-12 21:08                   ` Felipe Contreras
@ 2020-11-13  8:51                     ` Roman Perepelitsa
  2020-11-14  0:52                       ` Felipe Contreras
  0 siblings, 1 reply; 53+ messages in thread
From: Roman Perepelitsa @ 2020-11-13  8:51 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Zsh hackers list

On Thu, Nov 12, 2020 at 10:08 PM Felipe Contreras
<felipe.contreras@gmail.com> wrote:
>
> On Thu, Nov 12, 2020 at 1:11 PM Roman Perepelitsa
> <roman.perepelitsa@gmail.com> wrote:
>>
> > Note that these two snippets have different effect:
> >
> >   var foo
> >
> > and
> >
> >   var foo
> >   delete foo
> >
> > Just line in zsh, and unlike ksh/bash.
>
> No. That code doesn't even work in JavaScript:

I didn't realize you cannot unset variables in JavaScript. Then
comparing it with shells isn't very useful.

>  "unset foo" and "foo = undefined" do *exactly* the same thing

`undefined` is just a value, so `foo = undefined` simply changes the
value of foo. You can still pass foo around, just like you could do it
if it held any other value. Unsetting a parameter in a shell is quite
different. It's impossible to detect a difference between these two
cases: 1) foo was never declared, and 2) foo was declared and
subsequently unset. (At least in global scope. Shells differ w.r.t.
local variables.)

We'll need another language that allows unsetting variables to have a
meaningful comparison. How about elisp? As I mentioned earlier, it
shares two important properties with ksh/bash/zsh -- dynamic typing
and dynamic scope. In elisp declaring a variable and then unsetting it
is not equivalent to just declaring a variable. Like in zsh and unlike
ksh/bash.

> In JavaScript "var foo" does not set foo to an empty string.

It sets *some* value, specifically `undefined`. In shells there is no
such value, so assigning `undefined` is not an option. The only
options are: assign the default value that corresponds to the
parameter's storage type (an empty string for string parameters) or
leave the parameter unset. The latter has no equivalence in JavaScript
because JavaScript has no notion of unset variables.

I don't think this discussion will affect anything of substance. I'm
continuing merely out of politeness. You've asked why I consider the
behavior of zsh natural and I'm doing my best to explain. I can see
that you consider the behavior of ksh/bash natural and I agree that
your position is consistent. I'm not arguing that what zsh does is
objectively *more* natural, only that it's also consistent and has
precedence in other languages (elisp).

I think I've found a language that has constructs equivalent to
typeset and unset with the same semantics as in ksh/bash. In Lua this
snippet:

  local x
  x = nil

Is equivalent to this:

  local x

Moreover, variables to which nil has been assigned are
indistinguishable from variables that have never been declared.
"Variable foo is nil" has the same meaning as "variable foo does not
exist". Like in shells and unlike JavaScript.

Roman.


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

* Re: Bug with unset variables
  2020-11-12 21:48                   ` Felipe Contreras
@ 2020-11-13 22:17                     ` Bart Schaefer
  2020-11-14  0:58                       ` Felipe Contreras
  0 siblings, 1 reply; 53+ messages in thread
From: Bart Schaefer @ 2020-11-13 22:17 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Roman Perepelitsa, Zsh hackers list

On Thu, Nov 12, 2020 at 1:48 PM Felipe Contreras
<felipe.contreras@gmail.com> wrote:
>
> Syntax is not semantics.

Um, yes?  That was sort of my point.

>   ...  there's no previous equivalent of "typeset var".

Also my point.

> There's a third conception; a non-empty value.

Except that "unset" is not the same as having a non-empty value (I
would actually call this simply a "non-value", "empty" has nothing to
do with it), from the standpoint of internal representation.  I don't
happen to agree that they're equatable in the semantics of the
language, either, but that opinion is not relevant.

Consider this from an evolutionary standpoint.  To represent a
non-value requires a data structure that knows the name of the object
but contains metadata to the effect that the implementation must not
reveal to the interpreted program any value corresponding to that
name.  To represent an unset object merely requires that no data
structure exists, period; unset removes the name itself.

Given the latter implementation of "unset", we're now asked to declare
local scopes.  The most straightforward step without an architectural
change, is to cause the data structure to come into existence, so that
we know its name, and add metadata about its scope; but the existence
of the name implies that SOME value becomes visible to the program.
The historical precedent for the default behavior is established.

The only reason we can even have this discussion now is because in the
intervening years those architectural changes have been made and there
exists an internal representation for the properties of an invisible
"unset" name.


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

* Re: Bug with unset variables
  2020-11-13  8:51                     ` Roman Perepelitsa
@ 2020-11-14  0:52                       ` Felipe Contreras
  2020-11-14  5:41                         ` Roman Perepelitsa
  0 siblings, 1 reply; 53+ messages in thread
From: Felipe Contreras @ 2020-11-14  0:52 UTC (permalink / raw)
  To: Roman Perepelitsa; +Cc: Zsh hackers list

On Fri, Nov 13, 2020 at 2:52 AM Roman Perepelitsa
<roman.perepelitsa@gmail.com> wrote:
>
> On Thu, Nov 12, 2020 at 10:08 PM Felipe Contreras
> <felipe.contreras@gmail.com> wrote:
> >
> > On Thu, Nov 12, 2020 at 1:11 PM Roman Perepelitsa
> > <roman.perepelitsa@gmail.com> wrote:
> >>
> > > Note that these two snippets have different effect:
> > >
> > >   var foo
> > >
> > > and
> > >
> > >   var foo
> > >   delete foo
> > >
> > > Just line in zsh, and unlike ksh/bash.
> >
> > No. That code doesn't even work in JavaScript:
>
> I didn't realize you cannot unset variables in JavaScript. Then
> comparing it with shells isn't very useful.
>
> >  "unset foo" and "foo = undefined" do *exactly* the same thing
>
> `undefined` is just a value, so `foo = undefined` simply changes the
> value of foo. You can still pass foo around, just like you could do it
> if it held any other value. Unsetting a parameter in a shell is quite
> different. It's impossible to detect a difference between these two
> cases: 1) foo was never declared, and 2) foo was declared and
> subsequently unset. (At least in global scope. Shells differ w.r.t.
> local variables.)

The two things are functionally *exactly* the same.

In JavaScript if you don't declare foo, accessing it gives you the
value of "undefined", and if you declare it and "unset" it, it also
gives you "undefined". Exactly the same as in shell.

You just don't want to accept they are functionally the same because
you don't want them to be the same.

> We'll need another language that allows unsetting variables to have a
> meaningful comparison. How about elisp? As I mentioned earlier, it
> shares two important properties with ksh/bash/zsh -- dynamic typing
> and dynamic scope. In elisp declaring a variable and then unsetting it
> is not equivalent to just declaring a variable. Like in zsh and unlike
> ksh/bash.

Lisp doesn't allow defining variables without a value.

> > In JavaScript "var foo" does not set foo to an empty string.
>
> It sets *some* value, specifically `undefined`. In shells there is no
> such value, so assigning `undefined` is not an option.

Once again: a distinction without a difference.

https://en.wikipedia.org/wiki/Distinction_without_a_difference

> I don't think this discussion will affect anything of substance. I'm
> continuing merely out of politeness. You've asked why I consider the
> behavior of zsh natural and I'm doing my best to explain.

Yes, but you have avoided some of my strongest arguments, for example this:

  func () {
    [[ -n "$1" ]] && var=$1
    dosomething ${var-other}
  }

  func () {
    typeset var
    [[ -n "$1" ]] && var=$1
    dosomething ${var-other}
  }

You have never explained how it makes sense that adding that extra
line changes the behavior.

> I'm not arguing that what zsh does is
> objectively *more* natural, only that it's also consistent and has
> precedence in other languages (elisp).

And I've shown you how you are comparing apples to oranges.

> I think I've found a language that has constructs equivalent to
> typeset and unset with the same semantics as in ksh/bash. In Lua this
> snippet:
>
>   local x
>   x = nil
>
> Is equivalent to this:
>
>   local x
>
> Moreover, variables to which nil has been assigned are
> indistinguishable from variables that have never been declared.
> "Variable foo is nil" has the same meaning as "variable foo does not
> exist". Like in shells and unlike JavaScript.

Exactly the same thing as in JavaScript, just s/nil/undefined/.

Either way, "local x" in Lua does exactly the same thing as it does in Bash.

When you compare apples to apples the behavior is exactly the same in
all languages.

Cheers.

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-13 22:17                     ` Bart Schaefer
@ 2020-11-14  0:58                       ` Felipe Contreras
  0 siblings, 0 replies; 53+ messages in thread
From: Felipe Contreras @ 2020-11-14  0:58 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Roman Perepelitsa, Zsh hackers list

On Fri, Nov 13, 2020 at 4:17 PM Bart Schaefer <schaefer@brasslantern.com> wrote:

> Given the latter implementation of "unset", we're now asked to declare
> local scopes.  The most straightforward step without an architectural
> change, is to cause the data structure to come into existence, so that
> we know its name, and add metadata about its scope; but the existence
> of the name implies that SOME value becomes visible to the program.
> The historical precedent for the default behavior is established.

The most straightforward way is not necessarily the best way.

Very often the best way takes effort.

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-14  0:52                       ` Felipe Contreras
@ 2020-11-14  5:41                         ` Roman Perepelitsa
  2020-11-16 19:41                           ` Felipe Contreras
  0 siblings, 1 reply; 53+ messages in thread
From: Roman Perepelitsa @ 2020-11-14  5:41 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Zsh hackers list

On Sat, Nov 14, 2020 at 1:52 AM Felipe Contreras
<felipe.contreras@gmail.com> wrote:
>
> In JavaScript if you don't declare foo, accessing it gives you the
> value of "undefined", and if you declare it and "unset" it, it also
> gives you "undefined".

Here's what I'm getting in Chrome console:

  console.log(foo)

    Uncaught ReferenceError: foo is not defined

  foo = undefined
  console.log(foo)

    undefined

Is this behavior non-standard?

> You just don't want to accept they are functionally the same because
> you don't want them to be the same.

Let's keep the discussion limited to the subject matter of programming
languages.

> Lisp doesn't allow defining variables without a value.

Here's what I'm getting in GNU Emacs 26.3:

  (defun foo ()
    (let ((var))
      var))

  (defun bar ()
    (let ((var))
      (makunbound 'var)
      var))

  (foo)
  nil

  (bar)
  *** Eval error ***  Symbol’s value as variable is void: var

A variable declared without a value gets the value of nil. You can
pass nil around like any other value.

> you have avoided some of my strongest arguments, for example this:
>
>   func () {
>     [[ -n "$1" ]] && var=$1
>     dosomething ${var-other}
>   }
>
>   func () {
>     typeset var
>     [[ -n "$1" ]] && var=$1
>     dosomething ${var-other}
>   }
>
> You have never explained how it makes sense that adding that extra
> line changes the behavior.

I thought you were arguing that the behavior of `typeset var` in
ksh/bash makes sense while in zsh it doesn't. However, in the example
you've given above adding `typeset var` to func changes the function's
behavior in all shells. What am I missing?

> > Moreover, [in Lua] variables to which nil has been assigned are
> > indistinguishable from variables that have never been declared.
> > "Variable foo is nil" has the same meaning as "variable foo does not
> > exist". Like in shells and unlike JavaScript.
>
> Exactly the same thing as in JavaScript, just s/nil/undefined/.

If you try to print a variable that hasn't been defined, you'll get an
error in JavaScript and "nil" in Lua.

> Either way, "local x" in Lua does exactly the same thing as it does in Bash.

That was my point. Originally I said I didn't know of any language
that does what ksh/bash does but then I realized that Lua could fit
the bill, so I mentioned it. To be more specific, I was looking for a
language that 1) allows you to declare variables without specifying
their values; 2) allows you to unset/unbind/undeclare variables; 3)
the effect of declaring a variable and immediately unsetting it is
equivalent to declaring a variable without specifying the initial
value.

FWIW, one of my gripes with Lua is that accessing an undeclared
variable gives you nil. If it was an error instead (which I would
prefer), Lua wouldn't satisfy the 3rd requirement I've listed above,
so it wouldn't be like ksh/bash for the purpose of this discussion. It
would be like zsh and elisp.

> The most straightforward way is not necessarily the best way.
>
> Very often the best way takes effort.

This is obviously true.

I'll summarize my position. I believe it is in agreement with Peter
and Bart but I wouldn't presume speaking for them.

- The way typeset works in zsh makes sense. There is no inconsistency,
there is precedence in other languages, and it was a natural evolution
from global-only parameters.
- If we could change history, it would be better if typeset in zsh
worked the same way as in ksh/bash because that behavior also makes
sense and compatibility is valuable.
- It's infeasible to change the behavior of typeset in zsh in native
mode because it'll break too much user code.
- It's feasible and desirable to make typeset compatible with ksh/bash
when KSH_TYPESET is set.

Roman.


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

* Re: Bug with unset variables
  2020-11-14  5:41                         ` Roman Perepelitsa
@ 2020-11-16 19:41                           ` Felipe Contreras
  2020-11-16 20:22                             ` Roman Perepelitsa
  2020-11-17 20:54                             ` Bart Schaefer
  0 siblings, 2 replies; 53+ messages in thread
From: Felipe Contreras @ 2020-11-16 19:41 UTC (permalink / raw)
  To: Roman Perepelitsa; +Cc: Zsh hackers list

On Fri, Nov 13, 2020 at 11:41 PM Roman Perepelitsa
<roman.perepelitsa@gmail.com> wrote:
>
> On Sat, Nov 14, 2020 at 1:52 AM Felipe Contreras
> <felipe.contreras@gmail.com> wrote:
> >
> > In JavaScript if you don't declare foo, accessing it gives you the
> > value of "undefined", and if you declare it and "unset" it, it also
> > gives you "undefined".
>
> Here's what I'm getting in Chrome console:
>
>   console.log(foo)
>
>     Uncaught ReferenceError: foo is not defined
>
>   foo = undefined
>   console.log(foo)
>
>     undefined
>
> Is this behavior non-standard?

We are talking about local variables. Did you declare 'foo' as a local variable?

Moreover, JavaScript has the notion of hoisted variables:

  console.log(foo); # undefined
  var foo;

> > You just don't want to accept they are functionally the same because
> > you don't want them to be the same.
>
> Let's keep the discussion limited to the subject matter of programming
> languages.

The interpretation of language is directly related to programming languages.

You want to ignore an interpretation because it's inconvenient for you.

It is a fact the two are functionally the same.

> > Lisp doesn't allow defining variables without a value.

> A variable declared without a value gets the value of nil. You can
> pass nil around like any other value.

If "(let ((var)) ...)" is the same as "(let ((var nil)) ...)", then
it's *exactly* the same as "var = None" in Python.

> > you have avoided some of my strongest arguments, for example this:
> >
> >   func () {
> >     [[ -n "$1" ]] && var=$1
> >     dosomething ${var-other}
> >   }
> >
> >   func () {
> >     typeset var
> >     [[ -n "$1" ]] && var=$1
> >     dosomething ${var-other}
> >   }
> >
> > You have never explained how it makes sense that adding that extra
> > line changes the behavior.
>
> I thought you were arguing that the behavior of `typeset var` in
> ksh/bash makes sense while in zsh it doesn't. However, in the example
> you've given above adding `typeset var` to func changes the function's
> behavior in all shells. What am I missing?

It doesn't change the behavior of the function func(), it only changes
the scope of the variable "var" (like in all languages).

You know what the behavior of the original func() was. It seems you
are being obtuse on purpose.

> > > Moreover, [in Lua] variables to which nil has been assigned are
> > > indistinguishable from variables that have never been declared.
> > > "Variable foo is nil" has the same meaning as "variable foo does not
> > > exist". Like in shells and unlike JavaScript.
> >
> > Exactly the same thing as in JavaScript, just s/nil/undefined/.
>
> If you try to print a variable that hasn't been defined, you'll get an
> error in JavaScript and "nil" in Lua.

Declared is not the same as defined.

  func () {
    var foo;
  }

Foo is undefined, but declared with a local scope.

> > Either way, "local x" in Lua does exactly the same thing as it does in Bash.
>
> That was my point. Originally I said I didn't know of any language
> that does what ksh/bash does but then I realized that Lua could fit
> the bill, so I mentioned it. To be more specific, I was looking for a
> language that 1) allows you to declare variables without specifying
> their values; 2) allows you to unset/unbind/undeclare variables; 3)
> the effect of declaring a variable and immediately unsetting it is
> equivalent to declaring a variable without specifying the initial
> value.

1) But you ignore the languages that can use nil, which is
functionally the same as no-value.

2) But you ignore the languages that can unset the value of a variable
(using nil), which is functionally the same as no-value.

3) Which makunbound doesn't do in elisp (and var=nil does do on
virtually all languages).

> FWIW, one of my gripes with Lua is that accessing an undeclared
> variable gives you nil. If it was an error instead (which I would
> prefer), Lua wouldn't satisfy the 3rd requirement I've listed above,
> so it wouldn't be like ksh/bash for the purpose of this discussion. It
> would be like zsh and elisp.

It does satisfy 3), you just do want to accept it.

  local foo
  print(foo)

Is *exactly* the same as:

  local foo
  foo = nil -- unset
  print(foo)

All languages we explored have the same notion (inside a function):

JavaScript:

  var foo;
  console.log(foo); # undefined
  foo = 'set';
  foo = undefined' # unset()
  console.log(foo); # undefined

Python:

  foo = None
  print(foo) # None
  foo = "set"
  foo = None # unset()
  print(foo) # None

Ruby:

  foo = nil
  p foo # nil
  foo = "set"
  foo = nil # unset()
  p foo # nil

Lua:

  local foo
  print(foo) # nil
  foo = 'set'
  foo = nil # unset()
  print(foo) # nil

Emacs Lisp:

  (defun foo ()
    (let ((var))
      (print var) ; nil
      (set 'var "set")
      (set 'var nil) ; unset
      (print var) ; nil
    )
  )

Shell:

  local foo
  echo ${foo-nil} # nil
  foo="set"
  unset foo
  echo ${foo-nil} # nil

These are all functionally *exactly* the same. And that's an undeniable fact.

> > The most straightforward way is not necessarily the best way.
> >
> > Very often the best way takes effort.
>
> This is obviously true.
>
> I'll summarize my position. I believe it is in agreement with Peter
> and Bart but I wouldn't presume speaking for them.
>
> - The way typeset works in zsh makes sense. There is no inconsistency,
> there is precedence in other languages, and it was a natural evolution
> from global-only parameters.

That is an opinion. I disagree.

> - If we could change history, it would be better if typeset in zsh
> worked the same way as in ksh/bash because that behavior also makes
> sense and compatibility is valuable.

Indeed.

> - It's infeasible to change the behavior of typeset in zsh in native
> mode because it'll break too much user code.

Nothing is impossible. It's just harder when you don't even think of trying it.

> - It's feasible and desirable to make typeset compatible with ksh/bash
> when KSH_TYPESET is set.

KSH_TYPESET does something else that not even ksh does. But another
option might make sense.

Cheers.

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-16 19:41                           ` Felipe Contreras
@ 2020-11-16 20:22                             ` Roman Perepelitsa
  2020-11-17 20:28                               ` Felipe Contreras
  2020-11-17 20:54                             ` Bart Schaefer
  1 sibling, 1 reply; 53+ messages in thread
From: Roman Perepelitsa @ 2020-11-16 20:22 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Zsh hackers list

Felipe, you are doubling down on targeting *me* in your statements
despite my prior request to keep the discussion focused on programming
languages.

The discussion is going nowhere, so I suggest that we drop it.

Roman.


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

* Re: Bug with unset variables
  2020-11-16 20:22                             ` Roman Perepelitsa
@ 2020-11-17 20:28                               ` Felipe Contreras
  2020-11-18 22:45                                 ` Daniel Shahaf
  2020-11-19  2:59                                 ` Bart Schaefer
  0 siblings, 2 replies; 53+ messages in thread
From: Felipe Contreras @ 2020-11-17 20:28 UTC (permalink / raw)
  To: Roman Perepelitsa; +Cc: Zsh hackers list

On Mon, Nov 16, 2020 at 2:22 PM Roman Perepelitsa
<roman.perepelitsa@gmail.com> wrote:
>
> Felipe, you are doubling down on targeting *me* in your statements
> despite my prior request to keep the discussion focused on programming
> languages.

I am not targeting you. I am making factual objective statements:

1. A and B are functionally the same
2. You don't want to accept that A and B are functionally the same

It is 100% a fact that A and B are functionally the same, and it is
also a fact that you don't accept this fact.

The only reason the discussion is going nowhere is that you don't want
to accept this true fact, but that doesn't stop it from being a fact.

Curiously, you are also not denying the fact either, you are simply
ignoring it. Every time I say A and B are *functionally* the same, you
ignore that claim.

If you don't at least attempt to engage with that fact (which I tried
to exemplify in dozens of ways already), then I agree; we can't move
forward.

Cheers.

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-16 19:41                           ` Felipe Contreras
  2020-11-16 20:22                             ` Roman Perepelitsa
@ 2020-11-17 20:54                             ` Bart Schaefer
  2020-11-22  1:49                               ` Felipe Contreras
  1 sibling, 1 reply; 53+ messages in thread
From: Bart Schaefer @ 2020-11-17 20:54 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Roman Perepelitsa, Zsh hackers list

On Mon, Nov 16, 2020 at 11:42 AM Felipe Contreras
<felipe.contreras@gmail.com> wrote:
>
> Declared is not the same as defined.

True, but in the shell language traditionally the only way to declare
a variable was to define it.  The exception was "export VAR" which has
so far been out of scope (ha ha) for this discussion, and later
"readonly VAR" which has limited use if VAR is not also defined.

> All languages we explored have the same notion (inside a function):

I'm just going to excerpt one of these because you claim they're all
the same ...

> Python:
>
>   foo = None
>   print(foo) # None
>   foo = "set"
>   foo = None # unset()
>   print(foo) # None
>
> Shell:
>
>   local foo
>   echo ${foo-nil} # nil
>   foo="set"
>   unset foo
>   echo ${foo-nil} # nil
>
> These are all functionally *exactly* the same. And that's an undeniable fact.

Except your examples are NOT the same.  Your shell example introduces
what amounts to a ternary test.  In shell

local foo
echo -n $foo

does not output "nil" or "undefined" or "None", it outputs NOTHING.
When you throw in ${foo-nil} you're effectively writing (pseudo code)

if the variable foo has no value
then substitute nil
else substitute the value of foo
fi

There literally is no concept of "not defined" in the shell language
outside of that implicit ternary; undefined is not a first-class
value.  You cannot write "if [[ $foo == undefined ]]" or any of the
similar comparisons that can be done in most if not all of the other
languages you assert are equivalent.  You can use $anydamnthing in the
shell anywhere an empty string can be used, without producing a null
dereference or similar error -- unless of course you've activated
NO_UNSET, which by the way:

nounset_error() {
  setopt localoptions nounset
  print $foo  # error
}
nounset_ok() {
  setopt localoptions nounset
  typeset foo
  print $foo  # not error
}

So the decisions made about the behavior of typeset have ramifications
beyond your use case.

> > > The most straightforward way is not necessarily the best way.

And the perfect is often the enemy of the good.  Let's stop throwing
aphorisms at each other, especially when they can't change decisions
made decades ago.

> KSH_TYPESET does something else that not even ksh does. But another
> option might make sense.

Which particular something are you thinking of?


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

* Re: Bug with unset variables
  2020-11-17 20:28                               ` Felipe Contreras
@ 2020-11-18 22:45                                 ` Daniel Shahaf
  2020-11-22  1:20                                   ` Felipe Contreras
  2020-11-19  2:59                                 ` Bart Schaefer
  1 sibling, 1 reply; 53+ messages in thread
From: Daniel Shahaf @ 2020-11-18 22:45 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Roman Perepelitsa, Zsh hackers list

Felipe Contreras wrote on Tue, 17 Nov 2020 14:28 -0600:
> On Mon, Nov 16, 2020 at 2:22 PM Roman Perepelitsa
> <roman.perepelitsa@gmail.com> wrote:
> >
> > Felipe, you are doubling down on targeting *me* in your statements
> > despite my prior request to keep the discussion focused on programming
> > languages.  
> 
> I am not targeting you. I am making factual objective statements:
> 
> 1. A and B are functionally the same
> 2. You don't want to accept that A and B are functionally the same
> 
> It is 100% a fact that A and B are functionally the same, and it is
> also a fact that you don't accept this fact.
> 
> The only reason the discussion is going nowhere is that you don't want
> to accept this true fact, but that doesn't stop it from being a fact.
> 
> Curiously, you are also not denying the fact either, you are simply
> ignoring it. Every time I say A and B are *functionally* the same, you
> ignore that claim.
> 
> If you don't at least attempt to engage with that fact (which I tried
> to exemplify in dozens of ways already), then I agree; we can't move
> forward.

Do not argue about a person.  Argue about the technical matter at hand.

What are A and B?

Why does the Python example not use «del» as the "unset" operation?


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

* Re: Bug with unset variables
  2020-11-17 20:28                               ` Felipe Contreras
  2020-11-18 22:45                                 ` Daniel Shahaf
@ 2020-11-19  2:59                                 ` Bart Schaefer
  2020-11-22  1:50                                   ` Felipe Contreras
  1 sibling, 1 reply; 53+ messages in thread
From: Bart Schaefer @ 2020-11-19  2:59 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Roman Perepelitsa, Zsh hackers list

On Tue, Nov 17, 2020 at 12:28 PM Felipe Contreras
<felipe.contreras@gmail.com> wrote:
>
> It is 100% a fact that A and B are functionally the same, and it is
> also a fact that you don't accept this fact.

What has not yet been accepted is your proof of this "fact."  It is
100% your assertion that A and B are functionally the same, but as
I've noted, you're using behavior of languages that have a first-class
value of "undefined" to assert something about a language where there
is no such first-class value.

Your premise that zsh's default behavior is not internally consistent
is based on that assertion.

I'm curious to see your proof, but it's unlikely to convince anyone
who currently disagrees with you to undertake alteration of the
default behavior.


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

* Re: Bug with unset variables
  2020-11-18 22:45                                 ` Daniel Shahaf
@ 2020-11-22  1:20                                   ` Felipe Contreras
  2020-11-23  4:00                                     ` Daniel Shahaf
  0 siblings, 1 reply; 53+ messages in thread
From: Felipe Contreras @ 2020-11-22  1:20 UTC (permalink / raw)
  To: Daniel Shahaf; +Cc: Roman Perepelitsa, Zsh hackers list

On Wed, Nov 18, 2020 at 4:45 PM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:

> Do not argue about a person.  Argue about the technical matter at hand.

That's what I did. The technical matter was being ignored.

> What are A and B?

I already explained this multiple times:

A: unset foo
B: foo = nil

> Why does the Python example not use «del» as the "unset" operation?

Because it doesn't do the same thing as unset.

In shell, this leaves foo declared in a local scope:

  local foo # declare
  unset foo # unset

In Python, this doesn't:

  foo = None # declare
  del foo # undeclare

They are *not* functionally the same thing.

Cheers.

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-17 20:54                             ` Bart Schaefer
@ 2020-11-22  1:49                               ` Felipe Contreras
  2020-11-23  6:48                                 ` Bart Schaefer
  0 siblings, 1 reply; 53+ messages in thread
From: Felipe Contreras @ 2020-11-22  1:49 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Roman Perepelitsa, Zsh hackers list

On Tue, Nov 17, 2020 at 2:54 PM Bart Schaefer <schaefer@brasslantern.com> wrote:
>
> On Mon, Nov 16, 2020 at 11:42 AM Felipe Contreras
> <felipe.contreras@gmail.com> wrote:

> > Python:
> >
> >   foo = None
> >   print(foo) # None
> >   foo = "set"
> >   foo = None # unset()
> >   print(foo) # None
> >
> > Shell:
> >
> >   local foo
> >   echo ${foo-nil} # nil
> >   foo="set"
> >   unset foo
> >   echo ${foo-nil} # nil
> >
> > These are all functionally *exactly* the same. And that's an undeniable fact.
>
> Except your examples are NOT the same.  Your shell example introduces
> what amounts to a ternary test.  In shell
>
> local foo
> echo -n $foo
>
> does not output "nil" or "undefined" or "None", it outputs NOTHING.
> When you throw in ${foo-nil} you're effectively writing (pseudo code)
>
> if the variable foo has no value
> then substitute nil
> else substitute the value of foo
> fi

So?

Is it *functionally* the same or not?

> There literally is no concept of "not defined" in the shell language
> outside of that implicit ternary; undefined is not a first-class
> value.  You cannot write "if [[ $foo == undefined ]]" or any of the
> similar comparisons that can be done in most if not all of the other
> languages you assert are equivalent.  You can use $anydamnthing in the
> shell anywhere an empty string can be used, without producing a null
> dereference or similar error -- unless of course you've activated
> NO_UNSET, which by the way:

This is a smoke screen.

Notions don't change the behavior of the code above.

It either is *functionally* the same, or it isn't.

> > > > The most straightforward way is not necessarily the best way.
>
> And the perfect is often the enemy of the good.  Let's stop throwing
> aphorisms at each other, especially when they can't change decisions
> made decades ago.

My statement was not an aphorism, but even if it was; that doesn't
change the fact that it's true.

I was not the one that brought history into the thread. You are the
one that brought the history, which by definition cannot be changed.

If now you are saying there's no point in talking about something that
can't be changed (the past), then fine by me.

> > KSH_TYPESET does something else that not even ksh does. But another
> > option might make sense.
>
> Which particular something are you thinking of?

My understanding of that option is that it changed the behavior of this:

    typeset var=$(echo one word)

To this:

  builtin typeset var=$(echo one word)

In other words:

  typeset var=one word

But that's not what ksh does, at least the version I have installed.

Anyway, I see now that it's obsolete, so in theory it could be reused.

Cheers.

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-19  2:59                                 ` Bart Schaefer
@ 2020-11-22  1:50                                   ` Felipe Contreras
  0 siblings, 0 replies; 53+ messages in thread
From: Felipe Contreras @ 2020-11-22  1:50 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Roman Perepelitsa, Zsh hackers list

On Wed, Nov 18, 2020 at 8:59 PM Bart Schaefer <schaefer@brasslantern.com> wrote:
>
> On Tue, Nov 17, 2020 at 12:28 PM Felipe Contreras
> <felipe.contreras@gmail.com> wrote:
> >
> > It is 100% a fact that A and B are functionally the same, and it is
> > also a fact that you don't accept this fact.
>
> What has not yet been accepted is your proof of this "fact."  It is
> 100% your assertion that A and B are functionally the same, but as
> I've noted, you're using behavior of languages that have a first-class
> value of "undefined" to assert something about a language where there
> is no such first-class value.

So?

The behavior is still *functionally* the same.

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-22  1:20                                   ` Felipe Contreras
@ 2020-11-23  4:00                                     ` Daniel Shahaf
  2020-11-23  6:18                                       ` Felipe Contreras
  0 siblings, 1 reply; 53+ messages in thread
From: Daniel Shahaf @ 2020-11-23  4:00 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Roman Perepelitsa, Zsh hackers list

Felipe Contreras wrote on Sat, Nov 21, 2020 at 19:20:56 -0600:
> On Wed, Nov 18, 2020 at 4:45 PM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
> 
> > Do not argue about a person.  Argue about the technical matter at hand.
> 
> That's what I did. The technical matter was being ignored.
> 
> > What are A and B?
> 
> I already explained this multiple times:
> 
> A: unset foo
> B: foo = nil

And in Python, A is «del foo»; B is «foo = None»; and they aren't
equivalent.  Actually, more precisely, Python doesn't even *have* a B,
because Python doesn't have a syntax for declaring a variable without
a value.  (When you write «foo = None», that «None» is not implicitly
provided by the language.)

However, I don't see how any of this is an argument in favour of the
behaviour change you proposed.  Other languages' behaviours be what they
may, they're unlikely to be a good enough reason to break backwards
compatibility.  (For instance, I don't think a proposal to disable null
elision would be accepted, due to backwards compatibility concerns,
regardless of how few other languages do null elision.)

> > Why does the Python example not use «del» as the "unset" operation?
> 
> Because it doesn't do the same thing as unset.
> 
> In shell, this leaves foo declared in a local scope:
> 
>   local foo # declare
>   unset foo # unset
> 
> In Python, this doesn't:
> 
>   foo = None # declare
>   del foo # undeclare
> 
> They are *not* functionally the same thing.

In Python, the "declare" operation would be just «pass», or more
precisely, the removal of any «global foo» declarations… but, again,
unless this Python discussion somehow bears on a proposed change to zsh,
I'm not interested in continuing it.


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

* Re: Bug with unset variables
  2020-11-23  4:00                                     ` Daniel Shahaf
@ 2020-11-23  6:18                                       ` Felipe Contreras
  0 siblings, 0 replies; 53+ messages in thread
From: Felipe Contreras @ 2020-11-23  6:18 UTC (permalink / raw)
  To: Daniel Shahaf; +Cc: Roman Perepelitsa, Zsh hackers list

On Sun, Nov 22, 2020 at 10:00 PM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
>
> Felipe Contreras wrote on Sat, Nov 21, 2020 at 19:20:56 -0600:
> > On Wed, Nov 18, 2020 at 4:45 PM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
> >
> > > Do not argue about a person.  Argue about the technical matter at hand.
> >
> > That's what I did. The technical matter was being ignored.
> >
> > > What are A and B?
> >
> > I already explained this multiple times:
> >
> > A: unset foo
> > B: foo = nil
>
> And in Python, A is «del foo»; B is «foo = None»; and they aren't
> equivalent.  Actually, more precisely, Python doesn't even *have* a B,
> because Python doesn't have a syntax for declaring a variable without
> a value.  (When you write «foo = None», that «None» is not implicitly
> provided by the language.)

Are your A and B functionally the same?

No.

Are my A and B functionally the same?

Yes.

Those are undeniable facts.

> However, I don't see how any of this is an argument in favour of the
> behaviour change you proposed.  Other languages' behaviours be what they
> may, they're unlikely to be a good enough reason to break backwards
> compatibility.  (For instance, I don't think a proposal to disable null
> elision would be accepted, due to backwards compatibility concerns,
> regardless of how few other languages do null elision.)

I made the claim and I've substantiated it. Others disagreed with the
claim, and argued against it.

If you don't see how the fact that virtually all languages do the same
thing as Bash and ksh is relevant, then don't argue against the claim.

But my claim still stands.

> > > Why does the Python example not use «del» as the "unset" operation?
> >
> > Because it doesn't do the same thing as unset.
> >
> > In shell, this leaves foo declared in a local scope:
> >
> >   local foo # declare
> >   unset foo # unset
> >
> > In Python, this doesn't:
> >
> >   foo = None # declare
> >   del foo # undeclare
> >
> > They are *not* functionally the same thing.
>
> In Python, the "declare" operation would be just «pass», or more
> precisely, the removal of any «global foo» declarations… but, again,
> unless this Python discussion somehow bears on a proposed change to zsh,
> I'm not interested in continuing it.

No. That's not how you declare local variables in Python.

If you are not interested in continuing it then don't argue against it.

Either argue against my claim or don't, but you can't have your cake
and eat it too.

Cheers.

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-22  1:49                               ` Felipe Contreras
@ 2020-11-23  6:48                                 ` Bart Schaefer
  2020-11-23  7:26                                   ` Felipe Contreras
  0 siblings, 1 reply; 53+ messages in thread
From: Bart Schaefer @ 2020-11-23  6:48 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Roman Perepelitsa, Zsh hackers list

On Sat, Nov 21, 2020 at 5:49 PM Felipe Contreras
<felipe.contreras@gmail.com> wrote:
>
> On Tue, Nov 17, 2020 at 2:54 PM Bart Schaefer <schaefer@brasslantern.com> wrote:
> >
> > There literally is no concept of "not defined" in the shell language
> > outside of that implicit ternary; undefined is not a first-class
> > value.
>
> This is a smoke screen.

This statement confuses me.   If you are insinuating that I'm raising
a point solely for the purpose of obfuscating the discussion, then
either (a) you haven't been paying attention to anything I've written
on this mailing list in the past 25 years, or (b) I'm forced to
believe you're actively attempting to be insulting.

> It either is *functionally* the same, or it isn't.

You keep "shouting" that word as if saying it louder is all that's necessary.

> I was not the one that brought history into the thread. You are the
> one that brought the history, which by definition cannot be changed.

You asked why zsh's default behavior is what it is; the answer is
historical practice.

Unless I've misunderstood something, the subsequent discussion has
focused on the idea that we should change the default, despite that
breaking several precedents, because the default behavior is not
internally consistent, and that the reason it's not consistent is
because of the notion that unsetting a variable is equivalent to
assigning it an undefined value.

Even if we grant the latter, which I don't think everyone does, it
still doesn't follow that the only consistent choice for the default
state of a declared variable is unset.

> My understanding of [KSH_TYPESET] is that it changed the behavior of this:
>
>     typeset var=$(echo one word)
>
> To this:
>
>   builtin typeset var=$(echo one word)

No; it changes the former to something closer to

    typeset var="$(echo one word)"

because *without* the option, it was interpreted as

>   typeset var=one word


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

* Re: Bug with unset variables
  2020-11-23  6:48                                 ` Bart Schaefer
@ 2020-11-23  7:26                                   ` Felipe Contreras
  2020-11-23 20:26                                     ` Bart Schaefer
  0 siblings, 1 reply; 53+ messages in thread
From: Felipe Contreras @ 2020-11-23  7:26 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Roman Perepelitsa, Zsh hackers list

On Mon, Nov 23, 2020 at 12:48 AM Bart Schaefer
<schaefer@brasslantern.com> wrote:
>
> On Sat, Nov 21, 2020 at 5:49 PM Felipe Contreras
> <felipe.contreras@gmail.com> wrote:
> >
> > On Tue, Nov 17, 2020 at 2:54 PM Bart Schaefer <schaefer@brasslantern.com> wrote:
> > >
> > > There literally is no concept of "not defined" in the shell language
> > > outside of that implicit ternary; undefined is not a first-class
> > > value.
> >
> > This is a smoke screen.
>
> This statement confuses me.   If you are insinuating that I'm raising
> a point solely for the purpose of obfuscating the discussion, then
> either (a) you haven't been paying attention to anything I've written
> on this mailing list in the past 25 years, or (b) I'm forced to
> believe you're actively attempting to be insulting.

No. A smoke screen screen doesn't have to be intentional.

I am saying X doesn't have anything to do with Y. You are arguing Y,
IMO all that is doing is diverting attention from X.

> > It either is *functionally* the same, or it isn't.
>
> You keep "shouting" that word as if saying it louder is all that's necessary.

Nope. I demonstrated how they are functionally the same with plenty of examples.

> > I was not the one that brought history into the thread. You are the
> > one that brought the history, which by definition cannot be changed.
>
> You asked why zsh's default behavior is what it is; the answer is
> historical practice.

Indeed, and that's all that was needed to answer *that* particular question.

But then you used an historic argument to counter my claim that Zsh
was not consistent. Go look at mid [1] (I don't know how you link to
the archives, which don't seem to be updated).

This is an entirely different matter.

> Unless I've misunderstood something, the subsequent discussion has
> focused on the idea that we should change the default, despite that
> breaking several precedents, because the default behavior is not
> internally consistent, and that the reason it's not consistent is
> because of the notion that unsetting a variable is equivalent to
> assigning it an undefined value.

No. Again, go back to mid [1]. I specifically said:

"Adding a setopt option for the new behavior doesn't break a lot of
existing zsh code."

I argued it makes sense to add a setopt option that turns on the
behavior that a) in my opinion is more consistent, b) is what Bash and
ksh does, and c) is the equivalent of what virtually all languages do.

> Even if we grant the latter, which I don't think everyone does, it
> still doesn't follow that the only consistent choice for the default
> state of a declared variable is unset.

But it does follow. I already presented several arguments, most of
which have not been even addressed at all. Would like me to list them
all in a document so it's clear how they have not been addressed?

> > My understanding of [KSH_TYPESET] is that it changed the behavior of this:
> >
> >     typeset var=$(echo one word)
> >
> > To this:
> >
> >   builtin typeset var=$(echo one word)
>
> No; it changes the former to something closer to
>
>     typeset var="$(echo one word)"
>
> because *without* the option, it was interpreted as
>
> >   typeset var=one word

OK. So it's the other way around.

But this actually sets a precedent for an option that turns on
behavior similar to that of ksh, that eventually becomes the default,
because presumably it eventually made sense.

The same could happen in this case... Eventually.

Either way, I don't see any argument against adding an option (or
reusing) to turn on this behavior.

Cheers.

[1] CAH+w=7ZwyKq_RxM_RXWu42Y-RbCkRtrLTqesfqCmFNc_C_CwoA@mail.gmail.com

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-23  7:26                                   ` Felipe Contreras
@ 2020-11-23 20:26                                     ` Bart Schaefer
  2020-11-23 23:39                                       ` Felipe Contreras
  0 siblings, 1 reply; 53+ messages in thread
From: Bart Schaefer @ 2020-11-23 20:26 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Zsh hackers list

On Sun, Nov 22, 2020 at 11:27 PM Felipe Contreras
<felipe.contreras@gmail.com> wrote:
>
> Nope. I demonstrated how they are functionally the same with plenty of examples.

All of your examples are from other languages.

> But then you used an historic argument to counter my claim that Zsh
> was not consistent.

The historic reference was for context.  The actual argument is that
zsh is consistent because the behavior of variables inside function
scope mirrors that of variables at global scope.  History is merely
why variables behave that way at global scope.

Your argument is that zsh was wrong to adopt that interpretation of
variables in function scope.  That doesn't make it (internally)
inconsistent, it just makes it different.

But there are plenty of other ways that the shell language is
different from pretty much any other language you can name.  Korn has
spent years and many revisions gradually dragging in concepts from
other languages.  Zsh has so far (often just for lack of developer
time/attention) not attempted to track with all of those.

However ...

> I argued it makes sense to add a setopt option that turns on the
> behavior that a) in my opinion is more consistent, b) is what Bash and
> ksh does, and c) is the equivalent of what virtually all languages do.

That's where we could have been ten days ago, but you said (of
changing the default) ...

"Nothing is impossible. It's just harder when you don't even think of
trying it."

... so we've been down the rabbit hole of arguing necessary/desirable.

To hopefully tie this off, does anyone want to argue for a new option
instead of adding this to KSH_TYPESET?


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

* Re: Bug with unset variables
  2020-11-23 20:26                                     ` Bart Schaefer
@ 2020-11-23 23:39                                       ` Felipe Contreras
  2020-11-24  0:52                                         ` Bart Schaefer
  0 siblings, 1 reply; 53+ messages in thread
From: Felipe Contreras @ 2020-11-23 23:39 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

On Mon, Nov 23, 2020 at 2:26 PM Bart Schaefer <schaefer@brasslantern.com> wrote:
>
> On Sun, Nov 22, 2020 at 11:27 PM Felipe Contreras
> <felipe.contreras@gmail.com> wrote:
> >
> > Nope. I demonstrated how they are functionally the same with plenty of examples.
>
> All of your examples are from other languages.

"It" in this case is code from Python compared with code from shell
which is functionally the same, that is to say: it does the same
thing.

Of course it's from other languages. That's precisely what is being compared.

> > But then you used an historic argument to counter my claim that Zsh
> > was not consistent.
>
> The historic reference was for context.  The actual argument is that
> zsh is consistent because the behavior of variables inside function
> scope mirrors that of variables at global scope.  History is merely
> why variables behave that way at global scope.

You used history to explain what was the most straightforward way to
implement the new feature without much architectural changes in zsh.

This does not imply it was the best way to do it, nor does it show it
is consistent from the user's point of view, because it's 100%
dependent on the implementation of the shell.

> Your argument is that zsh was wrong to adopt that interpretation of
> variables in function scope.  That doesn't make it (internally)
> inconsistent, it just makes it different.

I did not argue it was internally inconsistent.

I grant you--after looking at the code--the change was likely
internally consistent.

My argument is about the consistency from user's perspective.

This is the example I gave to Roman, which went completely unresponded:

  func () {
    [[ -n "$1" ]] && var=$1
    dosomething ${var-other}
  }

  func () {
    typeset var
    [[ -n "$1" ]] && var=$1
    dosomething ${var-other}
  }

> > I argued it makes sense to add a setopt option that turns on the
> > behavior that a) in my opinion is more consistent, b) is what Bash and
> > ksh does, and c) is the equivalent of what virtually all languages do.
>
> That's where we could have been ten days ago, but you said (of
> changing the default) ...
>
> "Nothing is impossible. It's just harder when you don't even think of
> trying it."

Yes, that was in response to you saying it was infeasible to change the default.

I argued that nothing is impossible. It may be infeasible in the final
analysis, but maybe not, the only way we could know is if it's tried
first (with an option).

So it's perfectly consistent to argue both: a) a setopt option makes
sense now, and b) eventually this option can be considered to be the
default and it's not necessarily completely infeasible.

> ... so we've been down the rabbit hole of arguing necessary/desirable.
>
> To hopefully tie this off, does anyone want to argue for a new option
> instead of adding this to KSH_TYPESET?

Not me. I'd say any way to enable this mode would be fine, and if
there's no conflict with KSH_TYPESET, that sounds like a sensible
option.

Cheers.

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-23 23:39                                       ` Felipe Contreras
@ 2020-11-24  0:52                                         ` Bart Schaefer
  2020-11-25  8:46                                           ` Felipe Contreras
  0 siblings, 1 reply; 53+ messages in thread
From: Bart Schaefer @ 2020-11-24  0:52 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Zsh hackers list

On Mon, Nov 23, 2020 at 3:39 PM Felipe Contreras
<felipe.contreras@gmail.com> wrote:
>
> My argument is about the consistency from user's perspective.

Consistent from what user's point of view?  One coming to zsh from
other languages or one long familiar with zsh?  Because zsh
development has consistently (ahem) sided with the latter.

> This is the example I gave to Roman, which went completely unresponded:
>
>   func () {
>     [[ -n "$1" ]] && var=$1
>     dosomething ${var-other}
>   }
>
>   func () {
>     typeset var
>     [[ -n "$1" ]] && var=$1
>     dosomething ${var-other}
>   }

In the first case, $var is a global, so the behavior of ${var-other}
is unknown.  It's not possible to write deterministic code.

In the second case, there's a knowable behavior of ${var-other}.  That
behavior doesn't match your expectation, but it's well-defined.

To make the first function deterministic, it is necessary to write:

func () {
  unset var
  [[ -n "$1" ]] && var=$1
  dosomething ${var-other}
}

Whether one should expect "typeset var" to imply "unset" is how we
ended up in this discussion.


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

* Re: Bug with unset variables
  2020-11-24  0:52                                         ` Bart Schaefer
@ 2020-11-25  8:46                                           ` Felipe Contreras
  2020-11-27 15:44                                             ` Daniel Shahaf
  0 siblings, 1 reply; 53+ messages in thread
From: Felipe Contreras @ 2020-11-25  8:46 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

On Mon, Nov 23, 2020 at 6:52 PM Bart Schaefer <schaefer@brasslantern.com> wrote:
>
> On Mon, Nov 23, 2020 at 3:39 PM Felipe Contreras
> <felipe.contreras@gmail.com> wrote:
> >
> > My argument is about the consistency from user's perspective.
>
> Consistent from what user's point of view?

Any user.

> One coming to zsh from
> other languages or one long familiar with zsh?  Because zsh
> development has consistently (ahem) sided with the latter.

Users can get accustomed to inconsistent behavior.

The fact that some users have become accustomed to X doesn't mean X is
consistent.

> > This is the example I gave to Roman, which went completely unresponded:
> >
> >   func () {
> >     [[ -n "$1" ]] && var=$1
> >     dosomething ${var-other}
> >   }
> >
> >   func () {
> >     typeset var
> >     [[ -n "$1" ]] && var=$1
> >     dosomething ${var-other}
> >   }
>
> In the first case, $var is a global, so the behavior of ${var-other}
> is unknown.  It's not possible to write deterministic code.

You are looking at the half of the picture that is irrelevant.

The behavior of "func foobar" is deterministic, and you know what it will do.

> In the second case, there's a knowable behavior of ${var-other}.  That
> behavior doesn't match your expectation, but it's well-defined.

Nobody is saying it's not well-defined, we are talking about *consistency*.

Only *one* change was added to B, and the behavior changed in *two* ways.

> To make the first function deterministic, it is necessary to write:
>
> func () {
>   unset var
>   [[ -n "$1" ]] && var=$1
>   dosomething ${var-other}
> }
>
> Whether one should expect "typeset var" to imply "unset" is how we
> ended up in this discussion.

The only difference from A to B is that B has a line that says
"declare 'var' as a local variable". That's a fact.

And the behavior of the function changes in two ways (other than what
was told to do). That's also a fact.

It is a fact that the code is doing more than what it was told to do.

If you have an operator called "declare_local_variable", and you do this:

  declare_local_variable var

You run the code, and you find that declare_local_variable does indeed
declare a local variable, but it *also* sets your cat on fire.

You investigate, and you find out the documentation clearly states
that declare_local_variable sets your cat on fire, so the behavior is
"well-defined". But it's not what it says on the tin.

Any normal person would expect such behavior to be enabled by:

  declare_local_variable var
  set_cat_on_fire

And not have to type:

  delcare_local_variable_but_dont_set_cat_on_fire var

Or worse:

  declare_local_variable var
  put_out_fire_from_cat

It doesn't matter how well explained it is in the documentation, or
how many people are accustomed to this behavior, it's still doing
*more* than one thing.

Now, you can call the fact that it's changing the behavior in more
than one way any way you want. When most operators in most languages
do one thing--and one thing only--and this operator does *two* things,
I call that inconsistent.

Maybe there's a better way to describe this fact. Maybe Git's notion
of logically separate changes [1] helps (e.g. you should not mix
whitespace cleanups with functional changes). But the fact is that in
virtually all languages (and bash and ksh) there's an idiom to declare
a local variable and *only* declare a local variable (not do anything
else).

Can we at least agree on that? In zsh typeset does *two* things.

Cheers.

[1] https://git-scm.com/docs/SubmittingPatches

-- 
Felipe Contreras


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

* Re: Bug with unset variables
  2020-11-25  8:46                                           ` Felipe Contreras
@ 2020-11-27 15:44                                             ` Daniel Shahaf
  2020-11-27 20:49                                               ` Felipe Contreras
  0 siblings, 1 reply; 53+ messages in thread
From: Daniel Shahaf @ 2020-11-27 15:44 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Bart Schaefer, Zsh hackers list

Felipe Contreras wrote on Wed, Nov 25, 2020 at 02:46:40 -0600:
> Maybe there's a better way to describe this fact. Maybe Git's notion
> of logically separate changes [1] helps (e.g. you should not mix
> whitespace cleanups with functional changes). But the fact is that in
> virtually all languages (and bash and ksh) there's an idiom to declare
> a local variable and *only* declare a local variable (not do anything
> else).
> 
> Can we at least agree on that? In zsh typeset does *two* things.

I'd rather say that «typeset» does one thing — it ${verb}s a variable
(for some value of $verb) — and the zsh data model doesn't feature
a "Not really a value" value, so the variable necessarily gets _some_
value, like «int foo;» in C.



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

* Re: Bug with unset variables
  2020-11-27 15:44                                             ` Daniel Shahaf
@ 2020-11-27 20:49                                               ` Felipe Contreras
  2020-11-27 20:59                                                 ` Daniel Shahaf
  0 siblings, 1 reply; 53+ messages in thread
From: Felipe Contreras @ 2020-11-27 20:49 UTC (permalink / raw)
  To: Daniel Shahaf; +Cc: Bart Schaefer, Zsh hackers list

On Fri, Nov 27, 2020 at 9:44 AM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
>
> Felipe Contreras wrote on Wed, Nov 25, 2020 at 02:46:40 -0600:
> > Maybe there's a better way to describe this fact. Maybe Git's notion
> > of logically separate changes [1] helps (e.g. you should not mix
> > whitespace cleanups with functional changes). But the fact is that in
> > virtually all languages (and bash and ksh) there's an idiom to declare
> > a local variable and *only* declare a local variable (not do anything
> > else).
> >
> > Can we at least agree on that? In zsh typeset does *two* things.
>
> I'd rather say that «typeset» does one thing — it ${verb}s a variable
> (for some value of $verb) — and the zsh data model doesn't feature
> a "Not really a value" value, so the variable necessarily gets _some_
> value, like «int foo;» in C.

If it's really one thing, then why does adding it in the example above
changes the behavior in *two* ways?

  func () {
    [[ -n "$1" ]] && var=$1
    dosomething ${var-other}
  }

  func () {
    typeset var
    [[ -n "$1" ]] && var=$1
    dosomething ${var-other}
  }

-- 
Felipe Contreras



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

* Re: Bug with unset variables
  2020-11-27 20:49                                               ` Felipe Contreras
@ 2020-11-27 20:59                                                 ` Daniel Shahaf
  2020-11-27 21:33                                                   ` Bart Schaefer
  0 siblings, 1 reply; 53+ messages in thread
From: Daniel Shahaf @ 2020-11-27 20:59 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Zsh hackers list

Felipe Contreras wrote on Fri, 27 Nov 2020 20:49 +00:00:
> On Fri, Nov 27, 2020 at 9:44 AM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
> >
> > Felipe Contreras wrote on Wed, Nov 25, 2020 at 02:46:40 -0600:
> > > Maybe there's a better way to describe this fact. Maybe Git's notion
> > > of logically separate changes [1] helps (e.g. you should not mix
> > > whitespace cleanups with functional changes). But the fact is that in
> > > virtually all languages (and bash and ksh) there's an idiom to declare
> > > a local variable and *only* declare a local variable (not do anything
> > > else).
> > >
> > > Can we at least agree on that? In zsh typeset does *two* things.
> >
> > I'd rather say that «typeset» does one thing — it ${verb}s a variable
> > (for some value of $verb) — and the zsh data model doesn't feature
> > a "Not really a value" value, so the variable necessarily gets _some_
> > value, like «int foo;» in C.
> 
> If it's really one thing, then why does adding it in the example above
> changes the behavior in *two* ways?

What two ways?

>   func () {
>     [[ -n "$1" ]] && var=$1
>     dosomething ${var-other}
>   }
> 
>   func () {
>     typeset var
>     [[ -n "$1" ]] && var=$1
>     dosomething ${var-other}
>   }
> 
> -- 
> Felipe Contreras
>



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

* Re: Bug with unset variables
  2020-11-27 20:59                                                 ` Daniel Shahaf
@ 2020-11-27 21:33                                                   ` Bart Schaefer
  2020-11-27 23:37                                                     ` Daniel Shahaf
  0 siblings, 1 reply; 53+ messages in thread
From: Bart Schaefer @ 2020-11-27 21:33 UTC (permalink / raw)
  To: Daniel Shahaf; +Cc: Felipe Contreras, Zsh hackers list

On Fri, Nov 27, 2020 at 1:00 PM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
>
> What two ways?

1) makes var a local name
2) changes the result of ${var-other}



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

* Re: Bug with unset variables
  2020-11-27 21:33                                                   ` Bart Schaefer
@ 2020-11-27 23:37                                                     ` Daniel Shahaf
  2020-11-27 23:45                                                       ` Bart Schaefer
  2020-11-28  0:24                                                       ` Bart Schaefer
  0 siblings, 2 replies; 53+ messages in thread
From: Daniel Shahaf @ 2020-11-27 23:37 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Felipe Contreras, Zsh hackers list

Bart Schaefer wrote on Fri, 27 Nov 2020 21:33 +00:00:
> On Fri, Nov 27, 2020 at 1:00 PM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
> >
> > What two ways?
> 
> 1) makes var a local name
> 2) changes the result of ${var-other}

See the third hunk of workers/47576 in combination with my last answer.

The best way to move forward would be to write a patch against the Test/
directory that specifies the proposed behaviour.  Use the "f" flag so
all newly-added tests will run, rather than just the first.

Daniel



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

* Re: Bug with unset variables
  2020-11-27 23:37                                                     ` Daniel Shahaf
@ 2020-11-27 23:45                                                       ` Bart Schaefer
  2020-11-28  0:24                                                       ` Bart Schaefer
  1 sibling, 0 replies; 53+ messages in thread
From: Bart Schaefer @ 2020-11-27 23:45 UTC (permalink / raw)
  To: Daniel Shahaf; +Cc: Felipe Contreras, Zsh hackers list

On Fri, Nov 27, 2020 at 3:38 PM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
>
> Bart Schaefer wrote on Fri, 27 Nov 2020 21:33 +00:00:
> > On Fri, Nov 27, 2020 at 1:00 PM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
> > >
> > > What two ways?
> >
> > 1) makes var a local name
> > 2) changes the result of ${var-other}
>
> See the third hunk of workers/47576 in combination with my last answer.
>
> The best way to move forward would be to write a patch against the Test/
> directory that specifies the proposed behaviour.  Use the "f" flag so
> all newly-added tests will run, rather than just the first.
>
> Daniel



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

* Re: Bug with unset variables
  2020-11-27 23:37                                                     ` Daniel Shahaf
  2020-11-27 23:45                                                       ` Bart Schaefer
@ 2020-11-28  0:24                                                       ` Bart Schaefer
  2020-11-28  7:32                                                         ` Bart Schaefer
  2020-11-28 12:05                                                         ` Felipe Contreras
  1 sibling, 2 replies; 53+ messages in thread
From: Bart Schaefer @ 2020-11-28  0:24 UTC (permalink / raw)
  To: Daniel Shahaf; +Cc: Zsh hackers list

[Apparently when I tried to go look at another message, a blank reply
got sent off.]

On Fri, Nov 27, 2020 at 3:38 PM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
>
> The best way to move forward would be to write a patch against the Test/
> directory that specifies the proposed behaviour.  Use the "f" flag so
> all newly-added tests will run, rather than just the first.

There are existing tests that specifically check for the current
behavior, so it's not as if this were simply overlooked.

To write the proposed new test cases, we need to decide (this list may
not be all-inclusive):

whether this is going to be attached to an option (and which one, now
that Oliver to at least some extent disagrees with KSH_TYPESET) or is
controlled by emulation mode;

what happens to "setopt NO_UNSET";

what "typeset -p" outputs following "unset".;

what happens when each (any) of the EFHLRTZilu options are passed to typeset;

whether we are OK with the implications of the foregoing when the -x
option is also present.



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

* Re: Bug with unset variables
  2020-11-28  0:24                                                       ` Bart Schaefer
@ 2020-11-28  7:32                                                         ` Bart Schaefer
  2020-11-28 12:05                                                         ` Felipe Contreras
  1 sibling, 0 replies; 53+ messages in thread
From: Bart Schaefer @ 2020-11-28  7:32 UTC (permalink / raw)
  To: Zsh hackers list

On Fri, Nov 27, 2020 at 4:24 PM Bart Schaefer <schaefer@brasslantern.com> wrote:
>
> To write the proposed new test cases, we need to decide (this list may
> not be all-inclusive):

More items:

what should ${(t)var} do

what should the (i) and (I) subscript flags do



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

* Re: Bug with unset variables
  2020-11-28  0:24                                                       ` Bart Schaefer
  2020-11-28  7:32                                                         ` Bart Schaefer
@ 2020-11-28 12:05                                                         ` Felipe Contreras
  1 sibling, 0 replies; 53+ messages in thread
From: Felipe Contreras @ 2020-11-28 12:05 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Daniel Shahaf, Zsh hackers list

On Fri, Nov 27, 2020 at 6:25 PM Bart Schaefer <schaefer@brasslantern.com> wrote:

> On Fri, Nov 27, 2020 at 3:38 PM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
> >
> > The best way to move forward would be to write a patch against the Test/
> > directory that specifies the proposed behaviour.  Use the "f" flag so
> > all newly-added tests will run, rather than just the first.
>
> There are existing tests that specifically check for the current
> behavior, so it's not as if this were simply overlooked.
>
> To write the proposed new test cases, we need to decide (this list may
> not be all-inclusive):

Yeah, I agree it's not as straightforward as it initially seemed.

I can write a test case for what I think should be the desired
behavior in the typical case: "typeset var" does *not* set var to an
empty string.

But that ignores most of the discussion that has already happened
here, and it seems in the Austin CSRG.

I bet it's possible to write the code that passes the above test-case,
but ten years from now--and if not, it will be twenty years from
now--somebody will try to add "local" to POSIX again, and zsh will
still be an inconsistent state.

Personally, I would rather attempt to do it right today, than add a
hack that sort of does what I initially wanted.

Maybe we are wasting time chasing multiple tails, but maybe we are
onto something.

Considering that POSIX hasn't managed to crack the problem after
essentially half a century, maybe a couple of mails in this mailing
list couldn't hurt.

When the solution requires creativity, you just can't know where it
could come from.

Cheers.

-- 
Felipe Contreras



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

end of thread, other threads:[~2020-11-28 12:05 UTC | newest]

Thread overview: 53+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-11 15:57 Bug with unset variables Felipe Contreras
2020-11-11 16:13 ` Roman Perepelitsa
2020-11-11 16:56   ` Felipe Contreras
2020-11-11 17:02     ` Roman Perepelitsa
2020-11-11 18:03       ` Felipe Contreras
2020-11-11 18:16         ` Roman Perepelitsa
2020-11-11 20:42           ` Felipe Contreras
2020-11-12  0:20             ` Mikael Magnusson
2020-11-12  1:10               ` Felipe Contreras
2020-11-12  8:45             ` Roman Perepelitsa
2020-11-12 10:47               ` Peter Stephenson
2020-11-12 18:48                 ` Bart Schaefer
2020-11-12 19:49                 ` Felipe Contreras
2020-11-12 18:46               ` Felipe Contreras
2020-11-12 19:10                 ` Roman Perepelitsa
2020-11-12 21:08                   ` Felipe Contreras
2020-11-13  8:51                     ` Roman Perepelitsa
2020-11-14  0:52                       ` Felipe Contreras
2020-11-14  5:41                         ` Roman Perepelitsa
2020-11-16 19:41                           ` Felipe Contreras
2020-11-16 20:22                             ` Roman Perepelitsa
2020-11-17 20:28                               ` Felipe Contreras
2020-11-18 22:45                                 ` Daniel Shahaf
2020-11-22  1:20                                   ` Felipe Contreras
2020-11-23  4:00                                     ` Daniel Shahaf
2020-11-23  6:18                                       ` Felipe Contreras
2020-11-19  2:59                                 ` Bart Schaefer
2020-11-22  1:50                                   ` Felipe Contreras
2020-11-17 20:54                             ` Bart Schaefer
2020-11-22  1:49                               ` Felipe Contreras
2020-11-23  6:48                                 ` Bart Schaefer
2020-11-23  7:26                                   ` Felipe Contreras
2020-11-23 20:26                                     ` Bart Schaefer
2020-11-23 23:39                                       ` Felipe Contreras
2020-11-24  0:52                                         ` Bart Schaefer
2020-11-25  8:46                                           ` Felipe Contreras
2020-11-27 15:44                                             ` Daniel Shahaf
2020-11-27 20:49                                               ` Felipe Contreras
2020-11-27 20:59                                                 ` Daniel Shahaf
2020-11-27 21:33                                                   ` Bart Schaefer
2020-11-27 23:37                                                     ` Daniel Shahaf
2020-11-27 23:45                                                       ` Bart Schaefer
2020-11-28  0:24                                                       ` Bart Schaefer
2020-11-28  7:32                                                         ` Bart Schaefer
2020-11-28 12:05                                                         ` Felipe Contreras
2020-11-12 19:26                 ` Bart Schaefer
2020-11-12 21:48                   ` Felipe Contreras
2020-11-13 22:17                     ` Bart Schaefer
2020-11-14  0:58                       ` Felipe Contreras
2020-11-11 18:36         ` Bart Schaefer
2020-11-11 21:08           ` Felipe Contreras
2020-11-11 17:02     ` Peter Stephenson
2020-11-11 18:05       ` Felipe Contreras

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