Just use z = 1 function2 = @anon c -> c + z for z = 1:100 function2.z = z # do whatever with function2, including making a copy end
--Tim On Friday, January 22, 2016 08:55:25 AM Cedric St-Jean wrote: > (non-mutating) Closures and FastAnonymous work essentially the same way. > They store the data that is closed over (more or less) and a function > pointer. The thing is that there's only one data structure in Julia for all > regular anonymous functions, whereas FastAnonymous creates one per @anon > site. Because the FastAnonymous-created datatype is specific to that > function definition, the standard Julia machinery takes over and produces > efficient code. It's just as good as if the function had been defined > normally with `function foo(...) ... end` > > > for z = 1:100 > function2 = @anon c -> (c + z) > > dict[z] = function2 > end > > > So we end up creating multiple functions for each z value. > > > In this code, whether you use @anon or not, Julia will create 100 object > instances to store the z values. > > The speed difference between the two will soon be gone. > <https://github.com/JuliaLang/julia/pull/13412> > > Cédric > > On Friday, January 22, 2016 at 11:31:36 AM UTC-5, Bryan Rivera wrote: > > I have to do some investigating here. I thought we could do something > > like that but wasn't quite sure how it would look. > > > > Check this out: > > > > This code using FastAnonymous optimizes to the very same code below it > > where functions have been manually injected: > > > > using FastAnonymous > > > > > > function function1(a, b, function2) > > > > if(a > b) > > > > c = a + b > > return function2(c) > > > > else > > > > # do anything > > # but return nothing > > > > end > > > > end > > > > > > z = 10 > > function2 = @anon c -> (c + z) > > > > > > a = 1 > > b = 2 > > @code_llvm function1(a, b, function2) > > @code_native function1(a, b, function2) > > > > Manually unrolled equivalent: > > > > function function1(a, b, z) > > > > if(a > b) > > > > c = a + b > > return function2(c, z) > > > > else > > > > # do anything > > # but return nothing > > > > end > > > > end > > > > > > function function2(c, z) > > > > return c + z > > > > end > > > > > > a = 1 > > b = 2 > > z = 10 > > > > > > @code_llvm function1(a, b, z) > > > > @code_native function1(a, b, z) > > > > However, this is a bit too simplistic. My program actually does this: > > > > # Test to see if multiple functions are created. They are. > > # We would only need to create a single function if we used julia anon, > > but its time inefficient. > > > > dict = Dict{Int, Any}() > > for z = 1:100 > > > > function2 = @anon c -> (c + z) > > > > dict[z] = function2 > > > > end > > > > > > a = 1 > > b = 2 > > > > function test() > > > > function1(a,b, dict[100]) > > function1(a,b, dict[50]) > > > > end > > > > @code_llvm test() > > @code_native test() > > > > > > > > So we end up creating multiple functions for each z value. We could use > > Julia's anon funs, which would only create a single function, however > > these > > lamdas are less performant than FastAnon. > > > > So its a space vs time tradeoff, I want the speed of FastAnon, without the > > spacial overhead of storing multiple functions. > > > > Can we be greedy? :) > > > > On Thursday, January 21, 2016 at 9:56:51 PM UTC-5, Cedric St-Jean wrote: > >> Something like this? > >> > >> function function1(a, b, f) # Variable needed in callback fun injected. > >> > >> if(a > b) > >> > >> c = a + b > >> res = f(c) # Callback function has been injected. > >> return res + 1 > >> > >> else > >> > >> # do anything > >> # but return nothing > >> > >> end > >> > >> end > >> > >> type SomeCallBack > >> > >> z::Int > >> > >> end > >> Base.call(callback::SomeCallBack, c) = c + callback.z > >> > >> function1(2, 1, SomeCallBack(10)) > >> > >> Because of JIT, this is 100% equivalent to your "callback function has > >> been injected" example, performance-wise. My feeling is that .call > >> overloading is not to be abused in Julia, so I would favor using a > >> regular > >> function call with a descriptive name instead of call overloading, but > >> the > >> same performance guarantees apply. Does that answer your question? > >> > >> On Thursday, January 21, 2016 at 9:02:50 PM UTC-5, Bryan Rivera wrote: > >>> I think what I wrote above might be too complicated, as it is an attempt > >>> to solve this problem. > >>> > >>> In essence this is what I want: > >>> > >>> > >>> # wasmerged, _, _, _ = elide_pairwise!(ttree1, ttree2, canmerge; nbrs=idbgv) > >>> function function1(a, b, onGreaterThanCallback) > >>> > >>> if(a > b) > >>> > >>> c = a + b > >>> res = onGreaterThanCallback(c, z) > >>> return res + 1 > >>> > >>> else > >>> > >>> # do anything > >>> # but return nothing > >>> > >>> end > >>> > >>> end > >>> > >>> > >>> global onGreaterThanCallback = (c) -> c + z > >>> > >>> function1(a, b, onGreaterThanCallback) > >>> > >>> > >>> Problems: > >>> > >>> The global variable. > >>> > >>> The anonymous function which has performance impact (vs other > >>> approaches). We could use Tim Holy's @anon, but then the value of `z` > >>> is > >>> fixed at function definition, which we don't always want. > >>> > >>> I think that the ideal optimization would look like this: > >>> function function1(a, b, z) # Variable needed in callback fun > >>> > >>> injected. > >>> > >>> if(a > b) > >>> > >>> c = a + b > >>> res = c + z # Callback function has been injected. > >>> return res + 1 > >>> > >>> else > >>> > >>> # do anything > >>> # but return nothing > >>> > >>> end > >>> > >>> end > >>> > >>> > >>> function1(a, b, z) > >>> > >>> In OO languages we would be using an abstract class or its equivalent. > >>> > >>> But I've thought about it, and read the discussions on interfaces, and > >>> > >>> don't see those solutions optimizing the code out like I did above. > >>> > >>> Any ideas?