# Promotion rules - what about when you can't promote?

#1

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.

#2

This seems fine to me. Unlike, say, `convert`, `promote` isn’t meant to be called by users directly, and it doesn’t have a contract that says it must return values of the same type. You can use `promote` to make the Bio.jl interface more convenient but shouldn’t assume it will have any effect.

This also happens with e.g.

``````julia> promote(1, :a)
(1, :a)
``````

#3

Ok, cool! Thanks Mike!