-
Notifications
You must be signed in to change notification settings - Fork 445
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
Different behavior of hidden status inheritance between Jsonnet and Go-Jsonnet #1111
Comments
Thanks for the bug report! Starting to investigate this. The C++ implementation implements object comprehensions through an internal object type https://github.com/google/jsonnet/blob/master/core/vm.cpp#L745-L748 } else if (auto *obj = dynamic_cast<const HeapComprehensionObject *>(obj_)) {
for (const auto &f : obj->compValues)
r[f.first] = ObjectField::VISIBLE;
} All fields are forced to 'VISIBLE', which probably accounts for the behaviour you're seeing here. The Go version implements object comprehensions differently, desugaring them to a call to a builtin function (builtinUglyObjectFlatMerge) which evaluates to a 'simple' object. That function appears to copy the field visibility to its output object. There may be details that I haven't grokked properly, particularly in the Go version, as I haven't really looked at the go-jsonnet implementation before. I think it's possible to make the C++ version respect field visibility in object comprehensions by storing visibility in the |
I will also note that my reading of the actual language abstract syntax at https://jsonnet.org/ref/spec.html#abstract_syntax is that object comprehensions as specified don't actually support either differing visibility, or the object-merge ( Regardless, if the merge sugar But it seems hidden or force-visible fields really aren't supported in object comprehensions. This simplifies a fix on the C++ side, where I think |
Even if +: was not supported then you could use |
It looks like the semantics declare that the object comprehension should use INHERIT (single |
As an aside, I often thought it would be nice if an object comprehension could choose |
This should make C++ Jsonnet match the existing behaviour of Go-Jsonnet. Object comprehensions do not support differing field visibility, that is an object comprehension with a "hidden" or "forced-visible" field such as `{[k]::1 for k in ["x"]}` is rejected with a syntax error. However, intuitively the `{[key_expr]: value_expr for x in ...}` syntax seems like it should behave similarly to a normal (non-comprehension) object that uses default field visibility. Default field visibility is to 'inherit' visibility when merging objects with the + operator, and this is the existing behaviour of Go-Jsonnet. Example case: ./jsonnet -e '{"one":: "base"} + {[k]: "derived" for k in ["one"]}' Before this commit, Go-Jsonnet output: { } Before this commit, C++ Jsonnet output: { "one": "derived" } Bug report: google#1111
This should make C++ Jsonnet match the existing behaviour of Go-Jsonnet. Object comprehensions do not support differing field visibility, that is an object comprehension with a "hidden" or "forced-visible" field such as `{[k]::1 for k in ["x"]}` is rejected with a syntax error. However, intuitively the `{[key_expr]: value_expr for x in ...}` syntax seems like it should behave similarly to a normal (non-comprehension) object that uses default field visibility. Default field visibility is to 'inherit' visibility when merging objects with the + operator, and this is the existing behaviour of Go-Jsonnet. Example case: ./jsonnet -e '{"one":: "base"} + {[k]: "derived" for k in ["one"]}' Before this commit, Go-Jsonnet output: { } Before this commit, C++ Jsonnet output: { "one": "derived" } Bug report: google#1111
…lity, not Unhide (#255) This PR changes the default visibility of fields in objects created by `std.mergePatch`: previously they were at `Unhide` visibility, equivalent to the `:::` operator, but as of this PR they are now at `Normal` standard visibility. Concretely, previously ```sjsonnet {a:: 0} + std.mergePatch({a: 1}, {}) ``` would return `{a: 1}` but after this patch it returns `{a:: 1)`, i.e. it preserves the hidden field. It turns out that v0.20.0 of google/jsonnet and google/go-jsonnet also differ in their behavior here. That, in turn, is due to a behavior difference in the default visibility of fields in object comprehension results: jsonnet marks object comprehension fields as forced-visible, while go-jsonnet marks them as inherited visibility; see google/jsonnet#1111. jsonnet accepted google/jsonnet#1140 to match go-jsonnet's behavior. Note that sjsonnet already matches go-jsonnet's behavior for object comprehensions: we only have a difference in `std.mergePatch` because our current implementation explicitly hardcodes Unhide visibility. This PR changes that mergePatch-specific behavior to match the current go-jsonnet (and future jsonnet) behavior.
Summary
I've been evaluating switching to Go-Jsonnet for our tooling and stumbled across a difference in how hidden status inheritance (https://jsonnet.org/ref/spec.html#hidden_inheritance) is implemented in Jsonnet and Go-Jsonnet.
Here's an example Jsonnet script which demonstrates the difference:
From what I can tell, the go-jsonnet implementation implements the specification correctly.
Example script evaluation and output
I've wrapped the example in Python (because that's what I had readily available) to run both implementations side-by-side:
This gives the following in a virtualenv (setup with
python3 -m venv venv && source venv/bin/activate && pip install jsonnet gojsonnet
):The text was updated successfully, but these errors were encountered: