# Passing a string into function as a expression

**URL:** https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625
**Category:** General Usage
**Tags:** question
**Created:** [November 28, 2019, 2:52pm UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625 "2019-11-28T14:52:54Z")
**Posts on this page:** 18
**Page:** 1

<div class="post-metadata">

### Author: ![ke\_xu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ke_xu/32/8871_2.png) [@ke\_xu](https://discourse.julialang.org/u/ke_xu)
#### Post date: [November 28, 2019, 2:52pm UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625/1 "2019-11-28T14:52:54Z")

</div>

```julia
function Compare(a,b,c::String)
    d = Meta.parse(c)
    if eval(d)
        true
    else
        false
    end
end
Compare(1,1,"a>b")

```

I tried to compare two integers by a customized expression, like the function above. But the generated expression can’t relate its containing variables to the function input. So I got the output:

```julia
UndefVarError: a not defined

```

Also, I found if I have global variables of `a` and `b`, the expression just use the global variables, ignoring the local `a` and `b` in the function `Compare`.  
It there any way to fix this?

---

<div class="post-metadata">

### Author: ![kdyrhage](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kdyrhage/32/2326_2.png) [@kdyrhage](https://discourse.julialang.org/u/kdyrhage)
#### Post date: [November 28, 2019, 3:05pm UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625/2 "2019-11-28T15:05:34Z")

</div>

`eval` always works in global scope (of the current module). In your first case, `a` and `b` are in local scope, so they are not seen.

---

<div class="post-metadata">

### Author: ![ke\_xu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ke_xu/32/8871_2.png) [@ke\_xu](https://discourse.julialang.org/u/ke_xu)
#### Post date: [November 28, 2019, 3:11pm UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625/3 "2019-11-28T15:11:18Z")

</div>

Thanks, but it’s a little strange to design it like this.  
Do the developers have designed a function that just convert a string to the code right there without any other influence? Is that technically possible?

---

<div class="post-metadata">

### Author: ![MatFi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matfi/32/10002_2.png) [@MatFi](https://discourse.julialang.org/u/MatFi)
#### Post date: [November 28, 2019, 3:14pm UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625/4 "2019-11-28T15:14:11Z")

</div>

Have a look at [https://docs.julialang.org/en/v1/manual/metaprogramming/index.html](https://docs.julialang.org/en/v1/manual/metaprogramming/index.html)

---

<div class="post-metadata">

### Author: ![MatFi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matfi/32/10002_2.png) [@MatFi](https://discourse.julialang.org/u/MatFi)
#### Post date: [November 28, 2019, 4:08pm UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625/5 "2019-11-28T16:08:04Z")

</div>

You can also try this:

```julia
function Compare(a,b,c::String)
    d = Meta.parse(c)
    for i in eachindex(d.args)
        if d.args[i] ==:a 
            d.args[i] = a
        elseif d.args[i] == :b
            d.args[i] = b
        end
    end    
    ex = Expr(:call,d.args...)
    if eval(ex)
        true
    else
        false
    end
end
Compare(1,2,"a>b") # false
Compare(1,2,"b>a") # true
)

```

or you can call `eval()` on each argument

```julia
function Compare(a,b,c::String)
    d = Meta.parse(c)
    eval(:(a=$a))
    eval(:(b=$b))
    if eval(d)
        true
    else
        false
    end
end

```

but be aware this solutions are all performance killers  
EDIT: Just because its mark as a solution: In particular the second approach can lead to unexpected behavior e.g.

```julia
a=3
Compare(1,2,"a>b>0") # true
a == 3 # false
a == 1 # true

```

so now I have warned you

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [November 28, 2019, 4:12pm UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625/6 "2019-11-28T16:12:25Z")

</div>

> [@ke\_xu](#):
>
> Thanks, but it’s a little strange to design it like this.

Optimizing code becomes extremely hard if you could just eval arbitrary code into local scope at runtime.

See [https://youtu.be/XWIZ\_dCO6X8?t=168](https://youtu.be/XWIZ_dCO6X8?t=168) which discusses this limitation and its impact.

---

<div class="post-metadata">

### Author: ![ke\_xu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ke_xu/32/8871_2.png) [@ke\_xu](https://discourse.julialang.org/u/ke_xu)
#### Post date: [November 28, 2019, 4:41pm UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625/7 "2019-11-28T16:41:22Z")

</div>

Thank you.  
That works!

Furthermore, if we have `F(condition::String, object::AType)` and the specific format of condition is unknow, such as `"object.someAttribute%10 == 0"`, can we still have a solution?

In fact, all I want is to provide a interface to customize the condition of a function to perform. That is

```julia
function F(condition::String, object::AType)
    if ConcertToCode(condition)
        Perform()
    end
end
F("object.someAttribute % 10 == 0", object)

```

Is there any good way to do it? If not using string as condition, what else way can be elegant to do this?

---

<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: [November 28, 2019, 4:43pm UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625/8 "2019-11-28T16:43:14Z")

</div>

> [@ke\_xu](#):
>
> `Compare(1,1,"a>b")`

Don’t do this. [Don’t pass expressions, or strings, pass functions](https://www.youtube.com/watch?v=mSgXWpvQEHE&t=573s): `Compare(1,1, >)` or `Compare(1,1, (a,b) -> a > b)`, for example.

Besides not needing to parse/eval the string, passing functions as arguments ([higher-order functions](https://en.wikipedia.org/wiki/Higher-order_function)) has many many advantages in terms of both performance and flexibility.

---

<div class="post-metadata">

### Author: ![MatFi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matfi/32/10002_2.png) [@MatFi](https://discourse.julialang.org/u/MatFi)
#### Post date: [November 28, 2019, 5:10pm UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625/9 "2019-11-28T17:10:26Z")

</div>

It’s hard to comprehend what you are looking for. Why is

```julia
function F(condition::Bool, object::AType)
    if condition
        Perform()
    end
end
F(object.someAttribute % 10 == 0, object)

```

not an option?

---

<div class="post-metadata">

### Author: ![ke\_xu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ke_xu/32/8871_2.png) [@ke\_xu](https://discourse.julialang.org/u/ke_xu)
#### Post date: [November 28, 2019, 7:04pm UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625/10 "2019-11-28T19:04:21Z")

</div>

Actually I’m writing a small scientific computation program. Sometimes I need the `condition` function is introduced by reading from a text file, and I think that would be useful because user can be more free to control the program. Whatever, if there’s no good way, at least I can generate the .jl file from the input text file.

---

<div class="post-metadata">

### Author: ![MatFi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matfi/32/10002_2.png) [@MatFi](https://discourse.julialang.org/u/MatFi)
#### Post date: [November 28, 2019, 9:38pm UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625/11 "2019-11-28T21:38:50Z")

</div>

I’m not an expert in this, but you can crawl trough the parsed arguments and replace the object like in the example above. You can generalize this task by performing some kind of “search and replace”.

```julia
function F(condition::String, object::AType)
    d = Meta.parse(condition)
    d.args[2].args[2].args[1] = object
    if eval(d)
        Perform()
    end
end
F("object.someAttribute % 10 == 0", object)

```

I’m pretty sure that this can be done in more general fashion.

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [November 28, 2019, 9:57pm UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625/12 "2019-11-28T21:57:22Z")

</div>

Just to point out, something like

```julia
julia> function Compare(a,b,c::String)
           h = @eval (a, b) -> $(Meta.parse(c))
           if Base.invokelatest(h, a, b)
               true
           else
               false
           end
       end
Compare (generic function with 1 method)

julia> Compare(1,2,"a>b")
false

julia> Compare(1,2,"a<b")
true

```

can be done. It’s not that good of an idea though.

---

<div class="post-metadata">

### Author: ![MatFi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matfi/32/10002_2.png) [@MatFi](https://discourse.julialang.org/u/MatFi)
#### Post date: [November 28, 2019, 10:07pm UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625/13 "2019-11-28T22:07:36Z")

</div>

cool… makes the solution for @ke_xu much more convenient and general

```julia
function F(condition::String, object::AType)
    d= @eval object -> $(Meta.parse(condition))
    if Base.invokelatest(d, object)
        Perform()
    end
end

```

---

<div class="post-metadata">

### Author: ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)
#### Post date: [November 28, 2019, 10:33pm UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625/14 "2019-11-28T22:33:50Z")

</div>

First, those who say that you should avoid evaluating expressions at runtime are absolutely correct. Don’t do it if there’s any other solution.

If you do need to do it, and there are situations where it is valid, you have two sane options to make it semantically local, even though the `eval` takes place in global scope.

1. Eval an anonymous function and pass your arguments to it.

```julia
julia> function Compare(a, b, c::String)
           f = eval(Meta.parse("(a, b) -> $c"))
           return Base.invokelatest(f, a, b)
       end
Compare (generic function with 1 method)

julia> Compare(1, 1, "a>b")
false

```

The `invokelatest` call does the same thing as `f(a, b)` but is necessary for technical reasons, basically because it calls a function that didn’t exist when `Compare` itself was called.

1. Inject your arguments into the expression before evaluating it. This has been demonstrated in earlier replies but let’s do it in a more general way, reusing a solution from [Evaluate expression with variables from a dictionary - #2 by GunnarFarneback](https://discourse.julialang.org/t/evaluate-expression-with-variables-from-a-dictionary/30047/2) :

```julia
interpolate_from_dict(ex::Expr, dict) = Expr(ex.head, interpolate_from_dict.(ex.args, Ref(dict))...)
interpolate_from_dict(ex::Symbol, dict) = get(dict, ex, ex)
interpolate_from_dict(ex::Any, dict) = ex
function Compare(a, b, c::String)
    expr = Meta.parse(c)
    return eval(interpolate_from_dict(expr, Dict(:a => a, :b => b)))
end

```

---

<div class="post-metadata">

### Author: ![ke\_xu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ke_xu/32/8871_2.png) [@ke\_xu](https://discourse.julialang.org/u/ke_xu)
#### Post date: [November 29, 2019, 3:04am UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625/15 "2019-11-29T03:04:28Z")

</div>

Thank you.  
If I store the f the for once for a fixed c::string at the initial stage of program, and invoke it for different a and b for many times, is that would be not very harmful to performance?

---

<div class="post-metadata">

### Author: ![ke\_xu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ke_xu/32/8871_2.png) [@ke\_xu](https://discourse.julialang.org/u/ke_xu)
#### Post date: [November 29, 2019, 3:05am UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625/16 "2019-11-29T03:05:06Z")

</div>

Thank you again, that is what I want.

---

<div class="post-metadata">

### Author: ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)
#### Post date: [November 29, 2019, 7:43am UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625/17 "2019-11-29T07:43:28Z")

</div>

If you cache the `eval`ed function you can avoid a part of the performance impact. Having to call through `invokelatest` is still slower than a normal function call though. You need to measure if the performance is good enough for your needs but don’t plan to use it for anything truly performance critical.

---

<div class="post-metadata">

### Author: ![abulak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abulak/32/28314_2.png) [@abulak](https://discourse.julialang.org/u/abulak)
#### Post date: [May 12, 2020, 9:58pm UTC](https://discourse.julialang.org/t/passing-a-string-into-function-as-a-expression/31625/18 "2020-05-12T21:58:40Z")

</div>

Sorry for necrobumping.

I needed something similar but solution 1 (define a function and evaluate it) turned out to be excruciatingly slow (I have millions of expressions to evaluate, don’t ask 🤦‍♂️)  
it turns out `eval`+`let` block are 20-30 × faster for me. Here’s what I did:

```julia
function parse_eval(arg, expr_str)
    ex = Meta.parse(expr_str)
    return @eval begin
        let Z=$arg
            $ex
        end
    end 
end

```
