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?