Re: [go-nuts] Nested struct types and closing over them in function literals

2017-11-24 Thread Ian Lance Taylor
On Fri, Nov 24, 2017 at 8:58 AM, Konstantin Khomoutov  wrote:
>
> We've just have a discussion with a colleague about the case of what
> exactly variable would a function literal close over, if it calls a
> method on a field of a struct-typed variable available in the scope of
> the enclosing function.
>
> Here's the code:
>
> ---8<
> package main
>
> import (
> "fmt"
> )
>
> type Foo struct {
> val int
> }
>
> func (foo *Foo) Show() {
> fmt.Println(foo.val)
> }
>
> type Bar struct {
> foo *Foo
> }
>
> func main() {
> foo := {123}
> bar := {foo}
>
> fn := func() {
> bar.foo.Show()
> }
>
> fn()
>
> bar.foo = {456}
>
> fn()
> }
> ---8<
>
> (Playground link: [1]).
>
> and the dispute was about whan variable would fn() close over.
>
> I proposed that it will close over bar.foo since it's the "narrowest"
> variable needed to be able to call Show().
> As it turned out, I was wrong, and fn() closes over bar.
>
> My line of reasoning stems from the following passage from the spec [2]:
>
> | Structured variables of array, slice, and struct types have elements and
> | fields that may be addressed individually. Each such element acts like a
> | variable.
>
> which seem to suggest in the case above bar.foo is a variable, and since
> bar itself is not needed to call the Show() method provided by the
> bar.foo's type, the function literal would close over the field alone
> (presumably internally storing a pointer to it).
>
> The part of the spec which discusses function literals [3] states:
>
> | Function literals are closures: they may refer to variables defined in a
> | surrounding function. Those variables are then shared between the
> | surrounding function and the function literal, and they survive as long
> | as they are accessible.
>
> So there is no clearly defined rule of how the compiler decides what to
> capture.
>
>
> I've got hunch that may be [2] really has concurrent access in mind when
> it states "Each such element acts like a variable", and this does not
> apply to other cases.
>
>
> Can anyone please explain where there is a flaw in my line of reasoning
> which led me to a wrong conclusion?
>
>  1. https://play.golang.org/p/_VfdzQDNZR
>  2. https://golang.org/ref/spec#Variables
>  3. https://golang.org/ref/spec#Function_literals

Although it's true that each field of a struct "acts like a variable,"
what matters for function closures is naming and scope.  The name
`bar` in the function closure must refer to something.  The `bar` in
scope is the local variable in `main`, and so that is that variable to
which `bar` in the function closure refers.  Everything else follows
from that.

You are suggesting that since `bar.foo` is in scope, the closure
should refer to that.  But `foo` is a field in `bar`; we have to first
decide what `bar` refers to.  And once we see that that is a variable,
that is the variable that is captured.  There is nothing in the spec
to suggest that we should narrow the capture to `bar.foo`.

Ian

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


[go-nuts] Nested struct types and closing over them in function literals

2017-11-24 Thread Konstantin Khomoutov
We've just have a discussion with a colleague about the case of what
exactly variable would a function literal close over, if it calls a
method on a field of a struct-typed variable available in the scope of
the enclosing function.

Here's the code:

---8<
package main

import (
"fmt"
)

type Foo struct {
val int
}

func (foo *Foo) Show() {
fmt.Println(foo.val)
}

type Bar struct {
foo *Foo
}

func main() {
foo := {123}
bar := {foo}

fn := func() {
bar.foo.Show()
}

fn()

bar.foo = {456}

fn()
}
---8<

(Playground link: [1]).

and the dispute was about whan variable would fn() close over.

I proposed that it will close over bar.foo since it's the "narrowest"
variable needed to be able to call Show().
As it turned out, I was wrong, and fn() closes over bar.

My line of reasoning stems from the following passage from the spec [2]:

| Structured variables of array, slice, and struct types have elements and
| fields that may be addressed individually. Each such element acts like a
| variable.

which seem to suggest in the case above bar.foo is a variable, and since
bar itself is not needed to call the Show() method provided by the
bar.foo's type, the function literal would close over the field alone
(presumably internally storing a pointer to it).

The part of the spec which discusses function literals [3] states:

| Function literals are closures: they may refer to variables defined in a
| surrounding function. Those variables are then shared between the
| surrounding function and the function literal, and they survive as long
| as they are accessible.

So there is no clearly defined rule of how the compiler decides what to
capture.


I've got hunch that may be [2] really has concurrent access in mind when
it states "Each such element acts like a variable", and this does not
apply to other cases.


Can anyone please explain where there is a flaw in my line of reasoning
which led me to a wrong conclusion?

 1. https://play.golang.org/p/_VfdzQDNZR
 2. https://golang.org/ref/spec#Variables
 3. https://golang.org/ref/spec#Function_literals

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