Where to put general conversion methods?

I am writing a type that has an obvious canonical binary representation which it can be converted to and from losslessly. Should I define methods on convert, or constructors? Both? Something else entirely? convert gives the nicer error message if the method doesn’t exist, but constructors allow easier-to-read piping. There’s precedent for both in the standard library, with no obvious pattern besides what’s documented in convert’s docs, which only covers what the difference should be if both exist and the type is numeric.

1 Like

Defining conversions using convert is more than reasonable. Use them within constructors to wrap the explicit conversions.

1 Like

In my opinion, you should generally only define convert methods if you want automatic conversions to work for your type, like this:

struct Suit
    id::UInt8

    function Suit(name::String)
        if name == "heart"
            new(0)
        elseif name == "diamond"
            new(1)
        elseif name == "club"
            new(2)
        elseif name == "spade"
            new(3)
        else
            throw(ArgumentError("Invalid suit name."))
        end
    end
end

Base.convert(::Type{UInt8}, s::Suit) = s.id
julia> push!(UInt8[], Suit("heart"))
1-element Vector{UInt8}:
 0x00

(And for the particular example I used here, automatic conversion doesn’t seem to make a whole lot of sense.)

3 Likes