s/puts them/puts the result/

On Thu, Jan 11, 2018 at 8:57 AM, Axel Wagner <axel.wagner...@googlemail.com>
wrote:

> On Thu, Jan 11, 2018 at 8:10 AM, 'Eric Johnson' via golang-nuts <
> golang-nuts@googlegroups.com> wrote:
>
>> I was looking at fixing an issue flagged by gometalinter, and realized I
>> didn't understand the actual behavior of defer statements. Specifically, I
>> was not handling the error return of a close operation.
>>
>> I wrote a test program so I could understand the behavior, which led to
>> these two function
>>
>> package main
>>
>> import "fmt"
>>
>> func checkDefer(newVal int, val *int) {
>> fmt.Printf("current value is %v\n", *val)
>> *val = newVal
>> }
>>
>> func main() {
>> fmt.Printf("variableOnUnnamedReturn value is %v, expected 30\n",
>> variableOnUnnamedReturn(20, 25, 30))
>> fmt.Printf("variableOnNamedReturn value is %v, expected 45\n",
>> variableOnNamedReturn(35, 40, 45))
>> }
>>
>> func variableOnUnnamedReturn(start, test, def int) int {
>> retval := start
>> defer checkDefer(def, &retval)
>> retval = test
>> return retval
>> }
>>
>> func variableOnNamedReturn(start, test, def int) (retval int) {
>> retval = start
>> defer checkDefer(def, &retval)
>> retval = test
>> return retval
>> }
>>
>>
>> The body of the two functions differs only by a single ":", and yet, the
>> output of the Printf calls differs. This appears to be due to very subtle
>> differences between how named and unnamed returns are handled in the
>> context of defer statements.
>>
>
> There are basically two reasons
> <https://github.com/golang/go/wiki/CodeReviewComments#named-result-parameters>
> to use named return values: 1) Documentation, 2) Do what you are doing here.
> It is interesting, though, that you find it confusing. To me, it always
> seemed kind of natural, that a defered function executes *after* the
> return. If you accept that part, the behavior should be very clear, IMO.
>
> I looked through the language spec, and did not see this clearly spelled
>> out.
>>
>
> It's spelled out here <https://golang.org/ref/spec#Defer_statements>,
> that defered functions can modify named returns. Though you are right that
> it's not explicitly spelled out whether they execute before, after or
> concurrent with the return statement.
>
>
>> It is not obvious to me, a relatively experience Go developer, that the 
>> "variableOnUnnamedReturn"
>> function should return a 25 in the above use, but the "variableOnNamedReturn"
>> function returns a 45 in the above use.
>>
>
>> As near as I can tell, operationally, the "unnamed" return could be
>> re-written in something like the following fashion (where addDeferredOps is
>> a collector for deferred operations.):
>>
>>         retval := start
>>         dos := addDeferredOps(func() { checkDefer(def, &retval)} )
>>         retval = test
>>         _retval1_ = retval
>>         dos.performDeferredOps()
>>         return _retval1_
>>
>> Which makes it obvious that the call to checkDefer() won't change the
>> return of the function. Whereas, the "named return" version effectively
>> amounts to this:
>>
>>         retval := start
>>         dos := addDeferredOps(func() { checkDefer(def, &retval)} )
>>         retval = test
>>         dos.performDeferredOps()
>>         return retval
>>
>> I read the language spec, and simply didn't see the description of the
>> difference between these two behaviors. Seems mostly like a language bug,
>> to me. Feels like the named and unnamed return cases should behave the same.
>>
>
> I don't agree. Currently, the sequence of a return is
>
> 1. The expressions in the return statement are evaluated and stored as
> return values (named or unnamed)
> 2. All defered functions are executed (potentially modifying the named
> returns)
> 3. Control is returned
>
> What you'd want amounts to
>
> 1. All defered functions are executed (potentially modifying the named
> returns)
> 2. All expressions in the return statement are evaluated and stored as
> return values
> 3. Control is returned
>
> Not only do I not see how this would be simpler to explain - it also opens
> up some other problems.
> For example, when I use named returns and modify them, I usually do it in this
> pattern <https://play.golang.org/p/iERVXiy5Yq7>. In the changed sequence
> of events, this would return "closing failed", instead of "stuff failed".
> And how would this <https://play.golang.org/p/VDt3A0lnFN7> work? recover
> can only work, after the returned expressions where evaluated; but the
> defer executes before that.
>
> The alternative would be, to somehow make return not actually return
> values, but to have something like
> 1. The expressions in the return statement are evaluated as references
> 2. All defered functions are executed
> 3. The references from the return statement are dereferenced and the
> values stored as return values
> 4. Control is returned
> But for that to work, you'd need to only allow addressable expressions in
> return (which would be bad) or you would need to somehow introduce a new,
> weird way to describe the sequence of events. Either way, this doesn't seem
> simpler to explain, yet again.
>
>
>> I can see why they don't (expressions on the return line, instead of
>> simple uses of the variables), but that doesn't make me happy about having
>> to explain the difference to others on my team.
>>
>
> I agree that there is *some* subtlety here, but I also believe it's easier
> to explain than the alternatives:
> 1) Return values are stored somewhere that isn't a local variable. You can
> name that storage, or don't, but it always exists
> 2) with := you are declaring a new, local variable.
> 3) return evaluates its expressions and puts them into the return storage
> 4) defered functions are executed after return, but before control is
> returned/panic'ing continues.
>
> Seems doable.
>
>
>> Eric.
>>
>>
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "golang-nuts" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to golang-nuts+unsubscr...@googlegroups.com.
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to