JuliaData / StructTypes.jl

Abstract definitions and convenience methods for describing, processing, and constructing Julia objects
https://juliadata.github.io/StructTypes.jl/stable/
MIT License
80 stars 22 forks source link

using CustomStruct lowering for AbstractType #58

Closed stonepreston closed 3 years ago

stonepreston commented 3 years ago

Hello. I'm very new to julia and am trying to use your package in conjunction with JSON3 to do some serialization of an abstract type. Originally I used JSON.jl but stumbled across this package which has the very cool feature of being able to write json to a Type so I am trying to switch over to JSON3.

With JSON.jl, I could specify a lowering function on an abstract type (in this case I am taking in an abstract type and wrapping it in a simple wrapper type called System:

struct System 
    parameters::Vector{Parameter}
    states::Vector{String}
    equations::Vector{String}
    connections::Vector{String}
end

JSON.lower(system::ModelingToolkit.AbstractSystem) = System(
    build_parameters(system),
    string.(states(system)),
    string.(equations(system)),
    get_connections(system)
)

That works fine and nothing else is needed.

With JSON3 however I found that in addition to registering the abstract type as a custom struct, I also have to register the sub types:

StructTypes.StructType(::Type{System}) = StructTypes.Struct()
StructTypes.StructType(::Type{ModelingToolkit.AbstractSystem}) = StructTypes.CustomStruct()
StructTypes.StructType(::Type{ModelingToolkit.ODESystem}) = StructTypes.CustomStruct()

StructTypes.lower(system::ModelingToolkit.AbstractSystem) = System(
    build_parameters(system),
    string.(states(system)),
    string.(equations(system)),
    get_connections(system)
)

if the system passed in to lower is of type ODESystem (or any other subtype of AbstractSystem) then I have to provide that CustomStruct type mapping for that. Is that normal? Am I doing something wrong?

quinnj commented 3 years ago

In order to signal than any subtype of AbstractSystem should be CustomStruct, you just need to change your definition to:

StructTypes.StructType(::Type{<:ModelingToolkit.AbstractSystem}) = StructTypes.CustomStruct()

alternatively, and perhaps more clear, you could define it as:

StructTypes.StructType(::Type{T}) where {T <: ModelingToolkit.AbstractSystem} = StructTypes.CustomStruct()

they both mean the same thing, but essentially you're doing a lower-bound constraint on ModelingToolkit.AbstractSystem and saying, "any type that is ModelingToolkit.AbstractSystem or lower". In your original definition, the method only matched when the ModelingToolkit.AbstractSystem abstract type itself was passed in, but not its subtypes.

Hope that helps.

stonepreston commented 3 years ago

That did it! Thanks so much