I am writing a code in which the input file is a Julia script, and the user may provide some input in the form of functions (of one or several variables).

The code may use these functions by calling them with `Float64`

, or with other datatypes. I have automatic differentiation in mind, but for this MWE, let us say it’s `Int64`

vs. `Float64`

.

Now, most input functions would use all their inputs

`f = (x,y) -> x^2+y`

but the user may say “Oh the input parameters do not really matter”

`g = (x,y) -> 1`

This causes me two types of problems

**a)** If I call an input function with two `Float64`

, two `Int64`

, or with an `Int64`

and a `Float64`

. I need to rely on the output being `promote_type(typeof(x),typeof(y))`

, that is, `Float64`

.

Without countermeasures, calling `g`

would wreak havoc in my dispatching logic further down the line. That issue, I can solve:

```
promote_eltype(v...) = promote_type(eltype.(v)...)
convert_eltype(a,v...) = convert(promote_eltype(a,v...),a)
typestable(f,x...) = convert_eltype(f(x...),x...)::promote_eltype(x)
F(x...) = typestable(g,x...)
G(x...) = typestable(f,x...)
```

So if I use `F`

and `G`

in place of `f`

and `g`

, my software does the computations I want.

**b)** *But* it does it slowly. Behold:

```
> @code_warntype typestable(f,3,2.)
Variables:
#self#::#typestable
f::##49#50
x::Tuple{Int64,Float64}
Body:
begin
SSAValue(0) = (Core.getfield)(x::Tuple{Int64,Float64}, 1)::Int64
return (Base.add_float)((Base.sitofp)(Float64, (Base.mul_int)(SSAValue(0), SSAValue(0))::Int64)::Float64, (Core.getfield)(x::Tuple{Int64,Float64}, 2)::Float64)::Float64
end::Float64
> @code_warntype F(3,2.)
Variables:
#self#::#F
x::Tuple{Int64,Float64}
Body:
begin
SSAValue(1) = Main.g
SSAValue(3) = (Core.getfield)(x::Tuple{Int64,Float64}, 1)::Int64
SSAValue(4) = (Core.getfield)(x::Tuple{Int64,Float64}, 2)::Float64
$(Expr(:inbounds, false))
# meta: location untitled-33e486cf08c224e1e95c30ab1d254fb4 typestable 8
SSAValue(2) = (SSAValue(1))(SSAValue(3), SSAValue(4))::ANY
# meta: pop location
$(Expr(:inbounds, :pop))
return (Core.typeassert)((Main.convert_eltype)(SSAValue(2), SSAValue(3), SSAValue(4))::ANY, $(QuoteNode(Real)))::REAL
end::REAL
```

So while calling “typestable” gives me, well, typestable code, any attempt at a syntactic sugar wrap makes me lose type stability.

I can live without the syntactic sugar, but if the implication is that typestability is not “exported by a function” then I am in CPU-trouble, and worse, I do not understand the logic of it all.

What is going on here, why are F and G not typestable, when they return a value that is stamped for type?