Why is reflect.Value.Elem settable for a pointer but not for a value held in an interface?
answer
- Elem means two different things
- one dereferences, one unboxes
- a boxed value is not a variable
- set the field, not what it holds
- unless the interface holds a pointer
basics
~20 sElem on a pointer returns the storage the pointer names, so it is addressable and settable. Elem on an interface returns a copy of the dynamic value the interface currently holds, which has no address of its own, so CanSet is false.
solid answer
~40 s`Value.Elem` does two different jobs depending on Kind. On a `Pointer`, it dereferences: the result describes the memory the pointer names, so it is addressable and, for exported paths, settable. On an `Interface`, it unpacks the dynamic value the interface holds — and an interface stores its data as an opaque word, not as a variable you can point at, so the Value you get back is a copy and `CanSet` is false. The consequence for a config walk is that you never write *through* an interface-typed field; you write *to* it. If the field itself is addressable, call `Set` on the field with a Value of a type assignable to the field's type, replacing what the interface holds. Trying `field.Elem().Set(...)` instead panics on an unaddressable value.
code
go · 11 linesvar setting any = 8080
// Kind Interface: names the variable, so it is settable.
iface := reflect.ValueOf(&setting).Elem()
// Kind Int: a copy of the boxed value, with no address of its own.
inner := iface.Elem()
fmt.Println(iface.CanSet(), inner.CanSet()) // true false
iface.Set(reflect.ValueOf(9090))
fmt.Println(setting) // prints: 9090go deeper
Know that Elem only applies to pointers and interfaces, and that the way to change an interface-typed field is to assign a whole new value to the field itself.
Explain why unpacking an interface yields a copy while dereferencing a pointer does not, and trace CanSet along a ValueOf(&x).Elem().Elem() chain.
Demonstrate the diagnosis: print Kind, CanAddr and CanSet at each hop of a walk and recognise the Interface-then-copy signature when an interface-typed setting silently keeps its old value.
Argue the design point: reflection permits exactly the writes ordinary Go could perform, so an API that must be filled reflectively should avoid interface-typed sinks and take concrete pointers instead.
## One method, two meanings `func (v Value) Elem() Value` panics unless `v.Kind()` is `Pointer` or `Interface`, and it behaves differently in each case. **Pointer.** `Elem` follows the pointer. The result describes the pointee's storage, so reflect knows its address: `CanAddr()` is true, and `CanSet()` is true for anything reached along an exported path. This is the standard way into a caller's variable. **Interface.** `Elem` unwraps the dynamic value. An interface value is conceptually a pair of a type descriptor and a data word; the value it holds is not a variable with independent storage that the program can name. What `Elem` gives back is therefore a copy: `CanAddr()` is false and `CanSet()` is false, even when the interface *field* you took it from was perfectly settable. ## The chain that shows both Take `var setting any = 8080`. - `reflect.ValueOf(&setting)` has Kind `Pointer`. - `.Elem()` on it has Kind `Interface`, and it **is** addressable and settable — it names the variable `setting`. - `.Elem()` again has Kind `Int`, and is **not** settable — it is a copy of the boxed 8080. So a single `Elem` is the pointer dereference you want; the second one crosses into interface unpacking and loses writability. ## Writing to an interface-typed field A settings struct with a field of type `any` (or of some interface type) is where this bites. The correct move is to replace the whole interface value: ``` field := v.FieldByName("Value") // Kind Interface, CanSet true field.Set(reflect.ValueOf(9090)) ``` `Set` requires the source's type to be **assignable** to the destination's type. Assigning a concrete `int` to a field of type `any` is legal Go, so it is legal here; assigning a type that does not implement the field's interface panics with a message about assignability, and `Type.AssignableTo` lets you check first. What does **not** work is `field.Elem().Set(reflect.ValueOf(9090))`. That takes a copy out of the interface and tries to write to the copy, which panics on an unaddressable value. ## The mutable escape hatch There is one arrangement where you can effectively write "inside" an interface: if the interface holds a **pointer**, then `Elem()` gives a pointer Value, and a further `Elem()` gives the addressable pointee. In other words `iface.Elem().Elem()` is settable when the interface's dynamic type is `*T`, because the address came along inside the pointer. This is exactly how a decoder handed `any` that happens to hold `*Config` still gets to write into the struct. ## Why the rule exists at all If reflect let you mutate the value inside an interface in place, the same boxed value could be observed changing by every copy of that interface value, breaking the ordinary Go rule that assigning an interface copies it. Making the unpacked value a copy keeps reflection's semantics identical to what the language already does, which is the guiding principle behind the whole settability model: reflect permits exactly the writes that plain Go code could have performed. ## Diagnosing it When a walk silently fails to update an interface-typed setting, print `Kind()`, `CanAddr()` and `CanSet()` at each hop. Seeing `Interface true true` followed by `Int false false` is the signature: the code stepped one `Elem` too far and is writing to a copy.
- When is the value inside an interface reachable in a settable form?When the interface's dynamic type is a pointer. `iface.Elem()` then yields a pointer Value, and one more `Elem()` reaches the addressable pointee. That is how a decoder handed an `any` that holds `*Config` can still fill the struct — the address travelled inside the pointer rather than being lost in the boxing.
- What must be true of the argument to Set on an interface-typed field?Its type must be assignable to the field's type, which for an interface field means the concrete type implements it (any concrete type satisfies `any`). Otherwise `Set` panics with an assignability message. `Type.AssignableTo` or `Type.Implements` lets a walk check first and report a useful error instead.
- What does Elem do on a Value whose Kind is Struct or Slice?It panics. `Elem` is defined only for Kind `Pointer` and Kind `Interface`; there is nothing to dereference or unbox otherwise. Struct fields are reached with `Field`, and slice or array elements with `Index` — both of which preserve addressability from the parent.
A pointer is a street address: follow it and you are standing in the actual house. An interface is a sealed parcel: opening it gives you a copy of the contents, and relabelling that copy does not change the parcel.
saying these in an interview costs you the question
- Treats Elem as a generic unwrap for any Value
- Writes through field.Elem() on an interface-typed field
- Assumes anything reached from a pointer stays settable forever
- Thinks an interface stores an addressable variable
- Expects Set to accept a type not assignable to the field