opa
opa copied to clipboard
Inconsistencies comparing int and float of same value (1 == 1.0)
While unlikely to be a problem in real-world policies, this coercion of float-value keys in maps is pretty confusing:
% opa eval -fpretty '{1: true, 1.0: false}'
{
"1": false
}
% opa eval -fpretty '{1.0: false, 1: true}'
{
"1": true,
"1.0": false
}
EDIT: Updated title to reflect that this is not isolated to object keys. More examples provided in comments below.
@anderseknert Is this something you think we can resolve with better docs?
The JSON spec's section on Objects has a grammar definition that requires all keys in a JSON object to be strings, so I assume that's why the OPA implementation coerces floats to string values here-- we're trying to match the JSON spec.
Rego has always been allowing keys to objects that aren't strings, and when the Rego rubber hits the JSON road, we need to do something about that. So we've been converting everything to strings, for better or for worse. There are known clashes, already, when using "1"
as an object key while also having 1
as key -- we'll need to pick something. But for floats, this just seems particularly confusing.
But I'm not completely sure that the JSON coercion isn't just one symptom of another underlying problem. Watch this:
$ opa eval -fpretty '1.0 == 1'
true
$ opa eval -fpretty 'count({1.0, 1})'
2
It's the same but a set consisting of both has two elements? I don't quite agree. 😅
Indeed, it isn't the number -> string coercion that's troubling here, but how 1.0 == 1
... maybe, maybe not :)
The example in the first description (which Stephan provided on Slack) was really my "favorite" one, where the order of idential entries in the map determines the number of items in the output 😄
Javascript, which has the same notion of 1 being equal to 1.0, does this correctly, I think:
JSON.stringify({1.0: 1})
"{\"1\":1}"
JSON.stringify({1.0: 1, 1: 1})
"{\"1\":1}"
JSON.stringify({1: 1, 1.0: 1})
"{\"1\":1}"
Perhaps a more important question to dig into: do we want to expose 2x numeric types at Rego-level (floats/ints), or do we want to expose only Javascript-style Number types that work kind of like floats most of the time?
Under the hood, we could still be switching representation dynamically, based on what's most efficient.
do we want to expose 2x numeric types at Rego-level (floats/ints), or do we want to expose only Javascript-style Number types that work kind of like floats most of the time?
I think at least on the surface, we're (should be) trying to uphold the illusion that there's only one number type in Rego.
Yep, like it or not, I think we'll have to accept that 1 == 1.0
😄 Let's just make it consistently so. When creating the issue I thought this was isolated to map keys, but as @srenatus have demonstrated, this is obviously not the case. I'll update the title to reflect this.
This issue has been automatically marked as inactive because it has not had any activity in the last 30 days.