Thank you for that clarification of what is happening under the hood.

Nevertheless, I do think there are many cases where it would be very valuable 
to have access through reflect of the true underlying type of the receiver 
struct.  This is evident in that stack overflow question, the *JSON code, and 
probably many other cases where reflect is used.  Just to be clear, in the 
[Un]MarshalJSON code, the inability to access the true type means that you 
cannot use an embedded interface to properly serialize derived types — any 
generic functionality you might want to add to the process must be added 
explicitly to each instance separately.  This leads to a need for major code 
replication, seemingly in contradiction to the Go philosophy.  Furthermore, I 
have many use-cases of wanting to generically access fields (Get / Set values, 
etc) that might be on a derived type of my tree Node type.

Anyway, if it is not technically possible, then there’s no point in wishing for 
it.  But I don’t think it is accurate to say that this would not extend the 
power and elegance of the language.

Meanwhile, in case others encounter this same situation, I have had to add a 
“this” member to my Node struct that stores the interface pointer version of 
the struct, so it is always possible to use that when access to the derived 
type is necessary.  Might make some Go folks barf, but it does the trick!  Just 
trying to get stuff working with the fewest LOC possible :)

- Randy

> On Mar 5, 2018, at 2:24 PM, Krzysztof Kowalczyk <kkowalc...@gmail.com> wrote:
> 
> (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 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