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:
>>
>>
>>
>> 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?
>>
>