Skip to content

Question: Why interfaces can be marshaled but not unmarshaled by default? #577

Open
@gabyx

Description

@gabyx

I have been playing around with this feature-rich library to see how it operates, but the following puzzled me pretty much and
I dont understand it. It would really help what the underlying pin points are what makes the two examples destinct, wenn encoding and then decoding (which is the problem).

I have the follwing structs:

Example A (with interface)

type B struct {
    N int `yaml:"n"`
}

type A struct {
    Number int `yaml:"number"
    Data Interface `yaml:"data"` // here B gets assigned
}

type Interface interface {}

Example B (Wrapping the interface in a concrete type)

type B struct {
    N int `yaml:"n"`
}

type A struct {
    Number int `yaml:"number"`
    Data Wrapper `yaml:"data"`
}

type Wrapper struct {
    Data Interface `yaml:",inline"` // here B gets assigned
}

type Interface interface {}

// Implementing the InterfaceUnmarshaler
func (w Wrapper) UnmarshalYAML(unmarshal func(any) error) error {
	return unmarshal(w.Data)
}

// Implementing the InterfaceMarshaler
func (w Wrapper) MarshalYAML() (any, error) {
	return w.Data, nil
}

Observations in the Marshal and Unmarshal Loop

  • In Example A I can create struct var a A{Data: B{}} and marshal it properly. The unmarshal does not work as
    the library throws an error that it cannot assign map[interface{}]interface{} to Interface.

  • In Example B I can marshal properly and also the unmarshaling works without any error.

Questions

  • In Example A somehow go-yaml uses reflect to iterate on the fields on A and also it is able to magically marshal Data which is an interface and does not implement UnmarshalYAML. But the unmarshaling does not work, but it works in example B, when it is wrapped in a type Wrapper which implements the UnmarshalYAML function.
    I don't get why:
  1. go-yaml cannot figure out in example A that it can unmarshal into Data? (when it could marshal it?) Why is this asymetric behavior, is it due to reflect?
  2. In example B, I am just forwarding the interface Data to the unmarshal function which then works for unmarshaling, which makes me wonder why in this case it works?

Thanks a lot for the help. It would be great to make this example into a documentation/example once this issue resolves in something meaningful. =)

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions