# Promote failed to change any arguments

**URL:** https://discourse.julialang.org/t/promote-failed-to-change-any-arguments/31361
**Category:** New to Julia
**Created:** [November 21, 2019, 11:25pm UTC](https://discourse.julialang.org/t/promote-failed-to-change-any-arguments/31361 "2019-11-21T23:25:14Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![venuur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/venuur/32/6493_2.png) [@venuur](https://discourse.julialang.org/u/venuur)
#### Post date: [November 21, 2019, 11:25pm UTC](https://discourse.julialang.org/t/promote-failed-to-change-any-arguments/31361/1 "2019-11-21T23:25:14Z")

</div>

I am having trouble figuring out how to implement promotions for a type. The main idea is the create a class that tracks operations applied to a variable type. This is perhaps not so different from Flux, but I wanted to try implementing it from first principles before I try using a library. However, I cannot make this `promote_rule` work to allow the two types to operate together:

```julia
abstract type RV end

struct ArrayRV <: RV
    variates
end

struct NExpr{N}
    rvs::NTuple{N, RV}
    f
end

apply(f, rvs::RV...) = NExpr(rvs, f)

Base.convert(::Type{NExpr}, x::RV) = apply(x -> x, x)
Base.promote_rule(::Type{NExpr{N}}, ::Type{RV}) where N = NExpr{N}

x = ArrayRV([1, 2, 3])
y = apply(x -> 2*x, x)
promote(x, y)

```

Produces the following error:

```julia
julia> promote(x,y)
ERROR: promotion of types ArrayRV and NExpr{1} failed to change any arguments
Stacktrace:
 [1] sametype_error(::Tuple{ArrayRV,NExpr{1}}) at .\promotion.jl:308
 [2] not_sametype(::Tuple{ArrayRV,NExpr{1}}, ::Tuple{ArrayRV,NExpr{1}}) at .\promotion.jl:302
 [3] promote(::ArrayRV, ::NExpr{1}) at .\promotion.jl:285
 [4] top-level scope at none:0

```

The docs show some examples for Rational, but I must have missed something. Where should I look next?

[https://docs.julialang.org/en/v1/manual/conversion-and-promotion/](https://docs.julialang.org/en/v1/manual/conversion-and-promotion/)

---

<div class="post-metadata">

### Author: ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)
#### Post date: [November 21, 2019, 11:44pm UTC](https://discourse.julialang.org/t/promote-failed-to-change-any-arguments/31361/2 "2019-11-21T23:44:50Z")

</div>

Julia’s promotion machinery works only for subtypes of `Number`.

What are you trying to do?

---

<div class="post-metadata">

### Author: ![venuur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/venuur/32/6493_2.png) [@venuur](https://discourse.julialang.org/u/venuur)
#### Post date: [November 22, 2019, 12:08am UTC](https://discourse.julialang.org/t/promote-failed-to-change-any-arguments/31361/3 "2019-11-22T00:08:30Z")

</div>

I see. Then here’s the more thorough explanation. I want to create a random variable type. The idea is that applying operators to the random variable type creates expressions which can be sampled from using Monte Carlo simulation. Essentially I’d like to be able to replace numerical variables in a formula and easily create Monte Carlo simulations from standard formulas.

I hadn’t thought to subtype Number, although maybe that’s appropriate. I want to treat them like numbers in most cases. Would that be a reasonable route to go?

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [November 22, 2019, 9:37am UTC](https://discourse.julialang.org/t/promote-failed-to-change-any-arguments/31361/4 "2019-11-22T09:37:58Z")

</div>

Regarding the original question: you should just extend the definitions to allow subtypes (since the methods are called with a concrete type):

```julia
Base.convert(::Type{<:NExpr}, x::RV) = apply(x -> x, x)
Base.promote_rule(::Type{NExpr{N}}, ::Type{<:RV}) where N = NExpr{N}

```

This now works with your example.

> [@dpsanders](#):
>
> Julia’s promotion machinery works only for subtypes of `Number` .

I am not sure why you say this, the code is generic.

> [@venuur](#):
>
> I hadn’t thought to subtype Number, although maybe that’s appropriate. I want to treat them like numbers in most cases. Would that be a reasonable route to go?

I would not subtype `Number`; just define the operations you want to perform. The promotion machinery _can_ help with that, but that’s just a convenience feature to organize your code.

---

<div class="post-metadata">

### Author: ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)
#### Post date: [November 22, 2019, 1:55pm UTC](https://discourse.julialang.org/t/promote-failed-to-change-any-arguments/31361/5 "2019-11-22T13:55:56Z")

</div>

Yeah–promotion works with any types, not just subtypes of `Number`, but it can be easier to use promotion and operator overloading with `Number` subtypes because Julia defines some useful methods like these:

```julia
+(x::Number, y::Number) = +(promote(x,y)...)
*(x::Number, y::Number) = *(promote(x,y)...)
-(x::Number, y::Number) = -(promote(x,y)...)
/(x::Number, y::Number) = /(promote(x,y)...)

```

[source](https://github.com/JuliaLang/julia/blob/e706e83eea9057f6ee910cf9ca006c6c4484d643/base/promotion.jl#L311-L314)

You can define those same operations for any type you create, although subtyping `Number` can save you some work because of convenience methods like those.

---

<div class="post-metadata">

### Author: ![venuur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/venuur/32/6493_2.png) [@venuur](https://discourse.julialang.org/u/venuur)
#### Post date: [November 22, 2019, 2:54pm UTC](https://discourse.julialang.org/t/promote-failed-to-change-any-arguments/31361/6 "2019-11-22T14:54:19Z")

</div>

Thanks @Tamas_Papp, I definitely forgot about using subtypes.

Since most of the operators are just straight forward to wrap in my modules `apply` function, I was originally planning to just have a for-loop that iterates over the standard operators and use `@eval` to create the default definitions.

I figure as I work through some specific scenarios I may decide that certain operations can benefit from special handling. For now I’m mostly trying to setup a minimal API to see if it feels right.
