jqlang/jq

|=.? returns empty

vintnes opened this issue · 11 comments

Thank you for this life-changing language. I regret that my first correspondence is a complaint.

Try-catch returns empty following filter assignment.

Input

 jq -nc '{foo: "bar"} | .foo |= .?'  

Expected output

 {"foo":"bar"}

Actual output

{}

Furthermore, // is unable to catch the result:

$ jq -nc '{foo: "bar"} | .foo |= ( .? // "baz" )'
{}

Environment (please complete the following information):

  • Debian Stretch, jq 1.5
  • jqplay, jq 1.6

This is an extremely minimized example; I'm actually trying to process incoming strings which may or may not contain valid JSON, as in .value |= (fromjson? // .). I catch some undocumented error formatting when I try this:

$ jq -nc '{value: "[]"} | .value |= try fromjson catch .'
{"value":{"__jq":0}}

Thanks again for your efforts.

That's a known bug that I think is fixed on master. If you're able, can you try building master from source?

@wtlangford Would you happen to have a link to the existing issue? I will close this as duplicate.

Sure, it's issue #2011

This is a different issue and reproducible with the master version.

 % jq --version
jq-master-a17dd32
 % jq -nc '{foo: "bar"} | .foo |= .?'
{}
 % jq -nc '{foo: "bar"} | .foo |= ( .? // "baz" )'
{}
 % jq -nc '{value: "[]"} | .value |= try fromjson catch .' # yes this works
{"value":[]}

Tentatively reopening on the basis that ? // has documented behavior different from that of try catch, specifically that catch . should return an error string, while // . should return the most recently piped input.

Also thought I should include my 1.5 workaround in case some poor soul with a conservative distro finds this thread because of the fromjson references:

.value as $string | .value = ( $string | fromjson? // . )

I think FORK_OPT (and DESTRUCTURE_ALT) should only react to the errors inside their scopes while FORK can be backtracked from anywhere (even from after emitting a value). Can we pop the fork stack when it gets out of the try catch scope or distinguish backtracks and errors completely by creating another forkopt stack?

Alright, now we're talking! @itchyny please see this branch https://github.com/leonid-s-usov/jq/tree/bt_signalling
It has a complete revision of the backtrack signaling and I actually have pushed some changes to DESTRUCTURE_ALT based on the new signalling here wtlangford#2

I'm finishing some scope of work at my day job and then have the plan to get back on track with the changes mentioned. It's a bit ambitious, cause it involves the dlopen initiative of @nicowilliams , but we'll pull it out this summer, I believe

Okay, thanks for explanation. I finally understand what #1859 (comment) means and it fixes various issues around this subject.

Regarding DESTRUCTURE_ALT, I noticed that the the subsequent expressions is not clear in the document if the subsequent expression returns an error, the alternative operator will attempt to try the next binding.

 % jq -n '[0] as [$x] ?// $x | $x[0]' # ok
0
 % jq -n '[0] as [$x] ?// $x | $x | .[0]' # still the subsequent expression?
0
 % jq -n '([0] as [$x] ?// $x | $x) | .[0]' # is this ok? or should be an error?
0
 % jq -n '([0] as [$x] ?// $x | $x) | type | error' # should be number?
jq: error (at <unknown>): array
 % jq -n '([2] as $x ?// [$x] | $x) * ([3] as $x ?// [$x] | $x)' # useful? or should be an error?
6

After encountering this error, I asked about it on Stackoverflow. One reply contained a link to this issue
Update operator yields empty object in JQ

~ jq --version
jq-1.6-145-ga9f97e9-dirty

~ jq -nc '{foo: "bar"} | .foo |= .?'
null