Skip to content

support both String and Symbol keys for all dict-operations on Objects#421

Merged
quinnj merged 1 commit into
JuliaIO:masterfrom
hhaensel:hh-symbol_string
Jan 12, 2026
Merged

support both String and Symbol keys for all dict-operations on Objects#421
quinnj merged 1 commit into
JuliaIO:masterfrom
hhaensel:hh-symbol_string

Conversation

@hhaensel
Copy link
Copy Markdown
Contributor

  • add methods for setindex!(), delete!() for obj::Object{String}, key::Symbol and vice versa
  • add method haskey(obj::Object{String}, key::Symbol)
  • add respective tests

…ey::Symbol and vice versa plus respective tests
@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.23%. Comparing base (928a3cc) to head (06ad3ee).
⚠️ Report is 2 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #421      +/-   ##
==========================================
+ Coverage   90.05%   90.23%   +0.18%     
==========================================
  Files           7        7              
  Lines        1347     1352       +5     
==========================================
+ Hits         1213     1220       +7     
+ Misses        134      132       -2     

☔ View full report in Codecov by Sentry.
📢 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.

@hhaensel
Copy link
Copy Markdown
Contributor Author

Background:
I have a program where I check for the existence of a key and if it exists, I modify the entry under certain conditions.
With the current implementation in JSON a key might exist, but I'm not allowed to modify the respective entry. Same story with deletion of entries. That's confusing.

julia> obj = JSON.parse("""{"a": "a"}""");

julia> haskey(obj, :a)
true

julia> obj[:a] = "b"
ERROR: MethodError: no method matching setindex!(::JSON.Object{String, Any}, ::String, ::Symbol)
The function `setindex!` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  setindex!(::AbstractDict, ::Any, ::Any, ::Any, ::Any...)
   @ Base abstractdict.jl:560
  setindex!(::JSON.Object{K, V}, ::Any, ::K) where {K, V}
   @ JSON ~/.julia/dev/JSON/src/object.jl:160

This PR solves that issue.

@hhaensel
Copy link
Copy Markdown
Contributor Author

BTW, @quinnj, are you planning a new release?

Copy link
Copy Markdown
Member

@quinnj quinnj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! This is a good follow-up to #420 for consistency.

Review Summary

Implementation: Clean and follows the existing pattern - simple delegation with key conversion. No issues here.

Tests: Comprehensive coverage for the methods added. The tests properly check both directions (Object{String} with Symbol keys and Object{Symbol} with String keys).

One Gap Remaining

After this PR, there's still one set of methods missing for full consistency - the get methods:

julia> obj = JSON.parse("""{"a": 1}""")
julia> get(obj, :a, 0)  # fails
ERROR: MethodError: no method matching find_node_by_key(::JSON.Object{String, Any}, ::Symbol)

julia> get(() -> 0, obj, :a)  # also fails
ERROR: MethodError: ...

To complete the String/Symbol interoperability, we'd also need:

Base.get(f::Base.Callable, obj::Object{String}, key::Symbol) = get(f, obj, String(key))
Base.get(f::Base.Callable, obj::Object{Symbol}, key::String) = get(f, obj, Symbol(key))
Base.get(obj::Object{String}, key::Symbol, default) = get(obj, String(key), default)
Base.get(obj::Object{Symbol}, key::String, default) = get(obj, Symbol(key), default)

Suggestion: Either add these to this PR, or we can merge this as-is and follow up with another PR. The current changes are valuable on their own.

Summary Table (after this PR)

Method Object{String} + Symbol Object{Symbol} + String
getindex #420 #420
setindex! ✅ this PR ✅ this PR
delete! ✅ this PR ✅ this PR
haskey ✅ existing ✅ this PR
get(callable, ...) ❌ missing ❌ missing
get(..., default) ❌ missing ❌ missing

Overall this looks good to merge as-is, with an optional follow-up for the get methods.

Copy link
Copy Markdown
Member

@quinnj quinnj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Merging now. I'll follow up with the missing get methods in a separate commit.

@quinnj quinnj merged commit 738fda9 into JuliaIO:master Jan 12, 2026
11 checks passed
quinnj added a commit that referenced this pull request Jan 12, 2026
Completes String/Symbol interoperability for Object by adding get
methods that accept cross-key-types:

- get(f::Callable, obj::Object{String}, key::Symbol)
- get(f::Callable, obj::Object{Symbol}, key::String)
- get(obj::Object{String}, key::Symbol, default)
- get(obj::Object{Symbol}, key::String, default)

This follows up on #421 which added setindex!, delete!, and haskey
for cross-key-types.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@hhaensel
Copy link
Copy Markdown
Contributor Author

@quinnj May I ask when you plan the next release?
I have a pending decision in one of my projects that depends on the implementation of this PR. I could wait or work around.

quinnj referenced this pull request Jan 14, 2026
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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.

2 participants