/Convertible.jl

Multi-step convert for Julia types

Primary LanguageJuliaOtherNOASSERTION

Convertible

Multi-step convert for Julia types.

Build Status Coverage Status codecov.io

This package provides the isconvertible trait that can be applied to struct type definitions via the @convertible macro. Types that share this trait can be easily converted into one another with a single call to Base.convert even though multiple intermediate conversions might be required.

Installation

The package can be installed through Julia's package manager:

Pkg.add("Convertible")

Usage

Define convertible types:

# For Julia 0.5:
# @convertible immutable/type A
@convertible struct A
    val::Int
end

@convertible struct B
    val::Int
end

@convertible struct C
    val::Int
end

@convertible struct D
    val::Int
end

Define Base.convert methods:

Base.convert(::Type{B}, a::A) = B(a.val+1)
Base.convert(::Type{D}, a::A) = B(a.val+1)
Base.convert(::Type{C}, b::B) = C(b.val+1)
Base.convert(::Type{A}, c::C) = A(c.val-2)

Type A can now be converted to type C directly even though there is no direct convert(::Type{C}, ::A) available.

julia> a = A(1)
julia> @convert convert(C, a)
C(3)

Internally Convertible.jl will compute the shortest conversion path and emit a specialized method based on a generated function, e.g. convert(C, convert(B, a)) in this case.

As shown above, you need to opt-in to the new convert behaviour by wrapping calls to convert with the @convert macro, e.g.:

@convert begin
    b = convert(B, a)
    c = convert(C, a)
    a = convert(A, b)
    d = convert(D, b)
end

Parametric Types

@convertible can only be used on non-parametric types. It can be applied to type aliases without parameters, though.

type Param{T}
    val::T
end

# The pre-v0.6 `typealias` keyword is not supported.
@convertible const ParamFloat64 = Param{Float64}
@convertible const ParamInt = Param{Int}
@convertible const ParamUInt8 = Param{UInt8}

Base.convert(::Type{ParamInt}, p::ParamFloat64) = Param{Int}(p.val)
Base.convert(::Type{ParamUInt8}, p::ParamInt) = Param{UInt8}(p.val)