Compatibility notes
On this page
Decision statusesInventoryWhat this inventory does not coverこのページの目次
判断状態A. 2.xで維持する互換性上の動作B. 算術と型変換C. 比較D. null、欠損値、パスE. 反復とパイプラインF. 代入と更新G. 未対応のjq機能H. 明示的な拡張と移行補助この一覧の対象外JQ::Liteは実用的なjq形式の言語を実装しますが、jqのすべての実行時の意味論をそのまま再現するものではありません。この文書は、両者が受け付けるフィルターでも結果や失敗の振る舞いが異なる既知のケースを記録します。2.xの動作の一覧であり、未対応の構文への対応を宣言するものではありません。
jq列の基準はjq 1.7です。JQ::Liteの結果はt/jq_semantic_differences.tで保護され、回帰テストにjq実行ファイルは不要です。
判断状態
- 維持:jqと異なってもJQ::Liteの意味を保つ。
- v3で変更:2.xでは保ち、個別レビューを経てv3でjq互換へ寄せる。
- 未決定:v3での決定はまだない。決定まで2.xの動作をテストで保護する。
この分類はロードマップ上の判断であり、2.xの動作変更ではありません。検討対象は架空のIssue番号ではなく、議題名で示します。
A. 2.xで維持する互換性上の動作
既存利用者が依存し得るため、構文解析やフィルター整理のついでに変更してはいけません。
| 項目 | 例 | jq 1.7 | JQ::Lite 2.x | v3の判断 | 検討対象 |
|---|---|---|---|---|---|
| 配列のcontains | [1,2,3] | contains([1,3]) |
true:再帰的な部分集合包含 |
false:引数全体と等しい1要素を探す |
v3で変更 | 包含の意味論 |
| 入れ子のオブジェクト | {"a":{"b":1,"c":2}} | contains({"a":{"b":1}}) |
true |
false:入れ子の値は等値が必要 |
v3で変更 | 包含の意味論 |
| 代替値演算子 | false // 9 |
9 |
false:null・欠損・空出力のみ代替 |
v3で変更 | nullと代替値 |
| 不揃いな行の転置 | [[1,2],[3]] | transpose |
[[1,3],[2,null]] |
[[1,3]]:最短行で切り詰める |
維持 | なし |
contains_subset(value)は再帰的で順序を問わない包含のための代替ですが、jqのcontainsと同一ではありません。多重集合として重複回数を数え、スカラーを文字列表現で比較します。
[1] | contains_subset([1,1])はfalseですが、jqのcontains([1,1])はtrueです。["1"] | contains_subset([1])はtrueですが、jqのcontains([1])はfalseです。
B. 算術と型変換
JQ::Liteは値を失わないパイプライン処理やPerlのスカラー変換を重視する場合があり、jqの型エラーや演算子の振る舞いと異なります。
| 項目 | 例 | jq 1.7 | JQ::Lite 2.x | v3の判断 | 検討対象 |
|---|---|---|---|---|---|
| 数値への変換 | "1e3" * 1 |
"1e3":文字列の反復 |
1000 |
未決定 | 算術・型変換 |
| 真偽値の算術 | true + 1 |
型エラー | 2 |
v3で変更 | 算術・型変換 |
| 配列への丸め | [1.2,"2.8","x"] | floor |
型エラー | [1,2,"x"] |
維持 | なし |
| 値を保持するJSON解析 | ["1","true","bad"] | fromjson |
型エラー:文字列でない入力 | [1,true,"bad"]:要素ごとに解析し不正な文字列は維持 |
維持 | なし |
| 正規表現のスカラー変換 | 42 | match("2") |
型エラー | "42"に対する一致オブジェクト |
未決定 | 型変換 |
JQ::Liteで成功しても、jqが同じ入力型を受け付けるとは限りません。jqの演算子の振る舞いをPerlの数値変換と同じだと仮定しないでください。
C. 比較
| 項目 | 例 | jq 1.7 | JQ::Lite 2.x | v3の判断 | 検討対象 |
|---|---|---|---|---|---|
| 異なる型の等値 | "10" == 10 |
false |
true:数値に見える文字列を数値比較 |
v3で変更 | 比較の意味論 |
| JSON型間の順序 | false < 0 |
true |
true |
維持 | 一致を保つ回帰テスト |
| 配列の順序 | [1,2] < [1,3] |
true:辞書式の順序 |
false |
v3で変更 | 比較の意味論 |
| 欠損値の比較 | .missing == null |
true |
true |
維持 | 一致を保つ回帰テスト |
一致する行も意図的に含めています。型変換の修正により、既にjqと一致する近接ケースが変わるのを防ぎます。
D. null、欠損値、パス
| 項目 | 例 | jq 1.7 | JQ::Lite 2.x | v3の判断 | 検討対象 |
|---|---|---|---|---|---|
| 欠損したフィールド | {}に.missing |
nullを1つ返す | 結果なし | v3で変更 | null・欠損・パス |
| 欠損フィールド経由 | {}に.missing.value |
nullを1つ返す | 結果なし | v3で変更 | null・欠損・パス |
| 配列の不正なフィールドパス | {"a":[]}に.a.value |
型エラー | 結果なし | 未決定 | パスのエラー方針 |
| オブジェクトの数値添字 | {}に.[5] |
型エラー | nullを1つ返す | v3で変更 | パスのエラー方針 |
直接のパス出力では、欠損の探索結果(空の結果列)と明示的なJSON nullを区別します。一方、.missing == nullの比較では現状同様に扱います。
E. 反復とパイプライン
| 項目 | 例 | jq 1.7 | JQ::Lite 2.x | v3の判断 | 検討対象 |
|---|---|---|---|---|---|
| 配列のパス射影 | [{"x":1},{"x":2}] | .x |
型エラー | 1, 2 |
維持 | なし |
| 混合型の反復後の射影 | {"a":[{"x":1}],"n":3} | .[] | .x |
配列で型エラー | 1:配列を射影しスカラーの欠損は落とす |
未決定 | 反復・パイプライン |
| 反復の接尾構文 | keys[] |
keys | .[]と同じ |
keys | .[]と同じ |
維持 | 一致を保つ回帰テスト |
| コンマと反復 | 0, [4,5][] |
0, 4, 5 |
0, 4, 5 |
維持 | 一致を保つ回帰テスト |
F. 代入と更新
| 項目 | 例 | jq 1.7 | JQ::Lite 2.x | v3の判断 | 検討対象 |
|---|---|---|---|---|---|
| 通常の代入 | {"a":1} | .a = 2 |
{"a":2} |
{"a":2} |
維持 | 一致を保つ回帰テスト |
| 更新代入の結果 | {"a":1} | .a |= . + 1 |
{"a":2} |
2:ルートではなく更新値を返す |
v3で変更 | 代入・更新 |
| 欠損した更新先 | {"a":1} | .missing |= . + 1 |
"missing":1を含むオブジェクト |
結果なし | v3で変更 | 代入・更新 |
| 複数結果の代入 | {"a":0} | .a = (1,2) |
更新したオブジェクトを2つ返す | 結果なし | 未決定 | 代入と結果列 |
G. 未対応のjq機能
機能がないことと意味論の衝突は別ですが、移植性に影響するため記録します。
| 機能 | 例 | JQ::Lite 2.x | v3の判断 | 検討対象 |
|---|---|---|---|---|
| ユーザー定義関数 | def inc: . + 1; inc |
未実装。現状はnullと評価 | 未決定 | 未対応構文の方針 |
| ラベルとbreak | label $out | break $out |
未実装 | 未決定 | 制御フロー |
| モジュール・import | import "x" as x; ... |
未実装 | 維持 | 軽量な範囲の対象外 |
| ストリーミング解析 | --stream |
CLIオプション未実装 | 維持 | 現在のCLI範囲外 |
H. 明示的な拡張と移行補助
jqと衝突する意味ではなく、JQ::Liteの意図や既存パイプラインに有用な動作を表します。
| 拡張 | 目的 | v3の判断 | 検討対象 |
|---|---|---|---|
contains_subset(value) |
再帰的・順序非依存の多重集合包含。重複には重複した一致が必要で、スカラーは文字列比較 | 未決定 | contains変更時に名前と意味を整合 |
to_number() |
厳密なtonumberと異なる、値を保持する要素ごとの数値変換 | 維持 | なし |
flatten_all(), flatten_depth(n) |
平坦化の明示的な形式 | 維持 | なし |
| 統計・便利な補助関数 | avg、median、mode、percentile、variance、stddev、clampなど |
維持 | なし |
この一覧の対象外
- 未対応の組み込み関数・CLIオプションをすべて列挙したものではありません。
- CLI診断は安定したCLI仕様に従い、jqの厳密なエラー文言は保証しません。
- JSONオブジェクトのキー順序は移植可能な意味論の保証でないため比較しません。
- jq 1.7以降の変更と、JQ::Lite自身の変更は別々に確認する必要があります。
差分を発見した場合は該当分類へ追加し、外部依存なしで現在の動作を保護する回帰テストを追加します。将来の変更は2.xへの影響を明示し、別の提案として扱います。
JQ::Lite implements a useful jq-like language, but it is not a drop-in implementation of every jq runtime semantic. This document records the currently known semantic differences: cases where a filter is accepted by both tools but its result or failure behaviour differs. It is a snapshot of the 2.x behaviour, not a claim that unsupported jq syntax is supported.
The examples in the jq column describe jq 1.7 behaviour. The JQ::Lite
results are protected by t/jq_semantic_differences.t; the regression suite
does not require a jq executable.
Decision statuses
Every inventoried item has one of the decision statuses requested for the v3 planning process:
- preserve — keep the JQ::Lite meaning, even though jq differs;
- change in v3 — retain it throughout 2.x, but make jq compatibility the target of a separately reviewed v3 change;
- undecided — no v3 decision has been made. The 2.x behaviour remains regression-protected until that decision is made.
The status is a roadmap classification, not a runtime change in the 2.x series. “Follow-up” deliberately uses topic names rather than inventing issue numbers; it can be replaced by a concrete issue link when that work is filed.
Inventory
A. Preserved 2.x compatibility behaviour
These differences are observable existing behaviour on which 2.x callers may rely. Changing them requires an explicit compatibility decision rather than an incidental parser or filter refactor.
| Area | Example | jq | JQ::Lite 2.x | v3 status | Follow-up |
|---|---|---|---|---|---|
Array contains |
[1,2,3] | contains([1,3]) |
true (recursive subset containment) |
false (looks for one element equal to the complete argument) |
change in v3 | containment semantics |
Nested object contains |
{"a":{"b":1,"c":2}} | contains({"a":{"b":1}}) |
true |
false (nested values must be equal) |
change in v3 | containment semantics |
| Alternative operator | false // 9 |
9 |
false (only null, missing, or empty output selects the fallback) |
change in v3 | null and fallback semantics |
Jagged transpose |
[[1,2],[3]] | transpose |
[[1,3],[2,null]] |
[[1,3]] (truncates to the shortest row) |
preserve | none |
For recursive, order-insensitive array containment, JQ::Lite provides the
explicit contains_subset(value) alternative. It avoids changing the
established meaning of contains(value) in the 2.x series, but it is not a
drop-in implementation of jq's contains: it uses multiset counting, whereas
jq can satisfy repeated needles with one matching value, and it compares
scalars by their string forms, whereas jq keeps JSON scalar types distinct.
For example, [1] | contains_subset([1,1]) is false although jq's
contains([1,1]) is true; ["1"] | contains_subset([1]) is true although
jq's contains([1]) is false.
B. Arithmetic and type coercion
JQ::Lite commonly favours lossless pipeline processing and Perl scalar coercion where jq reports a type error or applies a different overloaded operation.
| Area | Example | jq | JQ::Lite 2.x | v3 status | Follow-up |
|---|---|---|---|---|---|
| Numeric coercion | "1e3" * 1 |
"1e3" (string repetition) |
1000 |
undecided | arithmetic/coercion |
| Boolean arithmetic | true + 1 |
type error | 2 |
change in v3 | arithmetic/coercion |
| Vectorised rounding | [1.2,"2.8","x"] | floor |
type error | [1,2,"x"] |
preserve | none |
| Lossless JSON parsing | ["1","true","bad"] | fromjson |
type error (input is not a string) | [1,true,"bad"] (element-wise, invalid text passes through) |
preserve | none |
| Regex scalar coercion | 42 | match("2") |
type error | a match object for the string form "42" |
undecided | type coercion |
This category is especially important when moving filters between the tools: successful JQ::Lite output does not imply that jq will accept the same input types. Conversely, jq operator overloading must not be assumed to use Perl's numeric coercion in JQ::Lite.
C. Comparison
| Area | Example | jq | JQ::Lite 2.x | v3 status | Follow-up |
|---|---|---|---|---|---|
| Equality across types | "10" == 10 |
false |
true (numeric-looking strings compare numerically) |
change in v3 | comparison semantics |
| Ordering across JSON types | false < 0 |
true |
true |
preserve | none; regression parity guard |
| Array ordering | [1,2] < [1,3] |
true (lexicographic ordering) |
false |
change in v3 | comparison semantics |
| Missing-value comparison | .missing == null |
true |
true |
preserve | none; regression parity guard |
Parity rows are included intentionally: they mark adjacent behaviour that was checked during the inventory and prevent a future coercion fix from changing a currently jq-compatible case by accident.
D. Null, missing values, and paths
| Area | Example | jq | JQ::Lite 2.x | v3 status | Follow-up |
|---|---|---|---|---|---|
| Missing object field | {} with .missing |
one null result |
no results | change in v3 | null/missing/path semantics |
| Path through a missing field | {} with .missing.value |
one null result |
no results | change in v3 | null/missing/path semantics |
| Invalid array field path | {"a":[]} with .a.value |
type error | no results | undecided | path error policy |
| Numeric index on an object | {} with .[5] |
type error | one null result |
change in v3 | path error policy |
JQ::Lite therefore distinguishes a missing traversal (an empty result stream)
from an explicit JSON null in direct path output, even though comparisons such
as .missing == null currently treat them alike.
E. Iterators and pipelines
| Area | Example | jq | JQ::Lite 2.x | v3 status | Follow-up |
|---|---|---|---|---|---|
| Array path projection | [{"x":1},{"x":2}] | .x |
type error | 1, 2 |
preserve | none |
| Projection after mixed iteration | {"a":[{"x":1}],"n":3} | .[] | .x |
type error on the array | 1 (projects through the array and drops the scalar's missing value) |
undecided | iterator/pipeline semantics |
| Iterator suffix | keys[] |
same results as keys | .[] |
same results as keys | .[] |
preserve | none; regression parity guard |
| Comma plus iterator | 0, [4,5][] |
0, 4, 5 |
0, 4, 5 |
preserve | none; regression parity guard |
F. Assignment and update
| Area | Example | jq | JQ::Lite 2.x | v3 status | Follow-up |
|---|---|---|---|---|---|
| Plain assignment | {"a":1} | .a = 2 |
{"a":2} |
{"a":2} |
preserve | none; regression parity guard |
| Update assignment result | {"a":1} | .a |= . + 1 |
{"a":2} |
2 (emits the updated value, not the root) |
change in v3 | assignment/update semantics |
| Missing update target | {"a":1} | .missing |= . + 1 |
object with "missing":1 |
no results | change in v3 | assignment/update semantics |
| Multi-result assignment | {"a":0} | .a = (1,2) |
two updated objects | no results | undecided | assignment/update stream semantics |
G. Unsupported jq behaviour
Feature absence is distinct from a semantic conflict, but unsupported jq constructs affect portability and are therefore tracked here as required by the audit.
| jq facility | Example | JQ::Lite 2.x | v3 status | Follow-up |
|---|---|---|---|---|
| User-defined functions | def inc: . + 1; inc |
not implemented; currently evaluates to null |
undecided | parser unsupported-syntax policy |
Labels and break |
label $out | break $out |
not implemented | undecided | control-flow coverage |
| Modules/imports | import "x" as x; ... |
not implemented | preserve | none; outside lightweight scope |
| jq streaming parser mode | --stream |
CLI option not implemented | preserve | none; outside current CLI scope |
H. Explicit JQ::Lite extensions and migration aids
These names do not represent a conflicting jq meaning; they make JQ::Lite's intent explicit or provide behaviours useful to existing pipelines.
| Extension | Purpose | v3 status | Follow-up |
|---|---|---|---|
contains_subset(value) |
Recursive, order-insensitive multiset containment; unlike jq, duplicate needles require duplicate matches and scalar comparison coerces to strings | undecided | reconcile its semantics and name if contains changes in v3 |
to_number() |
Lossless/vectorised numeric conversion, distinct from strict tonumber() |
preserve | none |
flatten_all(), flatten_depth(n) |
Explicit flattening variants | preserve | none |
| Statistical and convenience helpers | avg, median, mode, percentile, variance, stddev, clamp, and the other extensions listed in the function reference |
preserve | none |
What this inventory does not cover
- The unsupported-behaviour table is representative rather than a complete list of every jq built-in or command-line option not implemented by JQ::Lite.
- CLI diagnostics are governed by the stable CLI contract; exact jq error text is not a JQ::Lite compatibility promise.
- Object key order is not compared because JSON object ordering is not a portable semantic guarantee.
- jq may evolve after 1.7. When this inventory is updated, jq-version changes and JQ::Lite behaviour changes should be reviewed separately.
When a new difference is found, add it to the appropriate category and add a dependency-free regression assertion for the current JQ::Lite behaviour. A future behaviour change should be proposed separately, with the relevant 2.x compatibility impact called out explicitly.