Change to reflect package

24 views
Skip to first unread message

Rob 'Commander' Pike

unread,
Jun 21, 2010, 2:04:11 PM6/21/10
to golang-nuts Nuts
The next release will contain a significant change to the reflect
package. If you have code that uses reflect, it will need to be
updated. If it's like most clients of the reflect library, it will
shrink significantly; if it's one of the few unlucky ones, it may grow
slightly.

The change regards the representation of numeric types and values:
integers, floating-point numbers, and complex numbers. Before there
was a distinct Type for each type (int, int8 etc., uint uint8 etc.,
float float32 etc., complex complex64 etc.); now there is one integer
Type (IntType), one unsigned integer Type (UintType), one floating
point Type (FloatType), and one complex Type (ComplexType). Now, all
the signed integers are represented by one reflect Type (IntType) and
one reflect Value (IntValue); methods of IntType and IntValue provide
further details for the few applications that need to know. A similar
collapse occurred to the other numeric types.

The situation for numeric types is therefore much like the situation
for, say, slices: there is only one SliceType but it can represent
slices of many element types; similarly there is one IntType but it
can represent all of int, int8, int16, int32, and int64. The size of
the item is still available through its Size method, but there is also
a Kind method that returns, for IntType, one of reflect.Int,
reflect.Int8, reflect.Int16, reflect.Int32, or reflect.Int64 (That is
the only way to be sure you have an int as opposed to an int32 or
int64). We have discovered most clients of reflection don't need to
know the precise underlying integer type, however, which is why we
made this change.

Most of the code that uses reflect uses a type switch to discover the
type of the item. Now, there will not need to be a single case for
each kind of integer, only one. If you do need to know the precise
type, you can switch on the Kind of the integer type to learn more.

For values, the Set and Get routines operate on maximum-precision
values of that class of item. That is, IntValue.Get() returns an int64
and IntValue.Set() takes an int64. It is the caller's responsibility
to adjust and verify the values, but we've found this is a small burden.

Here is an example from the implementation of fmt.Printf.

Before:

switch f := value.(type) {
case *reflect.BoolValue:
p.fmtBool(f.Get(), verb, field)
case *reflect.IntValue:
p.fmtInt64(int64(f.Get()), verb, field)
case *reflect.Int8Value:
p.fmtInt64(int64(f.Get()), verb, field)
case *reflect.Int16Value:
p.fmtInt64(int64(f.Get()), verb, field)
case *reflect.Int32Value:
p.fmtInt64(int64(f.Get()), verb, field)
case *reflect.Int64Value:
p.fmtInt64(f.Get(), verb, field)
case *reflect.UintValue:
p.fmtUint64(uint64(f.Get()), verb, sharp, field)
case *reflect.Uint8Value:
p.fmtUint64(uint64(f.Get()), verb, sharp, field)
case *reflect.Uint16Value:
p.fmtUint64(uint64(f.Get()), verb, sharp, field)
case *reflect.Uint32Value:
p.fmtUint64(uint64(f.Get()), verb, sharp, field)
case *reflect.Uint64Value:
p.fmtUint64(f.Get(), verb, sharp, field)
case *reflect.UintptrValue:
p.fmtUint64(uint64(f.Get()), verb, sharp, field)
// ...

After:

switch f := value.(type) {
case *reflect.BoolValue:
p.fmtBool(f.Get(), verb, field)
case *reflect.IntValue:
p.fmtInt64(f.Get(), verb, field)
case *reflect.UintValue:
p.fmtUint64(uint64(f.Get()), verb, sharp, field)
// ...


More details will be available through godoc after the release, or you
may sync to tip now.

-rob

Archos

unread,
Jun 22, 2010, 4:01:08 AM6/22/10
to golang-nuts
I'm changing the code related to it

Before:
===
func setfloat(v reflect.Value, f float64) {
switch v := v.(type) {
case *reflect.FloatValue:
v.Set(float(f))
case *reflect.Float32Value:
v.Set(float32(f))
case *reflect.Float64Value:
v.Set(float64(f))
}
}
===

After:
===
func setfloat(v reflect.Value, f float64) {
switch v := v.(type) {
case *reflect.FloatValue:
switch v.Type().Kind() {
case reflect.Float:
v.Set(float(f))
case reflect.Float32:
v.Set(float32(f))
case reflect.Float64:
v.Set(float64(f))
}
}
}
===
but I get now errors related to the conversion

cannot use float(f) (type float) as type float64 in function argument
cannot use float32(f) (type float32) as type float64 in function
argument

Andrew Gerrand

unread,
Jun 22, 2010, 4:23:42 AM6/22/10
to Archos, golang-nuts
With the new code, Set perfoms the inner switch for you. It becomes
much simpler:

func setfloat(v reflect.Value, f float64) {
switch v := v.(type) {
case *reflect.FloatValue:

v.Set(f)
}
}

For the internals, see: http://golang.org/src/pkg/reflect/value.go#L156

Andrew

Archos

unread,
Jun 22, 2010, 5:30:31 AM6/22/10
to golang-nuts
Reply all
Reply to author
Forward
0 new messages