How can I define functions inside of functions in a performant way?

I want to define functions f1 and f2 (to be inputted inside a struct S) from another function f, defined at global scope, using another auxiliary function fun:

mutable struct S
    f1::Function
    f2::Function
end

function fun(f)
    f1 = f
    f2 = x -> 2 * f1(x)
    # or function f2(x); 2 * f1(x); end
    S(f1, f2)
end

f(x) = x
s = fun(f)

Now, this works:

typeof(s.f1)
> typeof(f)

However,

typeof(s.f2)
> var"#f2#1"{typeof(f)}

which I guess will lead to performance and time losses along the line. Is there a better way to do it?

1 Like

Note that getting f1 or f2 from S will be type unstable. You might want

mutable struct S{F1, F2}
    f1::F1
    f2::F2
end

Yes, of course, I always forget to mention that I already do that when I write MWEs. A better representation of my problem would then be:

mutable struct S{f1_T, f2_T}
    f1::f1_T
    f2::f2_T
end

function fun(f)
    f1 = f
    f2 = x -> 2 * f1(x)
    # or function f2(x); 2 * f1(x); end
    S(f1, f2)
end

f(x) = x
s = fun(f)

typeof(s.f1)
> typeof(f)

typeof(s.f2)
> var"#f2#1"{typeof(f)}
1 Like

Maybe there is a misconception here. var"#f2#1"{typeof(f)} isn’t any worse than typeof(f), it’s just that’s an anonymous function so there are no better ways of representing it in the REPL.

Also, did you know you can define one-line functions like

f2(x) = 2 * f1(x)

? :slightly_smiling_face:

2 Likes

I see.

Actually, yes, but I had an issue (on julia v1.0) that prevented me to use that form, hence my example. However, I’m not able to reproduce that issue now (neither in v1.6 nor in v1.0) so I guess that’s sorted.

A follow-up question is: is this a good design pattern (in terms of performances) to do this kind of things? To be absolutely clear, this is the test case I have in mind:

module M
    mutable struct S{f1_T, f2_T}
        f1::f1_T
        f2::f2_T
    end

    function fun(f)
        f1 = f
        f2(x) = 2 * f1(x)
        S(f1, f2)
    end

    export S, fun
end

using .M

f(x) = x
s = fun(f)

typeof(s.f1)
typeof(s.f2)

I tried instead to define f1 and f2 as stubs outside fun and then overload them with new methods using fun, but that’s of course just worse.

I think that making the struct mutable does not make sense, because each function has its own type. You won’t be able to replace the function by another one (I think, can’t check now).

Concerning the performance, it is hard to tell, it depends on what you will be doing with such structure.

That’s very true; I didn’t think it through.

The idea is to take a function f and use fun to compute its derivatives (say, first and second ones, with ForwardDiff and/or FiniteDifferences), saving the results into f1 and f2.

For that the data structure is not important. The point is if you are planing to have functions that have this structure as a parameter, and if the structure changes frequently (thus begin type unstable) in your code.

If you using the structure just to store two functions (coming from wherever they come from) and then the expensive computation is done inside these functions (f1 and f2), how you stored them will not affect performance.

That’s it. Thanks!