# Understanding how \`promotion\` works: promote Celsius to Kelvin

**URL:** <https://discourse.julialang.org/t/understanding-how-promotion-works-promote-celsius-to-kelvin/19810>\
**Category:** New to Julia\
**Created:** [January 19, 2019, 11:42am UTC](https://discourse.julialang.org/t/understanding-how-promotion-works-promote-celsius-to-kelvin/19810 "2019-01-19T11:42:29Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![xiaodai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xiaodai/32/15937_2.png) [@xiaodai](https://discourse.julialang.org/u/xiaodai)\
**Post date:** [January 19, 2019, 11:42am UTC](https://discourse.julialang.org/t/understanding-how-promotion-works-promote-celsius-to-kelvin/19810/1 "2019-01-19T11:42:30Z")

</div>

I am trying to follow [this blog](https://medium.com/@Jernfrost/defining-custom-units-in-julia-and-python-513c34a4c971) which shows how to create a unit conversion code.

I have tried to define two temperate types `Celsius` and `Kelvin` and I define a promotion rule where `Celsius` get promoted to `Kelvin`. I also defined the conversion functions both way

```julia
abstract type Temperature end

struct Celsius <: Temperature
    value::Float64
end

struct Kelvin <: Temperature
   value::Float64
end

promote_rule(::Type{Kelvin}, ::Type{Celsius}) = Kelvin

convert(::Type{Kelvin}, t::Celsius) = Kelvin(t.value + 273.15)
convert(::Type{Celsius}, t::Kelvin) = Celsius(t.value - 273.15)

```

However, when I run

```julia
promote(Kelvin(1), Celsius(1))

```

I get the following error, what did I do wrong? Shouldn’t `promote` promote the second argument which is of type `Celsius` to `Kelvin`?

> ERROR: promotion of types Kelvin and Celsius failed to change any arguments  
> Stacktrace:  
> [1] error(::String, ::String, ::String) at .\error.jl:42  
> [2] sametype\_error(::Tuple{Kelvin,Celsius}) at .\promotion.jl:308  
> [3] not\_sametype(::Tuple{Kelvin,Celsius}, ::Tuple{Kelvin,Celsius}) at .\promotion.jl:302  
> [4] promote(::Kelvin, ::Celsius) at .\promotion.jl:285  
> [5] top-level scope at none:0

---

<div class="post-metadata">

**Author:** ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)\
**Post date:** [January 19, 2019, 11:50am UTC](https://discourse.julialang.org/t/understanding-how-promotion-works-promote-celsius-to-kelvin/19810/2 "2019-01-19T11:50:49Z")

</div>

You need `Base.X` if you want to define `X` for your custom type. Or do `import Base: X` first. It works with me when I do that.

---

<div class="post-metadata">

**Author:** ![xiaodai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xiaodai/32/15937_2.png) [@xiaodai](https://discourse.julialang.org/u/xiaodai)\
**Post date:** [January 19, 2019, 11:52am UTC](https://discourse.julialang.org/t/understanding-how-promotion-works-promote-celsius-to-kelvin/19810/3 "2019-01-19T11:52:38Z")

</div>

I see. So adding the below works

```julia
import Base: promote_rule, convert

```

---

<div class="post-metadata">

**Author:** ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)\
**Post date:** [January 19, 2019, 12:57pm UTC](https://discourse.julialang.org/t/understanding-how-promotion-works-promote-celsius-to-kelvin/19810/4 "2019-01-19T12:57:15Z")

</div>

> [@xiaodai](#):
>
> I see. So adding the below works
> 
> ```julia
> import Base: promote_rule, convert
> 
> ```

Yes. You can do

```julia
Base.convert(blah... )

```

or

```julia
import Base: convert
convert(blah....)

```

Both are used. After reading and writing these things a few times, I still don’t know which is preferable. But, sometimes the details bear on the choice. In the case of `convert`, it’s not unreasonable that a package would have a `convert` function that is semantically unrelated to `Base.convert`. In this case, writing `Base.convert` might reduce cognitive load a bit when reading the code.

Also, I can never remember how to use parens and quoting to write something like `Base.==(x, y) ...` Out of frustration, I often do `import Base: ==`.
