Subject: Re: [PATCH] typeset: set $? on incidental error
From: Eric Cook <[email-masked]>
To: [email-masked]
Date: Wed, 20 Jan 2016 10:00:12 -0500
List-Id: Zsh Workers List <zsh-workers.zsh.org>

On 01/20/2016 02:47 AM, Daniel Shahaf wrote:
> Mikael Magnusson wrote on Mon, Jan 18, 2016 at 05:38:17 +0100:
>> On Mon, Jan 18, 2016 at 3:25 AM, Daniel Shahaf <[email-masked]> wrote:
>>> Mikael Magnusson wrote on Fri, Jan 15, 2016 at 15:46:09 +0100:
>>>> On Fri, Jan 15, 2016 at 7:26 AM, Daniel Shahaf <[email-masked]> wrote:
>>>>> Eric Cook wrote on Thu, Jan 14, 2016 at 00:24:36 -0500:
>>>>>> On 01/13/2016 07:13 PM, Daniel Shahaf wrote:
>>>>>>> The 'typeset' family of builtins doesn't set $? when one would expect it
>>>>>>> to do so:
>>>>>>>
>>>>>>>     % x=$(true) y=$(exit 42); echo $?
>>>>>>>     42
>>>>>>>     % local x=$(true) y=$(exit 42); echo $?
>>>>>>>     0
>>>>>>>
>>>>>>> This patch makes 'typeset' behave as ordiary assignment does.
>>>>>>
>>>>>>
>>>>>> But who expects that?
>>>>>
>>>>> I did.
>>>>
>>>> local/typeset is a command, and it was successful, so I don't see why
>>>> $? should be set to anything else than 0.
>>>> % true x=$(false); echo $?
>>>> 0
>>>> is technically exactly the same situation as your above second command.
>>>
>>> I wouldn't call it successful: I asked for the parameter x to be created
>>> as a scalar and assigned a value and only part of my request was
>>> accomplished.
>>
>> That's not true, the parameter is created and assigned the value you
>> asked for (your command subst had empty output so the parameter is ""
>> but if you did local y=$(echo hi; exit 42) it would be "hi".)
> 
> In real-life examples, if the command subst had a non-zero exit status,
> the value would typically _not_ be the one I asked for:
> 
>     % cd $(mktemp -d)
>     % local mtime=$(zstat +mtime myfile)
>     zstat: myfile: no such file or directory
>     % echo ${(q)mtime} $? 
>     '' 1
> 
But local is still the last command to run and local successfully created
the parameter mtime. The commands that may possibly execute during the
parsing of the line, affecting the actual command's exit status is a weird
side effect that doesn't happen elsewhere.

The change is only useful if mtime is the last argument for local.
x=$(exit 42) y=$(true); echo $?
0

So in the event that you actually care about the exit status of a command
during assignment, explicitly testing a normal assignment after making the
parameter local makes sense.

local mtime
if mtime=$(zstat +mtime myfile); then ...

The last command to run in the conditional is actually zstat, so $? changing
is logically there.