Skip to content

Write StructUtils.Selectors.List as a JSON array - #502

Draft
krynju wants to merge 1 commit into
JuliaIO:masterfrom
krynju:kg/write-selectors-list
Draft

krynju wants to merge 1 commit into
JuliaIO:masterfrom
krynju:kg/write-selectors-list

Conversation

@krynju

@krynju krynju commented Oct 8, 2026

Copy link
Copy Markdown

StructUtils.Selectors.List <: AbstractVector, so JSON's AbstractVector{<:Pair}, AbstractVector{Any} and AbstractVector{Pair{K,Any}} methods are ambiguous with StructUtils' own arraylike(::StructStyle, ::List) / applyeach(::StructStyle, f, ::List). On master:

julia> using JSON, StructUtils; const List = StructUtils.Selectors.List

julia> JSON.json(JSON.lazy("""{"a":[{"b":1},{"b":2}]}""")[~, :b])   # a List{Any}
ERROR: MethodError: applyeach(::JSON.JSONWriteStyle, ::JSON.WriteClosure{…}, ::List{Any}) is ambiguous.

julia> JSON.json(List([:a => 1]))
ERROR: MethodError: arraylike(::JSON.JSONWriteStyle, ::List{Pair{Symbol, Int64}}) is ambiguous.

julia> JSON.json(List(Union{Int,Missing}[1, missing]))   # StructUtils' List applyeach skips `lower`
"[1,\"missing\"]"

This defines arraylike and applyeach for List on JSONStyle: a List is always written as a plain array of its lowered items. Vector{Any} items keep JSON's concrete-dispatch applyeach; anything else goes through StructUtils' generic AbstractArray method via invoke, which bypasses the AbstractVector{<:Pair} object methods on purpose, since List{<:Pair} is arraylike in StructUtils unlike Vector{<:Pair}.

After:

julia> JSON.json(JSON.lazy("""{"a":[{"b":1},{"b":2}]}""")[~, :b])
"[1,2]"

julia> JSON.json(List([:a => 1])), JSON.json(List(Union{Int,Missing}[1, missing])), JSON.json(List(Union{}[]))
("[{\"a\":1}]", "[1,null]", "[]")

Found while working on #500 (the Vector{Union{}} fix), whose AbstractVector{Union{}} method has the same List{Union{}} ambiguity; this PR resolves that one too, and the two PRs are independent. Selectors.List exists in StructUtils since 2.7.1, within the current compat. Full test suite passes locally except for the pre-existing juliac --trim segfault on Julia 1.12.7, which reproduces on unmodified master.

🤖 Generated with Claude Code

`Selectors.List <: AbstractVector`, so JSON's `AbstractVector{<:Pair}`,
`AbstractVector{Any}` and `AbstractVector{Pair{K,Any}}` methods are
ambiguous with StructUtils' own `arraylike`/`applyeach` methods for
`List`. In particular `List{Any}`, which is what the selector syntax
returns, could not be written at all (MethodError), and `List` items
skipped `lower`, so `missing` was written as `"missing"`.

Define `arraylike` and `applyeach` for `List` on the JSON style: a List
is always written as a plain array of its lowered items, including
`List{<:Pair}`, which unlike `Vector{<:Pair}` is arraylike in StructUtils.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@codecov

codecov Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.59%. Comparing base (4f3dfdc) to head (942feb2).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #502      +/-   ##
==========================================
+ Coverage   92.57%   92.59%   +0.01%     
==========================================
  Files           7        7              
  Lines        1927     1932       +5     
==========================================
+ Hits         1784     1789       +5     
  Misses        143      143              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant