Skip to content

YAML doesn't round-trip generics #715

Open

Description

@zewt
    string s = rfl::yaml::write("On"s);
    auto g = rfl::yaml::read<rfl::Generic>(s);
    printf("%s\n", rfl::json::write(g).c_str());

This prints true instead of "On", and the generic contains a bool instead of the string. This happens at least with bool-looking strings and strings containing numbers.

This makes rfl::Generic mostly unusable with yaml, since random strings deserialize to a different type than went in.

I don't know if this is a problem with yaml-cpp itself or how reflect-cpp is using it. Since I only know about this from the reflect-cpp side (I don't know anything about yaml-cpp) I figured this was the better place to bring it up. It's a bit of an ugly surprise waiting for anyone using rfl::Generic with YAML--not sure if I have any real workaround other than switching to JSON.

Activity

  1. liuzicheng1987 commented on Aug 23, 2026

    @liuzicheng1987
    Collaborator

    @zewt to be honest, I think this might even be a YAML issue. The YAML spec specifies that on/off are supposed to be interpreted as booleans.

    https://yaml.org/type/bool.html

  2. liuzicheng1987 commented on Aug 23, 2026

    @liuzicheng1987
    Collaborator

    @zewt the issue is in yaml-cpp:

    https://github.com/jbeder/yaml-cpp/blob/master/src/convert.cpp

    As you can see, on/off are interpreted as booleans. And they explicitly reference the same page that I shared as well.

  3. zewt commented on Aug 23, 2026

    @zewt
    Author

    That's just where the conversion is happening, not why. It happens for numbers too.

        rfl::Generic a("1234");
        string yaml = rfl::yaml::write(a);
        rfl::Generic b = rfl::yaml::read<rfl::Generic>(yaml).value();
        string result = b.to_string().value_or("error");
    

    results in "error", since b contains a double instead of a string.

    And this fails:

        struct test
        {
            string a = "1234";
        };
        test value;
    
        string yaml = rfl::yaml::write(value);
        rfl::Generic generic = rfl::yaml::read<rfl::Generic>(yaml).value();
        auto value2 = rfl::from_generic<test>(generic);
    

    "a" has become a double inside "generic", so from_generic fails with "Failed to parse field 'a': rfl::Generic: Could not cast the underlying value to a string."

    It seems like yaml-cpp doesn't handle types at the yaml level at all. It just parses all values to strings, and then node.as() converts to whichever data type is asked for. Generic::ReflectionType asks for bools and doubles before strings, so it asks for a bool, yaml-cpp sees the string "true" and happily converts it. I don't think that's a yaml-cpp bug, it's just how yaml-cpp works.

    yaml-cpp also doesn't quote strings that look like numbers or bools when serializing, which would be needed for that to be possible. I don't think yaml-cpp is meant to be type-preserving in the way reflect-cpp wants, even though YAML itself is perfectly capable of it.

    I've switched back to JSON, since this doesn't seem like something that can be fixed easily (or maybe at all without changing the yaml backend). But this is a bit of a landmine for people using rfl::Generic with YAML.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions