(in *Inner) InFunc() can't possibly say `in` is Outer.

This piece of code:

var := Outer{}
val.InFunc()

Is really:

val := Outer{}
var tmpInner *Inner = &(val.Inner)
tmpInner.InFunc()

What is passed to InFunc is a pointer to Inner struct embedded inside Outer 
struct, not a pointer to Outer struct.

The compiler did a little bit of magic behind the scenes because it makes 
using struct composition more convenient.

The idea is that if you include Inner struct inside Outer struct, Outer 
"inherits" fields and functions of Inner so syntactically you can say 
outer.Foo() and it will call function defined in Inner() without you having 
to say outer.Inner.Foo().

There's also confusion about what reflection is for.

In (in *Inner) InFoo() you already know the static type of in, which is a 
pointer to struct Inner. There's no need to use reflection.

Reflection is for cases where you have interface type, including the most 
common case of empty interface `interface{}`.

You can convert any value with static type to `interface{}`

var inter interface{} = in // you can convert any static type to interface{}
// code using reflection on inter

// it := in.(InType) // the "obvious" thing fails with: invalid type 
assertion: in.(InType) (non-interface type *Inner on left)

Here you can't use type assertion on `in` because it only works on 
interfaces 
(https://www.programming-books.io/essential/go/a-25362-type-assertion) and 
`in` isn't an interface. The compiler tells you so.

-- kjk

On Monday, March 5, 2018 at 10:28:25 AM UTC-8, Randall O'Reilly wrote:
>
> I'm new to golang, and am hitting some seemingly strange territory that I 
> couldn't find much prior discussion about -- here's one example of the 
> phenomenon in question:
>
>
> https://stackoverflow.com/questions/22153269/how-to-reflect-fields-of-containing-struct-from-a-method-of-the-embedded-struct/49094937#49094937
>
> In brief, it seems that reflect does NOT have access to the "true" 
> underlying type of a struct, when accessing a function receiver struct 
> pointer, but it DOES have access when an object is passed as a regular 
> argument via an interface.  While I understand that the receiver is 
> apparently special in terms of binding to the interface, there is also the 
> statement that it is really just another arg..
>
> In my use-case, I was trying to use reflect to provide some generic tree 
> functionality that could automatically apply to "derived" types that embed 
> a "Node" type with all the tree-relevant functionality.  However, depending 
> on this difference in where the struct appeared (receiver vs. arg) I was 
> variably getting the desired "inheritance" ability to access the fields of 
> the derived types in the base type's code.  In particular, defining a 
> MarshalJSON method for my base type forced everything to be Marshal'd as 
> the base type, not as its actual type -- the generic Marshal gets the 
> struct as an arg, whereas when you define this method you turn it into a 
> receiver!
>
> This issue generally seems relevant to this discussion about the value of 
> struct embedding and the true nature of inheritance in Go: 
> https://github.com/golang/go/issues/22013 -- as someone coming from the 
> C++ world, I find the ability to get at least some basic inheritance 
> functionality to be very powerful, while appreciating the extra flexibility 
> of the compositional / interface model as well.  The example of generic 
> JSON rendering shows how powerful reflection is, *when it can operate on 
> the "true" underlying types* -- this peculiarity with the receivers not 
> having the same "insight" into the true type seems like it should be an 
> easily fixable limitation (to the extent that args really are all the 
> same), and would make the overall behavior more consistent.
>
> Philosophically, Go seems to be "optimized for the lazy" (or elegance if 
> you prefer), which is certainly one of its main advantages compared to C++, 
> but then in the discussion on that proposal, people seem all-too-willing to 
> argue for rewriting a bunch of methods over and over again!  That seems to 
> contradict this core philosophy.  Anyway, someone can hopefully let me know 
> if I should file a bug ticket about this specific inconsistency (or let me 
> know if it already exists somewhere -- I couldn't find it but could have 
> not been using the right terms).
>
> Here's a more succinct example based on above stackoverflow case:
>
> https://play.golang.org/p/KmihXxU19Dd
>
> package main
>
> import (
> "fmt"
> "reflect"
> )
>
> type Inner struct {
> InMbr bool
> }
>
> type InType interface {
> InFun()
> }
>
> type Outer struct {
> Inner
> Id   int
> name string
> }
>
> func (in *Inner) InFun() {
> typ := reflect.TypeOf(in).Elem()
> fmt.Printf("InFun on in always says Inner: %v\n", typ.Name())
> // can I coerce the thing?
> // it := in.(InType) // the "obvious" thing fails with: invalid type 
> assertion: in.(InType) (non-interface type *Inner on left)
> // try to obfuscate the process via reflect: (per 
> https://groups.google.com/forum/#!msg/Golang-Nuts/KB3_Yj3Ny4c/Ai8tz-nkBwAJ
> )
> vp := reflect.New(typ)
> vp.Elem().Set(reflect.ValueOf(in).Elem())
> it := vp.Interface().(InType)
> ArgFun(it) // no such luck: argfun says "Inner" still
> }
>
> func ArgFun(in InType) {
> typ := reflect.TypeOf(in).Elem()
> fmt.Printf("ArgFun on in tells the truth: %v\n", typ.Name())
> }
>
> func main() {
> val := Outer{}
> val.InFun()
> ArgFun(&val)
> }
>
> Output: 
>
> InFun on in always says Inner: Inner
> ArgFun on in tells the truth: Inner
> ArgFun on in tells the truth: Outer
>
>
>

-- 
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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to