Unitful.jl
Unitful.jl copied to clipboard
Matching serialise/deserialise behaviours for units
Discussed from https://github.com/PainterQubits/Unitful.jl/issues/214#issuecomment-714178239 onwards. Making a separate issue so this is easier to find and track.
We should be able to serialise and deserialise units to strings - so e.g. that a table with a units column can be save and loaded again.The way of doing this suggested by @c42f is to make show output the raw julia version that uparse can read back into units. We would then add print methods and some REPL show methods that keep the current behaviour in normal use.
A PR for this would involve:
- [ ] swapping current
showmethods to work withprint - [ ] define
show(::IO, ::MIME"text/plain", unit)so the REPL still looks ok. - [ ] write new show methods that return the raw julia version
- [ ] write some tests for print/string/show behaviours
Just supporting julia syntax for round-tripping and the current syntax for pretty printing would be fine by me. It seems straightforward and explicit.
Continuing some conversation from #214
Solutions I can think of for this are to just parse whitespace as * in uparse leaving show as-is
Currently uparse just uses the Julia parser itself so somebody would have to implement a small parser. That might be fine though.
If we wanted to support a more general syntax, some research I did a while ago in https://github.com/PainterQubits/Unitful.jl/issues/214#issuecomment-572355866, seems relevant. Here's some links to existing prior art for unit string representations:
- The NIST SP811 is influential but doesn't specify a precise grammar for unit strings.
- The FITS standard is well developed but "overcomplete" allowing flexible parsing of various non-unique representations of a unit string. It's the standard followed in the astropy.units library and seems to have inspired various other standards and proto-standards such as ASDF which defers to FITS.
- The MIXF standard seems to be an elaborated version of SP811 for plain text unit strings provides a formal grammar. This seems promising but is rather opinionated about using
.as multiplication which means incompatibility with julia syntax. - The NetCDF format appears to use the udunits package which has a unit parser with a grammar also derived from SP811 with an extension for affine units.
- The python pint library seems to use python syntax for unit string constructions
This feature is badly wanted! See my comment in https://github.com/PainterQubits/Unitful.jl/issues/412#issuecomment-770627061.
It shouldn't be too hard to write if you want to have a go at it. I haven't had time yet as this is more something I want to work theoretically than something I need immediately.
@sostock @rafaqz @c42f I am working on this problem (cf. #412, #569). My implementation is based on this proposal, https://github.com/PainterQubits/Unitful.jl/issues/214#issuecomment-714911511 One example is here. Is my approach correct?
function print(io::IO, x::Units) # swaped old show(io::IO, x::Unitlike)
is_first =true
sep = " "
foreach(sortexp(x)) do y
is_first || print(io, sep)
showrep(io,y)
is_first = false
end
end
show(io::IO, mime::MIME"text/plain", x::Units) = print(io, x) # for REPL
function show(io::IO, x::Units) # for default, parsable
sep = "*"
is_first = true
foreach(sortexp(x)) do y
p = power(y)
pow = p == 1//1 ? "" :
p.den == 1 ? string("^", p.num) :
p == p.num/p.den ? string("^", "(", p.num, "/" , p.den, ")") :
string("^", "(", p.num, "//", p.den, ")")
is_first || print(io, sep)
print(io, prefix(y))
print(io, usym(y))
print(io, pow)
is_first = false
end
end
(The content of show(io::IO, x::Units) method is the same as the one in UnitfulParsableString.jl)