Description
Current Situation
- gc: unexported embedded structs are settable
- gccgo: unexported embedded structs are not settable
Both are not correct w.r.t. the way Go works: an unexported embedded struct should not be settable as a whole, however, exported fields and methods of unexported embedded structs may be promoted and be visible.
Goal
- Make gc and gccgo compatible again with a workable solution.
- address issues 7363 and 11007.
Solution
Make unexported embedded structs unsettable, but allow the reflect library to access exported fields and methods of such structs. Such fields could also be modified.
Rationale: this prevents blanket changes to values in structs that are generally not settable, while allowing access to fields that might be promoted.
The approach might still allow access to fields that are not accessible in the language, namely exported fields and methods that are not promoted because they are masked by or conflict with fields or methods of the same name. However, access to such fields is also necessary. Packages like encoding/xml and encoding/json allow users to map fields to alternative names using tags effectively breaking ties and making fields visible again. Disallowing access to blocked fields now would be too much of a disruptive change and break the Go 1 compatibility promise.
Impact
This will break packages like xml and json, but only minimally. The typical check for whether a field is exported, f.PkgPath != "", would have to be amended to f.PkgPath != "" && !f.Anonymous.
Alternatives
adopt gccgo behavior
Unacceptable: it would be too disruptive to packages like xml and json and would break documented behavior, breaking the Go 1 compatibility promise. It would mean reflect cannot give access to fields that are visible in Go itself.
adopt gc behavior
Less problematic, but it would make it very easy to access structs that are indicated as hidden. Users could bypass initialization code etc, raising various security issues. The proposed solution does not eliminate this, but it does considerably mitigate it by limiting access to fields that are deemed exported and settable if the embedded type were accessed directly.
package reflect provides a different API for accessing promoted fields and methods.
- This will be a huge change while still not addressing what to do with the remaining old API and its incompatibility.
- It would not be possible for xml and json to implement their documented behavior.
Provide a higher-level API for packages like xml and json for mapping structured data to struct fields
This would potentially give greater consistency and would make it easier for developers to write package like json and xml. However, it would be a huge change and similarly does not address the concerns of what to do with the current API. Like the current proposal, it would still allow access to non-promoted fields and methods. It could be implemented on top of the proposed solution.