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.