I’m writing some code for the first time dealing with promotion in julia.
Specifically I’m trying to defining some promotion rules for Bio.jl, first a bit of background:
BioJulia defines the following alphabet types:
"""
Alphabet of biological characters.
"""
abstract Alphabet
"""
DNA nucleotide alphabet.
"""
immutable DNAAlphabet{n} <: Alphabet end
"""
RNA nucleotide alphabet.
"""
immutable RNAAlphabet{n} <: Alphabet end
I defined the rules like so:
for alph in (DNAAlphabet, RNAAlphabet)
@eval function Base.promote_rule{A<:$alph,B<:$alph}(::Type{A}, ::Type{B})
return $alph{max(bitsof(A),bitsof(B))}
end
end
So when you have two of the same alphabet (e.g. DNAAlphabet), but with different n
, then promote_rule
will return the alphabet with the higher n
e.g. promote_rule(DNAAlphabet{4}, DNAAlphabet{2}) == DNAAlphabet{4}
This is because DNAAlphabet{4}
is a larger alphabet containing all the elements of the smaller DNAAlphabet{2}
.
So I then define a promote rule for the sequences that use those alphabets:
for alph in (DNAAlphabet, RNAAlphabet)
@eval function Base.promote_rule{A<:$alph,B<:$alph}(::Type{BioSequence{A}}, ::Type{BioSequence{B}})
return BioSequence{promote_rule(A,B)}
end
end
a = BioSequence{DNAAlphabet{2}}("aaaaa")
b = BioSequence{DNAAlphabet{4}}("aaaaa")
c = BioSequence{RNAAlphabet{2}}("aaaaa")
d = BioSequence{RNAAlphabet{4}}("aaaaa")
Now, using promotion works:
julia> typeof(promote(a, b))
Tuple{Bio.Seq.BioSequence{Bio.Seq.DNAAlphabet{4}},Bio.Seq.BioSequence{Bio.Seq.DNAAlphabet{4}}}
julia> typeof(promote(c, d))
Tuple{Bio.Seq.BioSequence{Bio.Seq.RNAAlphabet{4}},Bio.Seq.BioSequence{Bio.Seq.RNAAlphabet{4}}}
If there isn’t a promote_rule for the combination of alphabets, promote does no conversion:
julia> typeof(promote(a, d))
Tuple{Bio.Seq.BioSequence{Bio.Seq.DNAAlphabet{2}},Bio.Seq.BioSequence{Bio.Seq.RNAAlphabet{4}}}
Actually in BioJulia you can convert a BioSequence{RNAAlphabet} to a BioSequence{DNAAlphabet}, but it should be a conscious choice and deliberate action to do so, and it should not just be done by a function implicitly through promotion.
So, what is the best thing to do? Does I leave this behaviour as is - where promote
doesn’t do any conversion in this case?
Or should some rules be added to do some kind of throw ~“Something’s trying to promote a DNA sequence into an RNA one”?
I assume one can make throws happen during promote
for certain argument types as the docs for promote say:
Promotion to a common “greater” type is performed in Julia by the promote function, which takes any number of arguments, and returns a tuple of the same number of values, converted to a common type, or throws an exception if promotion is not possible.
Thanks,
Ben.