Is this a reflect bug?

1,080 views
Skip to first unread message

mattn

unread,
May 12, 2011, 11:07:36 PM5/12/11
to golan...@googlegroups.com
Hi.

Sorry that I don't read old-threads about discussions of reflect package.
I have a question.

'ifoo' is a interface{}. if ifoo point to pointer of struct directly, it can reflect and set value via address.
But  if ifoo point to interface{} that point to pointer of struct indirectly, it can't reflect to set.

Is this a design or not?
------------
package main

import "reflect"

func main() {
type foo struct{}
vfoo := map[string]interface{}{
"foo": (*foo)(nil),
}

var pfoo *foo
var ifoo interface{}

var pv, zv reflect.Value

ifoo = vfoo["foo"]
pv = reflect.ValueOf(&pfoo).Elem()
zv = reflect.New(pv.Type().Elem()) // pass
pv.Set(zv)

ifoo = pfoo
pv = reflect.ValueOf(&i).Elem()
zv = reflect.New(pv.Type().Elem()) // Elem of invalid type
pv.Set(zv)
}
------------

- Yasuhiro Matsumoto

mattn

unread,
May 12, 2011, 11:10:26 PM5/12/11
to golan...@googlegroups.com
Ooops, code is broken. please wait.

mattn

unread,
May 12, 2011, 11:13:43 PM5/12/11
to golan...@googlegroups.com
Below is correct broken(?) example.

----------------------
package main

import "reflect"

func main() {
type foo struct{}
vfoo := map[string]interface{}{
"foo": (*foo)(nil),
}

var pfoo *foo
var ifoo interface{}

var pv, zv reflect.Value

ifoo = pfoo
pv = reflect.ValueOf(&pfoo).Elem()
zv = reflect.New(pv.Type().Elem()) // pass
pv.Set(zv)

ifoo = vfoo["foo"]
pv = reflect.ValueOf(&ifoo).Elem()
zv = reflect.New(pv.Type().Elem()) // panic: reflect; Elem of invalid type
pv.Set(zv)
}
----------------------

Russ Cox

unread,
May 12, 2011, 11:14:48 PM5/12/11
to golan...@googlegroups.com
> But  if ifoo point to interface{} that point to pointer of struct
> indirectly, it can't reflect to set.

You used pv.Type().Elem(). pv.Type() is the reflect type for "interface{}".
Since this is now just a type, not a value, Elem doesn't make sense.
An interface type could have nearly any type inside it. Statically,
you don't know.

If you use pv.Elem().Type() you will get the type of the thing inside the
interface, because pv is a reflect value for a specific interface{} value.
You can call Elem() to get the thing inside the interface value and
then call Type on that (unless the interface value is nil).

Russ

mattn

unread,
May 12, 2011, 11:26:29 PM5/12/11
to golan...@googlegroups.com
ok, but 1 more question.
Shoud we check what interface{} point to?
I guess that the first 'ifoo' and second 'ifoo' both should work with same approach in following code.
But...

---------------------
package main

import "reflect"

func main() {
type foo struct{}
vfoo := map[string]interface{}{
"foo": (*foo)(nil),
}

var pfoo *foo
var ifoo interface{}

var pv, zv reflect.Value

ifoo = pfoo
pv = reflect.ValueOf(&pfoo).Elem()
zv = reflect.New(pv.Type().Elem())  // Shoud call Elem()
pv.Set(zv)

ifoo = vfoo["foo"]
pv = reflect.ValueOf(&ifoo).Elem() // Should not call Elem()
zv = reflect.New(pv.Type())
pv.Set(zv)
}
---------------------
 

Russ Cox

unread,
May 13, 2011, 11:30:40 AM5/13/11
to golan...@googlegroups.com
> Shoud we check what interface{} point to?

Interfaces don't point. They contain other values.
It sounds pedantic but it's important to remember
that an interface value is different from a pointer.

> I guess that the first 'ifoo' and second 'ifoo' both should work with same
> approach in following code.

> ifoo = pfoo

Notice that you set this and never used it.

> pv = reflect.ValueOf(&pfoo).Elem()

Here, pfoo has type *foo.
&pfoo has type **foo.
ValueOf(&pfoo) is a Value corresponding to a **foo.
ValueOf(&pfoo).Elem() is a Value corresponding to a *foo.
In fact, it corresponds exactly to pfoo.
pv.Set(ValueOf(x)) and pfoo = x will have the same effect.

> zv = reflect.New(pv.Type().Elem())

pv.Type() is the Type for *foo.
pv.Type().Elem() is the Type for foo.
New(pv.Type().Elem()) is like ValueOf(new(foo)).

> pv.Set(zv)

So this is basically the same as pfoo = new(foo).

> ifoo = vfoo["foo"]

Okay, so ifoo is an interface{} containing a *foo pointer.

> pv = reflect.ValueOf(&ifoo).Elem()

Here you used the same idiom to get something
corresponding exactly to ifoo. Now,
pv.Set(ValueOf(x)) and ifoo = x will have the same effect.
(This is different from before: note ifoo, not pfoo.)
pv is a Value corresponding to an interface{}.

> zv = reflect.New(pv.Type())

pv.Type() is the Type for interface{}.
So reflect.New(pv.Type()) is like ValueOf(new(interface{})).

> pv.Set(zv)

This is like ifoo = new(interface{}).

Russ

Reply all
Reply to author
Forward
0 new messages