This particular way of doing it is not a good idea since it generates type unstable code:
julia> @code_typed fx(1)(1)
CodeInfo(
1 ─ %1 = (Core.getfield)(#self#, :a)::Box
│ %2 = (Core.isdefined)(%1, :contents)::Bool
└── goto #3 if not %2
2 ─ goto #4
3 ─ $(Expr(:throw_undef_if_not, :a, false))::Any
4 ┄ %6 = (Core.getfield)(%1, :contents)::Any
│ %7 = (%6 * x)::Any
└── return %7
) => Any
Compare to @rdeits suggestion:
julia> @code_typed fx(1)(1)
CodeInfo(
1 ─ %1 = (Base.mul_int)(2, x)::Int64
└── return %1
) => Int64
However, that code may suffer from similar issues if either the input n
is not compile time known:
julia> fxwrapped(x) = fx(x)(x);
julia> fxwrapped(2)
6
julia> @code_typed fxwrapped(3)
CodeInfo(
1 ─ %1 = (x === 1)::Bool
└── goto #3 if not %1
2 ─ %3 = %new(Main.:(##133#135))::##133#135
└── goto #4
3 ─ %5 = %new(Main.:(##134#136))::##134#136
4 ┄ %6 = φ (#2 => %3, #3 => %5)::Union{##133#135, ##134#136}
└── goto #5
5 ─ %8 = (%6)(x)::Any
└── return %8
) => Any
Or if f
is subsequently used:
function fx2(n)
if n == 1
f = x -> 2x
else
f = x -> 3x
end
x -> f(2x)
end
Problem:
julia> fx2(1)(1)
4
julia> @code_typed fx2(1)(1)
CodeInfo(
1 ─ %1 = (Core.getfield)(#self#, :f)::Box
│ %2 = (Core.isdefined)(%1, :contents)::Bool
└── goto #3 if not %2
2 ─ goto #4
3 ─ $(Expr(:throw_undef_if_not, :f, false))::Any
4 ┄ %6 = (Core.getfield)(%1, :contents)::Any
│ %7 = (Base.mul_int)(2, x)::Int64
│ %8 = (%6)(%7)::Any
└── return %8
) => Any
A workaround for both issues is to have a single definition of f
, and also ensure that there’s no uncertainty of existence of variables:
function fx3(n)
a = ifelse(n == 1, 2, 3)
f(x) = a*x
return x -> f(2x)
end
fx3wrapped(x) = fx3(x)(x)
Type stability ensues:
julia> @code_typed fx3(2)(1)
CodeInfo(
1 ─ %1 = (Core.getfield)(#self#, :f)::#f#160{Int64}
│ %2 = (Base.mul_int)(2, x)::Int64
│ %3 = (Core.getfield)(%1, :a)::Int64
│ %4 = (Base.mul_int)(%3, %2)::Int64
└── return %4
) => Int64
julia> @code_typed fx3wrapped(2)
CodeInfo(
1 ─ %1 = (x === 1)::Bool
│ %2 = (Main.ifelse)(%1, 2, 3)::Int64
│ %3 = (Base.mul_int)(2, x)::Int64
│ %4 = (Base.mul_int)(%2, %3)::Int64
└── return %4
) => Int64