Type Conversion and Custom Parsing
If you find from_dict or from_toml doesn't not support a Julia type, such as Symbol, this is usually because the corresponding parser or format doesn't support this Julia type natively, in this case you will need to define your own type conversion for this option type by overloading Configurations.from_dict
How does it work?
The type conversion for option types work as following:
- if we find the target type does not match the value type, we will call
Configurations.from_dict - if
Configurations.from_dictis not overloaded, it will try to callBase.convert - if
Base.convertdoesn't work, a standard conversion failure error will be thrown byBase.convert.
Thus, if Base.convert is already overloaded, this will just work, or if the conversion rule is contextual based on the option type, one can also overload Configurations.from_dict, this also avoids potential type piracy.
For serialization, one can overload Configurations.to_dict, this
The Overloading Interface
from_dict provides two overloading interface
Configurations.from_dict — Methodfrom_dict(::Type{OptionType}, ::OptionField{f_name}, ::Type{T}, x) where {OptionType, f_name, T}For option type OptionType, convert the object x to the field type T and assign it to the field f_name. Raise FieldTypeConversionErrors errors if Base.convert raises exception
ERROR: MethodError: Cannot `convert` an object of type ...Configurations.from_dict — Methodfrom_dict(::Type{OptionType}, ::Type{T}, x) where {OptionType, T}For option type OptionType, convert the object x to type T. This is similar to Base.convert(::Type{T}, x) and will fallback to Base.convert if not defined.
Configurations.to_dict — Methodto_dict(::Type{T}, x, option::ToDictOption) where TConvert x when x is inside an option type T. option is a set of options to determine the conversion behaviour. this can be overloaded to change the behaviour of to_dict(x; kw...).
to_dict(::Type{T}, x) where TOne can also use the 2-arg version when x is not or does not contain an option type for convenience.
Example
The following is a builtin overload to handle list of options.
function Configurations.to_dict(::Type{T}, x::Vector, option::ToDictOption) where T
if is_option(eltype(x))
return map(p->to_dict(T, p, include_defaults), x)
else
return x
end
endThe following overloads the 2-arg to_dict to convert all VersionNumber to a String for all kinds of option types.
Configurations.to_dict(::Type, x::VersionNumber) = string(x)Example: Contextual Conversion
julia> using Configurationsjulia> @option struct MyOption a::Int b::Symbol end
directly calling from_dict will have the following error
julia> @option struct MyOption a::Int b::Symbol endjulia> d = Dict{String, Any}( "a" => 1, "b" => "ccc" )Dict{String, Any} with 2 entries: "b" => "ccc" "a" => 1julia> from_dict(MyOption, d)ERROR: FieldTypeConversionError: conversion from String to type Symbol for field b in type Main.MyOption failed
now if we define the following type conversion
julia> Configurations.from_dict(::Type{MyOption}, ::Type{Symbol}, s) = Symbol(s)
it will just work
julia> from_dict(MyOption, d)Main.MyOption(1, :ccc)