Functions in function

I have 2 functions:

f1(a1; a2=1, a3="a") # a4, a5, ...
f2(b1; b2='k', b3=2.0) # b4, b5, ...

I want to write a function which includes both functions and accepts all parameters of functions. What is the best way to do this? Do I have to write all the arguments of f1 and f2 in the function?
Thank you

Something like that?

function outerfunc(a1, a2, a3, b1, b2, b3)
      function f1(a1, a2 = a2, a3 = "a") 
            # a4 a5, ....
      end 

      function f2(b1, b2 = b2, b3 = b3) 
            # b4, b5, ....
      end 
 
      # possibly 
      # ... = f1(a1, a2 = a2, a3 = a3)
      # ... = f2(b1, b2 = b2, b3 = b3)
end

f1 and f2 are defined outside.
Inside outerfunc I call f1 and f2.
I want outsidefunc accept parameters for f1 and f2

Does you outer function take function names as arguments or the names of the functions are exactly defined at runtime, e.g. f1 and f2?

f1(a1; a2=1, a3="a") # a4, a5, ...
f2(b1; b2='k', b3=2.0) # b4, b5, ...

function f(x, y, z, a1, a2, a3, b1, b2, b3)
    # code
    f1(a1, a2=a2, a3=a3) 
    # code
    f2(b1, b2=b2, b3=b3)
    #code
end

It doesn’t look elegant and doesn’t scale if there are many functions.
Is there a way to take parameters for functions f1, f2 without explicitly writing them in f?

1 Like

maybe you can use three-dots like

function f(params...)
end

and set all of the arguments of f1 and f2 as optional.

f1 and f2 are in a Pkg. I didn’t write them.
I have to call them in a function but I want this function to accept the parameters for f1 and f2 as well.

1 Like

you can always wrap foreign functions

Can you give me an example?

I’d like to do something like this:

function f(x, y, z, a1, b1; params...)
    # code
    f1(a1; params...) 
    # code
    f2(b1; params...)
    #code
end

and functions choose only parameters that are compatible.

1 Like

That works fine if f1 and f2 are defined as

f1(a1; a2=1, a3="a", _...) # a4, a5, ...
f2(b1; b2='k', b3=2.0, _...) # b4, b5, ...

If they are defined outside your control your best bet is probably to write wrapper functions which slurp the unused keyword arguments.

1 Like

This works:

# examples
f1(a1; a2=1, a3="a") = (a1, a2, a3)
f2(b1; b2='k', b3=2.0) = (b1, b2, b3) 

function namedArgumentsOf(func, args...)
    func_args = @which func(args...)
    Base.kwarg_decl(func_args)
end 

function f(a1, b1; params...)
    args_f1 = [i for i in params if i[1] in namedArgumentsOf(f1, 1)]
    args_f2 = [i for i in params if i[1] in namedArgumentsOf(f2, 1)]

    f1(a1; args_f1...) |> println
    f2(b1; args_f2...) |> println
    
end

f(3, 5; a2=4, a3=7, b2='e')

Nice!

A tiny detail for multiple dispatch to work, probably is should be namedArgumentsOf(f1, a1) (and similar for f2) to ensure that it uses the right method depending on the type of a1.

2 Likes

I would perhaps try

function f(x, y, z, a1, b1, tup1, tup2)
    f1(a1; tup1...) 
    f2(b1; tup2...)
end

f(x, y, a1, b1, (a2=4, a3=7), (b2='e', b3=11))
1 Like

I like your solution. My final code is:

f1(a1; a2=1, a3="a") = (a1, a2, a3)
f2(b1; b2='k', b3=2.0) = (b1, b2, b3) 
function f(a1, b1; args_f1=(), args_f2=())
    f1(a1; args_f1...) |> println
    f2(b1; args_f2...) |> println    
end

f(3, 5; args_f1=(a2=4, a3=7), args_f2=(b3='e',)) 
f(3, 5; args_f1=(a2=4, a3=7))
f(3, 5; args_f2=(b3='e',))
f(3, 5; args_f2=())
f(3, 5)

The only problem is:

function f(a1, b1; args_f1=(a2=3, a3="b"), args_f2=()) # If I declare args different from the default ones of f1 (or f2)
    f1(a1; args_f1...) |> println
    f2(b1; args_f2...) |> println     
end
f(1, 2; args_f1=(a2=4,)) #  I don't get a3 = "b"
f(1, 2; args_f1=(a2=4,a3="b")) # I have to write a3="b" again