# 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:

1. if we find the target type does not match the value type, we will call Configurations.from_dict
2. if Configurations.from_dict is not overloaded, it will try to call Base.convert
3. if Base.convert doesn't work, a standard conversion failure error will be thrown by Base.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

from_dict provides two overloading interface

Configurations.from_dictMethod
from_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 ...
source
Configurations.from_dictMethod
from_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.

source
Configurations.to_dictMethod
to_dict(::Type{T}, x, option::ToDictOption) where T

Convert 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 T

One 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
end

The 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)
source

## 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)