Please direct me to documentation on how to pass a function as argument to another function in type stable manner. Thx!
There’s nothing special to do, just pass it.
Ah? When I pass as the function as argument, the code below does a lot of allocations.
Taking the function as global variable from main scope instead, makes allocations disappear.
Using @code_warntype does not reveal any concerns.
I am missing something.
mySourceFct(x,y) = x+y function generateLocalVector(element::Element, sourceFct::Function) p1 = element.p1; p2 = element.p2; p3 = element.p3; e1 = element.e1; e2 = element.e2; e3 = element.e3; area = element.area Iloc = SVector(e1, e2, e3) # use broadcast for the lines below instead f1 = area/3*sourceFct(p1.x,p1.y) f2 = area/3*sourceFct(p2.x,p2.y) f3 = area/3*sourceFct(p3.x,p3.y) floc = SVector(f1, f2, f3) return Iloc, floc end function generateVector(mesh, sourceFct::Function) #..recover number of elements N::Int64 = length(mesh.Elements) nnodes = mesh.nnodes #..preallocate the memory for local matrix contributions f = zeros(Float64,nnodes) for i = 1:N #..loop over number of elements.. element::Element = mesh.Elements[i] Iloc, floc = generateLocalVector(element,sourceFct) f[Iloc] += floc end return f; end
This should be fixed by changing
function generateVector(mesh, sourceFct::Function)
function generateVector(mesh, sourceFct::F) where F
If there are still problems, you might need to make the same change to
generateLocalVector, but that is probably not needed because the function is called directly by it.
Thx! Allocations are now indeed wiped out. Is compiler performance something to worry over here?
I wouldn’t usually worry about the compiler in limited cases like this. The place where you might get in trouble is throwing a zillion different functions at this. Compiling with specialization for a handful (or even tens or maybe hundreds) of functions won’t be noticeable… but the runtime performance that the specializations provide certainly is!
Maybe somebody else can provide a more thorough commentary as to why this behavior is default. My understanding is that it’s very useful in situations, but this performance trap catches just about everyone sooner or later.
Do I read the docs correctly if I understood that this non-specialisation of the outside method is happening because your are not actually using the function and just passing it through to the inside method ?
So that in the OP state of the code, the inner method indeed specializes on the function, but the outer one does not, and therefore cannot call the specialized inner one ?
Correct. Reminds me of a past thread; TLDR yes this exception is unintuitive, but specializing on functions by default improves performance in uncommon situations yet severely bloats compilation of caller chains generally, and chained callee inlining can and often removes the caller chain and nonspecialization issue for argument functions fixed at compile-time e.g.
foo(x, y) = map(+, x, y).