diff --git a/docs/content/manual/manual.yml b/docs/content/manual/manual.yml index 89252ac243..80ffb831bf 100644 --- a/docs/content/manual/manual.yml +++ b/docs/content/manual/manual.yml @@ -2373,9 +2373,16 @@ sections: - title: "Alternative operator: `//`" body: | - A filter of the form `a // b` produces the same - results as `a`, if `a` produces results other than `false` - and `null`. Otherwise, `a // b` produces the same results as `b`. + The `//` operator produces all the values of its left-hand + side that are neither `false` nor `null`, or, if the + left-hand side produces no values other than `false` or + `true`, then `//` produces all the values of its right-hand + side. + + A filter of the form `a // b` produces all the results of + `a` that are not `false` or `null`. If `a` produces no + results, or no results other than `false` or `null`, then `a + // b` produces the results of `b`. This is useful for providing defaults: `.foo // 1` will evaluate to `1` if there's no `.foo` element in the @@ -2383,13 +2390,36 @@ sections: (jq's `or` operator is reserved for strictly Boolean operations). - examples: + Note: `some_generator // defaults_here` is not the same + as `some_generator | . // defaults_here`. The latter will + produce default values for all non-`false`, non-`null` + values of the left-hand side, while the former will not. + Precedence rules can make this confusing. For example, in + `false, 1 // 2` the left-hand side of `//` is `1`, not + `false, 1` -- `false, 1 // 2` parses the same way as `false, + (1 // 2)`. In `(false, null, 1) | . // 42` the left-hand + side of `//` is `.`, which always produces just one value, + while in `(false, null, 1) // 42` the left-hand side is a + generator of three values, and since it produces a + value other `false` and `null`, the default `42` is not + produced. + + examples: + - program: 'empty // 42' + input: 'null' + output: ['42'] - program: '.foo // 42' input: '{"foo": 19}' output: ['19'] - program: '.foo // 42' input: '{}' output: ['42'] + - program: '(false, null, 1) // 42' + input: 'null' + output: ['1'] + - program: '(false, null, 1) | . // 42' + input: 'null' + output: ['42', '42', '1'] - title: try-catch body: | diff --git a/jq.1.prebuilt b/jq.1.prebuilt index de3dfa34f2..11bce4239a 100644 --- a/jq.1.prebuilt +++ b/jq.1.prebuilt @@ -2565,15 +2565,25 @@ jq \'[true, false | not]\' .IP "" 0 . .SS "Alternative operator: //" -A filter of the form \fBa // b\fR produces the same results as \fBa\fR, if \fBa\fR produces results other than \fBfalse\fR and \fBnull\fR\. Otherwise, \fBa // b\fR produces the same results as \fBb\fR\. +The \fB//\fR operator produces all the values of its left\-hand side that are neither \fBfalse\fR nor \fBnull\fR, or, if the left\-hand side produces no values other than \fBfalse\fR or \fBtrue\fR, then \fB//\fR produces all the values of its right\-hand side\. +. +.P +A filter of the form \fBa // b\fR produces all the results of \fBa\fR that are not \fBfalse\fR or \fBnull\fR\. If \fBa\fR produces no results, or no results other than \fBfalse\fR or \fBnull\fR, then \fBa // b\fR produces the results of \fBb\fR\. . .P This is useful for providing defaults: \fB\.foo // 1\fR will evaluate to \fB1\fR if there\'s no \fB\.foo\fR element in the input\. It\'s similar to how \fBor\fR is sometimes used in Python (jq\'s \fBor\fR operator is reserved for strictly Boolean operations)\. . +.P +Note: \fBsome_generator // defaults_here\fR is not the same as \fBsome_generator | \. // defaults_here\fR\. The latter will produce default values for all non\-\fBfalse\fR, non\-\fBnull\fR values of the left\-hand side, while the former will not\. Precedence rules can make this confusing\. For example, in \fBfalse, 1 // 2\fR the left\-hand side of \fB//\fR is \fB1\fR, not \fBfalse, 1\fR \-\- \fBfalse, 1 // 2\fR parses the same way as \fBfalse, (1 // 2)\fR\. In \fB(false, null, 1) | \. // 42\fR the left\-hand side of \fB//\fR is \fB\.\fR, which always produces just one value, while in \fB(false, null, 1) // 42\fR the left\-hand side is a generator of three values, and since it produces a value other \fBfalse\fR and \fBnull\fR, the default \fB42\fR is not produced\. +. .IP "" 4 . .nf +jq \'empty // 42\' + null +=> 42 + jq \'\.foo // 42\' {"foo": 19} => 19 @@ -2581,6 +2591,14 @@ jq \'\.foo // 42\' jq \'\.foo // 42\' {} => 42 + +jq \'(false, null, 1) // 42\' + null +=> 1 + +jq \'(false, null, 1) | \. // 42\' + null +=> 42, 42, 1 . .fi . diff --git a/tests/man.test b/tests/man.test index 354043ba67..822de5ab9a 100644 --- a/tests/man.test +++ b/tests/man.test @@ -769,6 +769,10 @@ false null [false, true] +empty // 42 +null +42 + .foo // 42 {"foo": 19} 19 @@ -777,6 +781,16 @@ null {} 42 +(false, null, 1) // 42 +null +1 + +(false, null, 1) | . // 42 +null +42 +42 +1 + try .a catch ". is not an object" true ". is not an object"