Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
gabyx opened this issue Dec 8, 2024 · 0 comments
Open
Labels
question Further information is requested

Comments

@gabyx
Copy link

gabyx commented Dec 8, 2024

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. =)

@gabyx gabyx added the bug Something isn't working label Dec 8, 2024
@goccy goccy added question Further information is requested and removed bug Something isn't working labels Dec 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants