invenia/JLSO.jl

Deprecate magic keyword constructor for `JLSOFile`

nickrobinson251 opened this issue · 2 comments

The currently have a keyword-only JLSOFile constructor which transforms keyword arguments into key => value objects to be serialised...

JLSO.jl/src/JLSOFile.jl

Lines 70 to 79 in dbf7be6

function JLSOFile(;
version=v"4",
julia=VERSION,
format=:julia_serialize,
compression=:gzip,
image=_image(),
kwargs...
)
return JLSOFile(
Dict(kwargs);

...but this is a bit magic, because it fails (or behaves differently) for certain "magic" words (julia, version):

julia> jlso = JLSOFile(x=1)
JLSOFile([x]; version="4.0.0", julia="1.6.0", format=:julia_serialize, compression=:gzip, image="")

julia> haskey(jlso.objects, :x)
true

julia> jlso = JLSOFile(x=1, image="y.png")
JLSOFile([x]; version="4.0.0", julia="1.6.0", format=:julia_serialize, compression=:gzip, image="y.png")

julia> haskey(jlso.objects, :image)  # surprising
false

julia> jlso = JLSOFile(x=1, image=rand(2,2))  # surprising
ERROR: MethodError: Cannot `convert` an object of type Matrix{Float64} to an object of type String

It also means we can't add new keywords in a non-breaking way, since this method already has different behaviour for any keyword that's not already in the "magic" set.

We already have a :key => value pair constructor which seems plenty convenient and more intuitive (no magic):

JLSOFile(data::Pair{Symbol}...; kwargs...) = JLSOFile(Dict(data); kwargs...)

So i think the magic-keywords constructor can be deprecated to this easily enough, e.g. and have

julia> JLSOFile(:x => 1, :image => rand(2,2))
JLSOFile([image, x]; version="4.0.0", julia="1.6.0", format=:julia_serialize, compression=:gzip, image="")

We should keep the no-args, keywords constructor JLSOFile() or JLSOFile(; kwargs...) (accpeting only the named kwargs, julia, version, image etc.) for creating an empty JLSOFile (i.e. a jlso::JLSOFile with isempty(jlso.objects))

Mentioned in #108 (comment)

I have suggested that Checkpoints.jl's checkpoint function should do the opposite that function is both similar and different. invenia/Checkpoints.jl#16

i don't use Checkpoints.jl and don't know anything about the internals, so won't comment on that. My objections here are "it fails (or behaves differently) for certain magic keywords" and "we can't add new keywords in a non-breaking way", so perhaps you can see if those objection apply in the Checkpoints case and if there's a strong enough counter-case. Here i think having only the pairs constructor is preferable to the current situation.