-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Whole number float values marshal to ambiguous integer values #430
Comments
The key reason to use YAML as a configuration format is for the content to be human-friendly, both when reading and when writing. From that perspective, "42" is a significantly more usual way for a person to express that number than "42.0". So if an application is behaving in a different way when someone enters "42" or "42.0", that sounds like a bug worth fixing in the application. Along the same lines, forcing everybody to read "42.0" in their configuration files just because the code is accepting a non-integer number also sounds unfriendly to those that will be reading the file. With that said, the v3 of go-yaml that I've been working on will allow you to unmarshal into an intermediate format that preserves exactly the original representation, including octals, hexadecimals, specific tags, etc. That will enable you to roundtrip the original representation much more precisely. In fact, even comments will be preserved to a good degree. The v3 release will be out for testing as soon as I manage to finish the last couple of incompatible changes |
Thanks for the quick response @niemeyer! Your explanation makes sense to me. This request is a nice-to-have formatting enhancement and not a failure of go-yaml to implement the YAML spec. That said, I would prefer to preserve the original value for my use case, and I look forward to the v3 release. 😄 |
Is v3 available to do such formatting now? |
I would argue that the current behavior (where a In other words, because go-yaml is able to successfully decode The regex that @sclevine quotes from the YAML 1.2 spec is the specification of a float... sort of. There is a list of regexes used to categorize untagged values, and, per the specification, "first match wins". So in order for an untagged value to be parsed as a float, it doesn't only have to match |
@philomory Hi Adam. For a 1-to-1 type matching I suggest looking into v3's yaml.Node. It goes even further by preserving the text. Otherwise, for general encoding/decoding what was described above applies and the human factor wins over the strict representation of types. I care too much about my inbox to consider |
@niemeyer Just, for the sake of clarity, I never meant to suggest that Is there an example anywhere of how to use |
I suggest just decoding that string into a yaml.Node with yaml.Unmarshal, and printing it out. You can move it back and forth and it should roundtrip. |
@niemeyer And if I want to go the other way? Edit: To be clear, I mean, I have an arbitrary |
If you're not using yaml.Node, the conversation above has all the details about what works when and why. |
Could somebody give an example how to output import (
"gopkg.in/yaml.v3"
)
func TestA(t *testing.T) {
data := make(map[interface{}]interface{})
data["a"] = 2.0
bts, err := yaml.Marshal(data)
require.NoError(t, err)
require.Equal(t, "a: 2.0\n", string(bts))
} Right now it's like this:
For example, this works for a flat map: func TestA(t *testing.T) {
data := make(map[interface{}]yaml.Node)
node := yaml.Node{}
node.Kind = yaml.ScalarNode
node.Value = "2.0"
data["a"] = node
bts, err2 := yaml.Marshal(data)
if err2 != nil {
require.NoError(t, err2)
}
require.Equal(t, "a: 2.0\n", string(bts))
} But if there's map of maps then one needs to traverse the map and generate a mirror structure but with |
Using go-yaml v2.2.2, whole number floats (e.g.,
1.0
) are marshaled to values that are ambiguous with integers (e.g.,1
). This makes it difficult to use go-yaml to modify arbitrary YAML without converting floats to integers.The YAML v1.2 spec makes it seem like
1
is a valid representation of a float:https://yaml.org/spec/1.2/spec.html#id2804923
While the YAML v1.1 spec suggests otherwise:
https://yaml.org/type/float.html
However, it isn't clear to me if these expressions are intended to apply to untagged values (without
!!float
), or just to allowed values when!!float
is used to specified the type.Given that YAML has distinct float and integer types, I propose that whole number floats be marshaled unambiguously.
For example:
Currently outputs:
Proposed change:
The text was updated successfully, but these errors were encountered: