How one can evaluate @printf to be returned to a value

Hi all, for a technical reason I would like to define functions as below. My problem is how to evaluate func(xx) to get a value

function DeltaAI(z)
return 1/(1+z)
end

function DeltaAII(z)
return √(1-z^2)
end

if (F==0)
    myfunc = "IA"
elseif  (F==1)
    myfunc = "IIA"
end
F=0;

func(x) = @printf("Delta%s(%f)",myfunc,x)
func(1) # it sould be = 0.5 whlie I've got DeltaIA(1.000000)

You could do something like

function DeltaAI(z)
    return 1/(1+z)
end

function DeltaAII(z)
    return √(1-z^2)
end

F=0;
if (F==0)
    myfunc = "AI"
elseif  (F==1)
    myfunc = "AII"
end

func(x) = getfield(@__MODULE__, Symbol("Delta", myfunc))(x)
func(1)

but I would very much recommend structuring your code differently and explicitly writing out the logic in func. E.g.

function func(x, F)
    if F == 0
        DeltaAI(x)
    elseif F == 1
        DeltaAII(x)
    else
        throw(ArgumentError("F must be 0 or 1"))
    end
end
1 Like

Thanks for very nice reply. I agree with you, but I would prefer the first like func(x) = getfield(@__MODULE__, Symbol("Delta", myfunc))(x) however I got the following error UndefVarError: DeltaIA not defined

Your original code has a typo in your definition of myfunc. You have "IA" instead of "AI" and similarly for IIA instead of AII (@pfitzseb fixed this in the solution given)

1 Like

I got it, thanks a lot @DanielVandH and @pfitzseb

1 Like

Instead of passing around functions as strings (or encoded as numbers like F), it is much better to simply pass them around as functions. e.g. if you set

myfunc = DeltaAII

you can just call myfunc(1). A function called DeltaAII can also be passed as an argument to another function. This is called a higher-order function.

PS. The literal answer to your original question is

func(x) = eval(Meta.parse(@sprintf("Delta%s(%f)",myfunc,x)))

but this is a classic anti-pattern. See How to warn new users away from metaprogramming … in particular, you almost never want to pass functions or expressions as strings that you parse and evaluate. It’s fragile, slow, and inflexible. Julia has first-class functions — enjoy it!

2 Likes

Thanks @stevengj for your comment, but the idea of @pfitzseb is faster than Meta.parse. However, I don’t know about first-class function or higher order one. Could you show me in a simple example how can we use that?

My point is that you should use neither eval(Meta.parse(...)) (which is slow) nor getfield(@__MODULE__, Symbol(...)) which is faster but still slow.

The eval(Meta.parse(@sprintf(...))) answer was the literal answer to your question (how can you evaluate the output of @printf as code), but you are probably asking the wrong question. This is a classic XY problem.

Since I don’t know what your ultimate goal is, I can only give a made-up example. Suppose you want to write a function integrate(f, a, b; N=100) that computes \int_a^b f(x) dx for a user-specified function f from a to b using an N-point trapezoidal rule. You could implement this with:

function integrate(f, a, b; N=100)
    dx = (b - a) / (N-1)
    I = (f(a) + f(b)) * dx / 2 # endpoints
    for i = 1:N-2 # interior points
        I += f(i * dx) * dx
    end
    return I
end

This is a “higher-order function” because it takes in a function f as an argument. For example, we could use this to approximately integrate your function DeltaAI from 0 to 1:

julia> integrate(DeltaAI, 0, 1)
0.6931535573789361

which matches the exact answer \ln 2 \approx 0.6931471805599453 to four digits, and we can get more digits correct by increasing N:

julia> integrate(DeltaAI, 0, 1, N=10^6)
0.6931471805600137

Notice how we can simply pass DeltaAI as an argument. No string evaluation etcetera is required, and Julia compiles this to very efficient code. We can even define new functions on the fly to integrate, e.g.

julia> integrate(x -> x^2, 0, 1) # ∫x² ≈ 1/3
0.3333503384008435

In this way, functions are “first-class” objects in Julia — you can pass them as arguments, return them from other functions, manipulate them to make new functions, etcetera, on the fly.

You wouldn’t store numbers as strings in Julia. Don’t store functions as strings either.

4 Likes