# Function as argument: name, symbol or string?

**URL:** https://discourse.julialang.org/t/function-as-argument-name-symbol-or-string/55926
**Category:** General Usage
**Created:** [February 24, 2021, 12:07pm UTC](https://discourse.julialang.org/t/function-as-argument-name-symbol-or-string/55926 "2021-02-24T12:07:18Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)
#### Post date: [February 24, 2021, 12:07pm UTC](https://discourse.julialang.org/t/function-as-argument-name-symbol-or-string/55926/1 "2021-02-24T12:07:18Z")

</div>

I have a function (a Machine Learning algorithm) where one of the parameters is a function (custom versions of gini, variance or entropy).

Do you advice using as parameter the name of the function, the symbol or a text string ? :

```julia
function myf(x)
    x + 1
end

# Solution 1: the function parameter is a symbol
function outerf(x,f)
    y = eval(Meta.parse("$a($x)"))
end
outerf(3,:myf)

# solution 2: the function parameter is the name/placeholder of the function
function outerf2(x,f)
    y = f(x)
end
outerf2(4,myf)

# solution 3: the function parameter is the string of the name/placeholder of the function
function outerf3(x,f)
    fsymbol = Symbol(a)
    y = eval(Meta.parse("$fsymbol($x)"))
end
outerf3(5,"myf")

```

While using directly the function name seems the simplest solution, I am concerned that the inner function may be in scope for the outer function (so that it can indeed be called), but not in the place calling the outer function. However there is a huge performance gain in calling the function directly:

```julia
@btime outerf(3,:myf) # 92.932 μs (44 allocations: 2.67 KiB)
@btime outerf2(4,myf) # 0.029 ns (0 allocations: 0 bytes)
@btime outerf3(5,"myf") # 93.474 μs (44 allocations: 2.67 KiB)

```

---

<div class="post-metadata">

### Author: ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)
#### Post date: [February 24, 2021, 12:22pm UTC](https://discourse.julialang.org/t/function-as-argument-name-symbol-or-string/55926/2 "2021-02-24T12:22:11Z")

</div>

ok, the way to go seems so use symbol, but using `getfield()` to actually call the function instead of `eval`. This is fast and flexible:

```julia
function outerf4(x,f)
    y = getfield(Main, Symbol(f))(x)
end
outerf4(6,:myf)
@btime outerf4(6,:myf) # 0.029 ns (0 allocations: 0 bytes)

```

See also [this SO thread](https://stackoverflow.com/questions/34016768/julia-invoke-a-function-by-a-given-string).

---

<div class="post-metadata">

### Author: ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)
#### Post date: [February 24, 2021, 12:35pm UTC](https://discourse.julialang.org/t/function-as-argument-name-symbol-or-string/55926/3 "2021-02-24T12:35:25Z")

</div>

You should definitely, 100%, use option 2 (unless I’m missing something of course).

It’s much clearer what’s going on, and that’s how the language is supposed to be used: If you want to pass a function as parameter, then pass the function 🙂

As the [manual](https://docs.julialang.org/en/v1/manual/functions/#man-anonymous-functions) says:

> Functions in Julia are [first-class objects](https://en.wikipedia.org/wiki/First-class_citizen): they can be assigned to variables, and called using the standard function call syntax from the variable they have been assigned to. They can be used as arguments, and they can be returned as values.

When you do `outerf2(4,myf)`, Julia will pass the function as parameter to `outer2`. Then for `outer2` it doesn’t matter in which module or scope the function was defined: it got the value so it can use it.

Example:

```julia
module A
myf(x) = 2x
outerf(f, x) = f(x)
end

module B
myf() = 3x
outerf(f, x) = f(x)
end

myf(x) = 4x

@show A.outerf(myf, 1)
@show B.outerf(myf, 1)
@show B.outerf(A.myf, 1)

```

gives

```julia
A.outerf(myf, 1) = 4
B.outerf(myf, 1) = 4
B.outerf(A.myf, 1) = 2

```

---

<div class="post-metadata">

### Author: ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)
#### Post date: [February 24, 2021, 12:59pm UTC](https://discourse.julialang.org/t/function-as-argument-name-symbol-or-string/55926/4 "2021-02-24T12:59:33Z")

</div>

Yes, but myf must be defined in the place where outerf is called.

for example, given the content of `functionTest.jl` is :

```julia

module myFTest
export outerfName, outerfSymbol

function innerf(x)
    x + 1
end
function outerfName(x,f)
    y = f(x)
end
function outerfSymbol(x,f)
    y = getfield(Main.myFTest, Symbol(f))(x)
end

end

```

Then you get :

```julia
julia> include("functionTest.jl")
Main.myFTest

julia> using .myFTest

julia> outerfName(1,innerf)
ERROR: UndefVarError: innerf not defined
Stacktrace:
 [1] top-level scope
   @ REPL[3]:1

julia> outerfSymbol(1,:innerf)
2

```

In this case the reason is that `innerf` is not exported, but in my case I am concerned on making a wrapper for my outer function for an other general package that knows nothing about the inner function, and hence using symbols seems more flexible and safe against name collisions…

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [February 24, 2021, 1:10pm UTC](https://discourse.julialang.org/t/function-as-argument-name-symbol-or-string/55926/5 "2021-02-24T13:10:41Z")

</div>

> [@sylvaticus](#):
>
> ```julia
> julia> outerfName(1,innerf)
> ERROR: UndefVarError: innerf not defined
> 
> ```

You would do `outerfName(1, myFTest.innerf)` to pass a non-exported function.

> [@sylvaticus](#):
>
> in my case I am concerned on making a wrapper for my outer function for an other general package that knows nothing about the inner function,

If the other package “knows nothing” about the inner function, why/how it passing that inner function as a parameter? This seems contradictory.
