Metaprogramming help

Hello,
I want to change the value of a variable within a function in a for loop. Here’s a silly example.

for k in 1:10
  myfun(a,b) = a*b+k
  println myfun(1,2)
end

So k is not an input, but I want to change it. I have good reasons for this, don’t worry ;).
I’m thinking I need to have the function definition as a string and then eval that string, or something like that. I don’t want to use k as a global variable, as that leads to issues.
Can anyone help?
Thanks a lot!

eval is not metaprogramming. eval should not be used outside select circumstances.

Maybe try reading through this blog post giving lots of explanation about metaprogramming.

1 Like

Perhaps use a callable mutable struct instead of a closure, which is syntactic sugar for a callable immutable struct. Then no metaprogramming is required.

But your example is working, right? (apart from a syntax error, which I assume is related to copy-pasting here)

julia> for k in 1:10
         myfun(a,b) = a*b+k
         println(myfun(1,2))
       end
3
4
5
6
7
8
9
10
11
12

I think this creates a new function that closes over the local variable k in each loop iteration. Is there anything wrong with this approach in your real context?

1 Like

FWIW, I still worry :slight_smile:

6 Likes

I was sure people would ask for the reasons behind this =P.
Basically this example is not at all how my real problem will be. The function will be called from other functions and I don’t want to risk having that unclear k in there.
My reason for doing this is just to validate some stuff in my code. So I don’t plan on keeping this in the actual code, just in a validation script.
I don’t want to modify the function or its inputs because that function is already pretty complicated in its definition (it actually belongs to a struct).
Anywho, any ideas on how to eval the function definition in the loop?
Thanks!

Okay so your setup is like the following?

function foo(x, y, z)
    # complicated stuff involving some number k
    k = 100
    k + x + y + z
end

and you want to change the internals of foo on the fly so that it’s definition is akin to

foo_new(x, y, z)
    k = 200
    k + x + y + z
end

?

Yes, I think you got it.
I’m looping over k and it’s used in a function. I want to modify it inside that function (which I’ll redefine anyway for each value of k). So I want to redefine the function based on what’s effectively a global var (without using global vars, as they can’t be redefined).
Is this clearer?

Was the function f defined while capturing a global variable k?

What you are asking for is not possible, unfortunately. You have have the function f take k as an input.

Making explicit the suggestion by @Jeff_Emanuel:

julia> mutable struct MyFun
           k::Int64
       end

julia> (f::MyFun)(a,b) = a * b + f.k

julia> myfun = MyFun(0);

julia> for k in 1:10
           myfun.k = k
           println(myfun(1,2))
       end
3
4
5
6
7
8
9
10
11
12
1 Like

There’s no equivalent to the eval in Matlab, where you can run a string?
Like

k=1
tmp="myfun(a,b)=a+b*$k"
eval(tmp)

Or something in these lines?

you need to first parse that String

julia> eval(Meta.parse(tmp))
myfun (generic function with 1 method)
1 Like

Yes, this seems to be a natural way to do what’s needed.

And it is actually very similar to the approach in the OP, which AFAIK is translated under the hood as something akin to:

julia> struct MyFun
           k::Int64
       end

julia> (f::MyFun)(a,b) = a * b + f.k

julia> for k in 1:10
           myfun = MyFun(k)
           println(myfun(1,2))
       end
3
4
5
6
7
8
9
10
11
12

So I’m wondering if there is something wrong with the solution outlined in the OP, that would rule out this class of techniques.

1 Like

Thanks, folks.
I think both of these options work!
Thanks again!

I believe he wants to change the value of k in the closure, which requires mutability, so the more verbose mutable struct is require.