Do locally declared lua functions get parsed every time they are passed? - function
Let's say I have a locally declared function inside another function that gets called a lot:
function outer()
-- Do stuff
local loop = true
while loop do -- for some reason
local function inner()
-- Do function stuff
end
-- Doing stuff
inner()
end
end
Does the inner function get newly created, parsed, processed, everything, every time it gets encountered at runtime? Basically, is there any performance difference between this pattern and declaring a separate standalone function?
function inner()
-- Do stuff
end
functions outer()
local loop = true
while loop do
inner()
end
end
Short answer: No.
When you run a Lua chunk (a chunk is usually a file, but sometimes a string), the entire chunk is compiled to bytecode before it is executed. When you define a local function, you are assigning a reference to that function's bytecode to the function's name. Lua does not re-evaluate the function itself.
In your first code snippet, you might get a tiny performance penalty from assigning the bytecode reference to the local variable. Of course, you should benchmark that to be sure. I don't know if Lua can optimize that away.
Note that closures can have different sets of upvalues, but still refer to the same function bytecode.
In addition to the answer that luther has provided, there is a bit more to this, but you can wonder if it is significant. I don't think it will matter a lot in performance.
Lua will compile each function block, however when you use a local function it will have to execute the CLOSURE instruction and a MOVE instruction each time that particular code is called. The MOVE is added to prevent the CALL instruction from popping the closure off the stack. I don't believe Lua optimizes that bit in any case.
If you have a global function or an upvalue, it will only need to acquire that value with an GETGLOBAL, GETTABUP or GETUPVALUE instruction.
You can see the generated bytecode here;
https://luac.nl/s/473abd2a0bb427a31766ea917
Related
What is the memory allocation when you return a function in Golang?
Here is a simplified code func MyHandler(a int) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteCode(a) }) } Whenever a http request comes MyHandler will be called, and it will return a function which will be used to handle the request. So whenever a http request comes a new function object will be created. Function is taken as the first class in Go. I'm trying to understand what actually happened when you return a function from memory's perspective. When you return a value, for example an integer, it will occupy 4 bytes in stack. So how about return a function and lots of things inside the function body? Is it an efficient way to do so? What's shortcomings?
If you're not used to closures, they may seem a bit magic. They are, however, easy to implement in compilers: The compiler finds any variables that must be captured by the closure. It puts them into a working area that will be allocated and remain allocated as long as the closure itself exists. The compiler then generates the inner function with a secret extra parameter, or some other runtime trickery,1 such that calling the function activates the closure. Because the returned function accesses its closure variables through the compile-time arrangement, there's nothing special needed. And since Go is a garbage-collected language, there's nothing else needed either: the pointer to the closure keeps the closure data alive until the pointer is gone because the function cannot be called any more, at which point the closure data evaporates (well, at the next GC). 1GCC sometimes uses trampolines to do this for C, where trampolines are executable code generated at runtime. The executable code may set a register or pass an extra parameter or some such. This can be expensive since something treated as data at runtime (generated code) must be turned into executable code at runtime (possibly requiring a system call and potentially requiring that some supervisory code "vet" the resulting runtime code). Go does not need any of this because the language was defined with closures in mind, so implementors don't, er, "close off" any easy ways to make this all work. Some runtime ABIs are defined with closures in mind as well, e.g., register r1 is reserved as the closure-variables pointer in all pointer-to-function types, or some such.
Actual function size is irrelevant. When you return a function like this, memory will be allocated for the closure, that is, any variables in the scope that the function uses. In this case, a pointer will be returned containing the address of the function and a pointer to the closure, which will contain a reference to the variable a.
Getting all functions in a Lua script
I'm trying to figure out a way to get all functions in a Lua script. This script has been compiled into a function through loadfile. For example, I'd want to get every function defined in the script below. function example1() end local function example2() end local library = {} function library:example3() end (function() -- Functions like this too. end) The names aren't important, I'm just looking for a way to get the actual functions so I can use them in debug.getinfo and get information like the lines they were defined in. I have LuaJIT, if that makes this any easier. Is something like this even possible? Thanks in advance.
I guess the file declares its functions as global, or it would be really easy to track what is returned. If that's the case, you can cycle through all the global items with a generic for loop, and only take the functions from them: allFuncs = {} for key, item in pairs(_G) do if type(item) == "function" then allFuncs[#allFuncs + 1] = item end end (_G is the table holding all the global variables) Then you will have a list (allFuncs) holding all the functions declared, but be aware that it will also contain default functions like setmetatable or xpcall. It's easy to modify the code to not make this happen, but only use this for testing / learning: function allFuncs() local funcsTab = {} for key, item in pairs(_G) do if type(item) == "function" then funcsTab[#funcsTab + 1] = item end end return funcsTab end defaultFuncs = allFuncs() --then you load your file: other functions get declared --we create another table containg the default + the new functions myFuncs = allFuncs() --then you subtract the first table from the second for i = 1, #myFuncs do for o = 1, #defaultFuncs do if myFuncs[i] == defaultFuncs[o] then table.remove(myFuncs, i) end end end This is if your file doesn't return anything and declares its functions as globals. If the file declares them as local and then returns a table containing them, just use the first piece of code replacing _G with that returned table.
This is not likely to be possible without syntax or bytecode analysis as each function definition is an assignment (just has different forms in your examples). See the bytecode inspector and a related discussion here. For the syntax analysis you can use metalua or something like lua-loose-parser. Keep in mind that even those tools won't give you the entire list of functions as some functions may be defined dynamically using loadstring (or similar methods). If you only have access to the result of loadfile, then you best bet is to use the bytecode analyzer.
This is possible using jit.attach in LuaJIT. You can attach callbacks to a number of compiler events with jit.attach. The callback can be called: when a function has been compiled to bytecode ("bc"); when trace recording starts or stops ("trace"); as a trace is being recorded ("record"); or when a trace exits through a side exit ("texit"). http://wiki.luajit.org/JIT-Compiler-API#jit-attach jit.attach(function(f) local funcInfo = jit.util.funcinfo(f) end, "bc")
Ada package function identifier expected
Learning Ada and trying to make a stack ADT and I'm using this webpage to figure it out. http://www.functionx.com/ada/Lesson06.htm eightqueens.adb with Ada.Text_IO; use Ada.Text_IO; with Stack; use Stack; procedure EightQueens is begin put_line ("awd"); end EightQueens; stack.ads package Stack is function awd () return Integer; end Stack; stack.adb package body Stack is function awd () return integer is begin return 1; end awd; end Stack; Error is stack.ads:2:19: identifier expected I'm most certain I did everything correctly.
Ada doesn't use empty parentheses, either for defining or for calling functions or procedures. And for future reference, the phrase "I'm most certain I did everything correctly." is a red flag indicating that you've almost certainly done something wrong.
Just to elaborate, there are some syntactic decisions that Ada made that IMHO are superior to what you may be used to from C-syntax languages. Functions with no parameters don't use empty parenthesis in their calls. This allows you to change a contant to a function call without having to recode any of the clients. Arrays use parentheses like function calls do, rather than some unique syntax. This allows you to change an array constant to a function call without having to recode any of the clients. To look at it another way, a constant is just a simplified version of a parameterless function, for when you can get away with always returning the same value. Likewise, a constant array is a simplified version of a parametered function call, for when you can get away with always returning the same value. If you later discover you need a more complex implementation, that's not the client's concern, and should not affect their code.
MATLAB Updating a global variable from one function does not get reflected in the other function
I have a function that uses a global variable and I want to change its value from another function. Even though I tried in many ways, the function that uses the value seems not getting updated with the new value of the global variable. Here's the code I'm using. calculate.m function calculateTest() global isStop; global value; value=0; while ~isStop pause(1); value = value+1 end end start.m function start() global isStop; isStop = 0; calculateTest(); end stop.m function stop() global isStop; isStop = 1; end When I call start() the value starts getting printed. But even if I call stop(), it never stops. It keeps on printing. Do you have any idea of what I am missing? (I have tried while isStop==0 as well. But the result was the same.
I think what you need is a background thread that would do the calculateTest while leaving you the possibility to run stop from a matlab script/command line. This functionality is not supported by MATLAB in the pure sense. You can sometimes implement similar things using the timer functionality. Essentially, you tell MATLAB to run a function repeatedly after some time has passed. However, MATLAB is running the timer function in the foreground. And while it is doing that you can not run your stop script. So you can not implement a long loop in the timer function. timer is only good to schedule some tasks to be executed by MATLAB every now and then, but does not implement threading. You could implement your own background thread using a MEX function. You could then call the MEX function to pass 'start'/'stop' commands to your thread. But the MEX thread would have to do the data processing inside. You can not e.g. call some matlab script to do the job. Another thing. start and stop are MATLAB functions that manage the timer. Do not use those identifiers as names of your own functions - that is allowed, but considered a bad practice.
You haven't actually called the stop function anywhere in your code, so there is no opportunity for it to update the global variable. You could, for example, modify calculateTest() by adding a conditional test which calls the stop function when "value" reaches a certain number, such as 5:- function calculateTest() global isStop; global value; value=0; while ~isStop pause(1); value = value+1 if value == 5 stop; end end end You will find that this stops it perfectly well. If you added the stop command into start instead, after CalculateTest, that will not work because the flow of control never reaches that line - it remains on CalculateTest until that function is terminated.
'Invalid Handle object' when using a timer inside a function in MatLab
I am using a script in MatLab that works perfectly fine by itself, but I need to make a function out of it. The script read a .csv file, extract all values, start a timer, and at each tick displays the corresponding coordinates extracted from the .csv, resulting in a 3D animation of my graph. What I would like is to give it the location of the .csv, so that it starts displaying the graphs for this csv. Here is what I have come up with: function handFig(fileLoc) csv=csvread(fileLoc,1,0); both = csv(:,2:19); ax=axes; set(ax,'NextPlot','replacechildren'); Dt=0.1; %sampling period in secs k=1; hp1=text(both(k,1),both(k,2),both(k,3),'thumb'); %get handle to dot object hold on; hp2=text(both(k,4),both(k,5),both(k,6),'index'); hp3=text(both(k,7),both(k,8),both(k,9),'middle'); hp4=text(both(k,10),both(k,11),both(k,12),'ring'); hp5=text(both(k,13),both(k,14),both(k,15),'pinky'); hp6=text(both(k,16),both(k,17),both(k,18),'HAND'); L1=plot3([both(k,1),both(k,16)],[both(k,2),both(k,17)],[both(k,3),both(k,18)]); L2=plot3([both(k,4),both(k,16)],[both(k,5),both(k,17)],[both(k,6),both(k,18)]); L3=plot3([both(k,7),both(k,16)],[both(k,8),both(k,17)],[both(k,9),both(k,18)]); L4=plot3([both(k,10),both(k,16)],[both(k,11),both(k,17)],[both(k,12),both(k,18)]); L5=plot3([both(k,13),both(k,16)],[both(k,14),both(k,17)],[both(k,15),both(k,18)]); hold off; t1=timer('TimerFcn','k=doPlot(hp1,hp2,hp3,hp4,hp5,hp6,L1,L2,L3,L4,L5,both,t1,k)','Period', Dt,'ExecutionMode','fixedRate'); start(t1); end And the doplot function used: function k=doPlot(hp1,hp2,hp3,hp4,hp5,hp6,L1,L2,L3,L4,L5,pos,t1,k) k=k+1; if k<5000%length(pos) set(hp1,'pos',[pos(k,1),pos(k,2),pos(k,3)]); axis([0 255 0 255 0 255]); set(hp2,'pos',[pos(k,4),pos(k,5),pos(k,6)]); set(hp3,'pos',[pos(k,7),pos(k,8),pos(k,9)]); set(hp4,'pos',[pos(k,10),pos(k,11),pos(k,12)]); set(hp5,'pos',[pos(k,13),pos(k,14),pos(k,15)]); set(hp6,'pos',[pos(k,16),pos(k,17),pos(k,18)]); set(L1,'XData',[pos(k,1),pos(k,16)],'YData',[pos(k,2),pos(k,17)],'ZData',[pos(k,3),pos(k,18)]); set(L2,'XData',[pos(k,4),pos(k,16)],'YData',[pos(k,5),pos(k,17)],'ZData',[pos(k,6),pos(k,18)]); set(L3,'XData',[pos(k,7),pos(k,16)],'YData',[pos(k,8),pos(k,17)],'ZData',[pos(k,9),pos(k,18)]); set(L4,'XData',[pos(k,10),pos(k,16)],'YData',[pos(k,11),pos(k,17)],'ZData',[pos(k,12),pos(k,18)]); set(L5,'XData',[pos(k,13),pos(k,16)],'YData',[pos(k,14),pos(k,17)],'ZData',[pos(k,15),pos(k,18)]); else k=1; set(hp1,'pos',[pos(k,1),pos(k,2),pos(k,3)]); axis([0 255 0 255 0 255]); set(hp2,'pos',[pos(k,4),pos(k,5),pos(k,6)]); set(hp3,'pos',[pos(k,7),pos(k,8),pos(k,9)]); set(hp4,'pos',[pos(k,10),pos(k,11),pos(k,12)]); set(hp5,'pos',[pos(k,13),pos(k,14),pos(k,15)]); set(hp6,'pos',[pos(k,16),pos(k,17),pos(k,18)]); end However, when I run handFig('fileName.csv'), I obtain the same error everytime: ??? Error while evaluating TimerFcn for timer 'timer-7' Invalid handle object. I figured that it might come from the function trying to create a new 'csv' and 'both' everytime, so I tried removing them, and feeding the function the data directly, without results. What is exactly the problem? Is there a solution? Thanks a lot!
I think it's because when you call doPlot in the timer for the first time, you pass in t1 as an argument, and it might not exist the first time. Does doPlot need t1 at all? I'd suggest modifying it so it's not used, and then your call to: t1=timer('TimerFcn','k=doPlot(hp1,hp2,hp3,hp4,hp5,hp6,L1,L2,L3,L4,L5,both,k)','Period', Dt,'ExecutionMode','fixedRate'); Note the missing t1 in the doPlot call. Either that, or initialise your t1 before you create the timer so it has some value to pass in. Update (as an aside, can you use pause(Dct) in a loop instead? seems easier) Actually, now I think it's a problem of scope. It took a bit of digging to get to this, but looking at the Matlab documentation for function callbacks, it says: When MATLAB evaluates function handles, the same variables are in scope as when the function handle was created. (In contrast, callbacks specified as strings are evaluated in the base workspace.) You currently give your TimerFcn argument as a string, so k=doPlot(...) is evaluated in the base workspace. If you were to go to the matlab prompt, run handFig, and then type h1, you'd get an error because h1 is not available in the global workspace -- it's hidden inside handFig. That's the problem you're running into. However, the workaround is to specify your function as a function handle rather than a string (it says function handles are evaluated in the scope in which they are created, ie within handFig). Function handles to TimerFcn have to have two arguments obj and event (see Creating Callback Functions). Also, that help file says you have to put doPlot in its own m-file to have it not evaluate in the base Matlab workspace. In addition to these two required input arguments, your callback function can accept application-specific arguments. To receive these input arguments, you must use a cell array when specifying the name of the function as the value of a callback property. For more information, see Specifying the Value of Callback Function Properties. It goes through an example of what you have to do to get this working. Something like: % create timer t = timer('Period', Dt,'ExecutionMode','fixedRate'); % attach `k` to t so it can be accessed within doPlot set(t,'UserData',k); % specify TimerFcn and its extra arguments: t.TimerFcn = { #doPlot, hp1, hp2, hp3, ...., both }; start(t) Note -- the reason k is set in UserData is because it needs to be somehow saved and modified between calls to doPlot. Then modify your doPlot to have two arguments at the beginning (which aren't used), and not accept the k argument. To extract k you do get(timer_obj,'UserData') from within doPlot: function k=doPlot(timer_obj, event, hp1,hp2,hp3,.....) k = get(timer_obj,'UserData'); .... % rest of code here. % save back k so it's changed for next time! set(timer_obj,'UserData',k); I think that's on the right track - play around with it. I'd highly recommend the mathworks forums for this sort of thing too, those people are whizzes. This thread from the mathworks forum was what got me started and might prove helpful to you. Good luck!