FAQ
I've started to look more closely at the Go type system
and I've found something that I don't yet understand.

Why can't a pointer to a struct that embeds some type be passed
to a function taking a pointer to the embedded type as in:

package main

type A struct{}
type B struct{ A }
type C struct{ B }

func (a *A) F() {}
func (a *A) G(f func(*A)) { f(a) }

func F(*A) {}

func main() {
a := new(A)
b := new(B)
c := new(C)

a.F() // ok
b.F() // no problems
c.F() // no problems

F(a) // ok
F(b) // Error: "cannot use b (type *B) as type *A in function argument"
F(c) // Error: "cannot use c (type *C) as type *A in function argument"

F(&b.A) // explicit workaround
F(&c.A) // explicit workaround

a.G(F) // ok
b.G(F) // no problems - even though G applies F(b) !!!
c.G(F) // no problems - even though G applies F(c) !!!
}


It seems to me that a pointer to a B could always be provided where a
pointer to an A is expected,
and this IS the case for methods.

The problem is more apparent when using functions as arguments. In that
case there doesn't seem to be any workaround,
even though as I noted the applications F(b) and F(c) are ok within method
G.

Can anyone please explain this?

Thanks,
Peter.

--
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+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Search Discussions

  • Ian Lance Taylor at Jan 9, 2014 at 2:05 am

    On Wed, Jan 8, 2014 at 5:48 PM, Peter Caven wrote:
    I've started to look more closely at the Go type system
    and I've found something that I don't yet understand.

    Why can't a pointer to a struct that embeds some type be passed
    to a function taking a pointer to the embedded type as in: ...
    It seems to me that a pointer to a B could always be provided where a
    pointer to an A is expected,
    and this IS the case for methods.

    The problem is more apparent when using functions as arguments. In that case
    there doesn't seem to be any workaround,
    even though as I noted the applications F(b) and F(c) are ok within method
    G.

    Can anyone please explain this?
    Go is generally not big on automatic type conversions. The use with
    inherited methods is just to allow, well, method inheritance. It
    isn't meant to be a general license for type conversion.

    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Jesse McNelis at Jan 9, 2014 at 2:48 am

    On Thu, Jan 9, 2014 at 12:48 PM, Peter Caven wrote:

    I've started to look more closely at the Go type system
    and I've found something that I don't yet understand.

    Why can't a pointer to a struct that embeds some type be passed
    to a function taking a pointer to the embedded type as in:

    package main

    type A struct{}
    type B struct{ A }
    type C struct{ B }

    func (a *A) F() {}
    func (a *A) G(f func(*A)) { f(a) }

    func F(*A) {}

    func main() {
    a := new(A)
    b := new(B)
    c := new(C)
    a.G(F) // ok
    b.G(F) // no problems - even though G applies F(b) !!!
    c.G(F) // no problems - even though G applies F(c) !!!
    }
    This shows that you're confused about how embedding works. You're expecting
    inheritance and embedding is composition.
      c.G(F) is applying F to c.B.A not to c. As G() is a method of A not of C.
    The G() method has no knowledge of C or B and has no way of knowing it's
    being called through a delegation from C.


    --
    =====================
    http://jessta.id.au

    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Peter Caven at Jan 9, 2014 at 5:01 am
    Thanks for pointing that out Jesse,

    You are correct - I see that the pointer passed to F in (*A).G has type *A
    , as it should.

    It looks like the compiler finds the embedded A inside a C and passes F a
    pointer to that - the offset is known at compile-time.
    From dumping the assembly code, this appears to be cleverly done inside
    code that is generated for (*C).G.

    That's the part that I didn't understand.

    A side note here: The compiler warns if there is an ambiguous embedding
    with a message like "ambiguous selector c.G" if there is more than one
    embedding of A inside C.
    However, with some playing around I found that I could still get a
    successful compilation if tried to hide an A inside another struct and
    embed that with another A inside a C.
    In that case the compiler appears to choose an A arbitrarily, maybe the
    most shallowly embedded A?

    -- Peter









    On Wednesday, January 8, 2014 9:48:14 PM UTC-5, Jesse McNelis wrote:

    On Thu, Jan 9, 2014 at 12:48 PM, Peter Caven <pca...@gmail.com<javascript:>
    wrote:
    I've started to look more closely at the Go type system
    and I've found something that I don't yet understand.

    Why can't a pointer to a struct that embeds some type be passed
    to a function taking a pointer to the embedded type as in:

    package main

    type A struct{}
    type B struct{ A }
    type C struct{ B }

    func (a *A) F() {}
    func (a *A) G(f func(*A)) { f(a) }

    func F(*A) {}

    func main() {
    a := new(A)
    b := new(B)
    c := new(C)
    a.G(F) // ok
    b.G(F) // no problems - even though G applies F(b) !!!
    c.G(F) // no problems - even though G applies F(c) !!!
    }
    This shows that you're confused about how embedding works. You're
    expecting inheritance and embedding is composition.
    c.G(F) is applying F to c.B.A not to c. As G() is a method of A not of C.
    The G() method has no knowledge of C or B and has no way of knowing it's
    being called through a delegation from C.


    --
    =====================
    http://jessta.id.au
    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Jesse McNelis at Jan 9, 2014 at 5:16 am

    On Thu, Jan 9, 2014 at 4:01 PM, Peter Caven wrote:
    A side note here: The compiler warns if there is an ambiguous embedding
    with a message like "ambiguous selector c.G" if there is more than one
    embedding of A inside C.
    However, with some playing around I found that I could still get a
    successful compilation if tried to hide an A inside another struct and
    embed that with another A inside a C.
    In that case the compiler appears to choose an A arbitrarily, maybe the
    most shallowly embedded A?
    It's not arbitrary, it's defined in the spec.
    http://golang.org/ref/spec#Selectors

    --
    =====================
    http://jessta.id.au

    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Peter Caven at Jan 9, 2014 at 5:27 am
    Yes, I see it there - thanks again!

    On Thursday, January 9, 2014 12:16:00 AM UTC-5, Jesse McNelis wrote:

    On Thu, Jan 9, 2014 at 4:01 PM, Peter Caven <pca...@gmail.com<javascript:>
    wrote:

    A side note here: The compiler warns if there is an ambiguous embedding
    with a message like "ambiguous selector c.G" if there is more than one
    embedding of A inside C.
    However, with some playing around I found that I could still get a
    successful compilation if tried to hide an A inside another struct and
    embed that with another A inside a C.
    In that case the compiler appears to choose an A arbitrarily, maybe the
    most shallowly embedded A?
    It's not arbitrary, it's defined in the spec.
    http://golang.org/ref/spec#Selectors

    --
    =====================
    http://jessta.id.au
    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Egon at Jan 9, 2014 at 5:11 am

    On Thursday, January 9, 2014 4:48:14 AM UTC+2, Jesse McNelis wrote:
    On Thu, Jan 9, 2014 at 12:48 PM, Peter Caven <pca...@gmail.com<javascript:>
    wrote:
    I've started to look more closely at the Go type system
    and I've found something that I don't yet understand.

    Why can't a pointer to a struct that embeds some type be passed
    to a function taking a pointer to the embedded type as in:

    package main

    type A struct{}
    type B struct{ A }
    type C struct{ B }

    func (a *A) F() {}
    func (a *A) G(f func(*A)) { f(a) }

    func F(*A) {}

    func main() {
    a := new(A)
    b := new(B)
    c := new(C)
    a.G(F) // ok
    b.G(F) // no problems - even though G applies F(b) !!!
    c.G(F) // no problems - even though G applies F(c) !!!
    }
    This shows that you're confused about how embedding works. You're
    expecting inheritance and embedding is composition.
    c.G(F) is applying F to c.B.A not to c. As G() is a method of A not of C.
    The G() method has no knowledge of C or B and has no way of knowing it's
    being called through
    a delegation
    >
    * forwarding
    from C.


    --
    =====================
    http://jessta.id.au
    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedJan 9, '14 at 1:48a
activeJan 9, '14 at 5:27a
posts7
users4
websitegolang.org

People

Translate

site design / logo © 2022 Grokbase