JSON3.jl icon indicating copy to clipboard operation
JSON3.jl copied to clipboard

Can't serialize unitful quantities

Open philip-stuckey opened this issue 3 years ago • 2 comments

Whenever I try to serialize a unitful quantity, I get a stack overflow error.

using JSON3
using Unitful: m
JSON3.write(10m)

yields

ERROR: StackOverflowError:
Stacktrace:
     [1] write(::StructTypes.NumberType, buf::Vector{UInt8}, pos::Int64, len::Int64, x::Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}})
       @ JSON3 ~/.julia/packages/JSON3/CpNms/src/write.jl:225
     [2] write(::StructTypes.NumberType, buf::Vector{UInt8}, pos::Int64, len::Int64, x::Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}; kw::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
       @ JSON3 ~/.julia/packages/JSON3/CpNms/src/write.jl:240
--- the last 2 lines are repeated 26659 more times ---
 [53321] write(::StructTypes.NumberType, buf::Vector{UInt8}, pos::Int64, len::Int64, x::Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}})
       @ JSON3 ~/.julia/packages/JSON3/CpNms/src/write.jl:225

julia and package info

julia Version 1.8.3
Commit 0434deb161e (2022-11-14 20:14 UTC)
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 4 × Intel(R) Core(TM) i7-4600U CPU @ 2.10GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, haswell)
  Threads: 4 on 4 virtual cores
  [0f8b85d8] JSON3 v1.12.0
  [1986cc42] Unitful v1.12.1

philip-stuckey avatar Nov 22 '22 15:11 philip-stuckey

I've narrowed down the problem. JSON3.write assumes that StructType.construct(NT,x) returns an object of type NT (in this case NT==Float64), and Unitful breaks that assumption by defining Float64(x) = Quantity(Float64(x.val), unit(x)).

philip-stuckey avatar Nov 22 '22 18:11 philip-stuckey

Hmmmm....I'm struggling to figure out what the right thing to do is for unitful quantities. They overload string to return 10 m, which isn't valid JSON. And you cant' do convert(Float64, x) because you get this cryptic error:

julia> convert(Float64, x)
ERROR: DimensionError:  and m are not dimensionally compatible.
Stacktrace:
 [1] #s104#159
   @ ~/.julia/packages/Unitful/G8F13/src/conversion.jl:12 [inlined]
 [2] var"#s104#159"(::Any, s::Any, t::Any)
   @ Unitful ./none:0
 [3] (::Core.GeneratedFunctionStub)(::Any, ::Vararg{Any})
   @ Core ./boot.jl:602
 [4] uconvert(a::Unitful.FreeUnits{(), NoDims, nothing}, x::Unitful.Quantity{Int64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}})
   @ Unitful ~/.julia/packages/Unitful/G8F13/src/conversion.jl:78
 [5] convert(#unused#::Type{Float64}, y::Unitful.Quantity{Int64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}})
   @ Unitful ~/.julia/packages/Unitful/G8F13/src/conversion.jl:145
 [6] top-level scope
   @ REPL[10]:1

It seems like probably the most robust solution would be to do an extension package where we write unitful quantities as JSON strings and then hopefully there's a way to parse unitful quantities?

quinnj avatar Mar 13 '23 23:03 quinnj