autohotkey: what does local followed by a variable name mean in function? - function

I've got an auto hotkey function:
loadkeyboard(ALanguage)
{
local i
k:=1
loop{
if k=512
break
a:=GetBits(k)
IniRead letter%a%,Keyboards.ini,%ALanguage%,%a%
if letter%a%=ERROR
letter%a%=
else
if(letter%a%="space")
letter%a%:=" "
k:=k+1
}
return true
}
in this function, what does local i mean? because i is not getting used anyware, and I think that in functions, all variables are by default local, so, what's the use of this line? I tried removing this line, and after removing / commenting, function stopped working. and I've changed the variable name after local keyword, but it worked good, can anyone please help?

By declaring a local variable on the first line of a function you are putting the function in to Assume-global mode
This makes all other Variables then "i" global so that there value can be used or set outside of your function.
So in a way you can replace "local i" with global and get the same result.

Related

Powershell: Function that adds data every time it is run from a function

I know I'm doing something wrong but I am stuck... I am connecting to a Cisco device over serial, then each time I send a command, I can read the output from by typing $port.ReadExisting(). I need to be able to run many commands, let the buffer fill, then get the output from the port. I have to check to make sure that there's something to read first, which is why I put it in a function to be able to be called over and over.
Every time it is called, the $COMReply is wiped out. How can I take what is in COMReply, add $port.ReadExisting(), and have COMReply spit out all of what was written?...
Function WaitForReply {
while ($port.BytesToRead -gt 0){
$COMReply += $($port.ReadExisting()) + "`n"
}
}
Also, how should I call my function?... should I just call it with: WaitForReply? or should I set a variable equal to it with $AllMyReplies = WaitForReply?
This is due to PowerShell's copy-on-write behavior when interacting with a variable in a different scope.
You'll find that you can write to the $COMReply variable defined outside the function if you prefix the variable name with the script: or global: scope qualifiers (ie. $script:COMReply += ...).
... but the real way to solve this problem is to avoid reading from, and more importantly writing to, variables across scope boundaries.
To avoid that, you'll want to:
Declare all the input you need as parameters
Output the results as-is, instead of writing to a variable outside of the function
If we do that, we end up with something like this:
function Wait-ForReply($Port){
while($Port.BytesToRead -gt 0){
$Port.ReadExisting()
}
}
This gives our function a nice clean surface - the function doesn't depend on being able to discover $port from the calling scope, and $COMReply is unaffected by what goes on inside the function.
Now you can add or concatenate to $COMReply in the calling scope, by simply doing:
$COMReply += Wait-ForReply -Port $port

Global variable in Tcl

I am trying to use a global variable (gpio_out_set_3) by declaring it outside a function (because the variable might be used in other functions too in future). Inside the function, I have declared the same variable as 'global' and trying to access it through '$gpio_out_set_3'.
I am getting an error "can't read "gpio_out_set_3": no such variable"
set gpio_out_set_3 0x03
proc port2phy { device } {
global gpio_out_set_3
erf_wr devcpu_gcb $gpio_out_set_3 $phy_mdc_gate_en
}
Please help.
Declare all of your global variable at the beginning of your main file using variable command.
variable gpio_out_set_3 0x03
TIP: I dont like the global command. I always forget to use, and hard to see which variable is global and which variable is local. I prefer the $::<varname>, which points to the global namespace.
proc port2phy { device } {
erf_wr devcpu_gcb $::gpio_out_set_3 $phy_mdc_gate_en
}
My guess is that when you're creating variable gpio_out_set_3 you're not at top level. You are in some other procedure. So the gpio_out_set_3 in not really global, but instead local in some proc.
Your global variable is named gpio_out_set_0 (not the same as gpio_out_set_3).
Although newer versions of tcl allow for executable code to exist almost anywhere in your program, a good habit to form is to be sure that where you set the variable initially is in the main section of your program code. In order for your code to run properly on any version of tcl, there should be no executable code prior to, or in-between your procs (including set commands). All of your procs should go at the beginning of the program followed by your main code. Things that can/should go before your procs are comment lines and any necessary "package require ..." commands.

swift calling functions passing vales I'm confused

I'm getting bit confused
hopefully somebody can put me straight
i have function
which works as i would expect in the playground
func testFunction(Astring:String,Anumber:Int,Afloat:CGFloat)
{
println(Astring)
println(Anumber)
println(Afloat)
}
testFunction("Hello",25,25.00)
but in a project i have to call it like this, if i don't i get error missing argument label "Afloat:" in call
testFunction("Hello",Anumber:25,Afloat:25.00)
the only difference is I'm calling the function from a button?
thanks for the help of this site without it I would be lost
By default, parameters after the first parameter require you to use the external name. If you do not want an external name, then you have to define that in the function. Also as a style point, local variables should start with lower case. Regardless, this should get you what you want. The "_" character basically says no external name.
func testFunction(aString:String, _ aNumber:Int, _ aFloat:CGFloat)

How to select a specific .m function when two exist?

First, here the way i'm calling the function :
eval([functionName '(''stringArg'')']); % functionName = 'someStringForTheFunctionName'
Now, I have two functionName functions in my path, one that take the stringArg and another one that takes something else. I'm getting some errors because right now the first one it finds is the function that doesn't take the stringArg. Considering the way i'm calling the functionName function, how is it possible to call the correct function?
Edit:
I tried the function which :
which -all someStringForTheFunctionName
The result :
C:\........\x\someStringForTheFunctionName
C:\........\y\someStringForTheFunctionName % Shadowed
The shadowed function is the one i want to call.
Function names must be unique in MATLAB. If they are not, so there are duplicate names, then MATLAB uses the first one it finds on your search path.
Having said that, there are a few options open to you.
Option 1. Use # directories, putting each version in a separate directory. Essentially you are using the ability of MATLAB to apply a function to specific classes. So, you might set up a pair of directories:
#char
#double
Put your copies of myfun.m in the respective directories. Now when MATLAB sees a double input to myfun, it will direct the call to the double version. When MATLAB gets char input, it goes to the char version.
BE CAREFUL. Do not put these # directories explicitly on your search path. DO put them INSIDE a directory that is on your search path.
A problem with this scheme is if you call the function with a SINGLE precision input, MATLAB will probably have a fit, so you would need separate versions for single, uint8, int8, int32, etc. You cannot just have one version for all numeric types.
Option 2. Have only one version of the function, that tests the first argument to see if it is numeric or char, then branches to perform either task as appropriate. Both pieces of code will most simply be in one file then. The simple scheme will have subfunctions or nested functions to do the work.
Option 3. Name the functions differently. Hey, its not the end of the world.
Option 4: As Shaun points out, one can simply change the current directory. MATLAB always looks first in your current directory, so it will find the function in that directory as needed. One problem is this is time consuming. Any time you touch a directory, things slow down, because there is now disk input needed.
The worst part of changing directories is in how you use MATLAB. It is (IMHO) a poor programming style to force the user to always be in a specific directory based on what code inputs they wish to run. Better is a data driven scheme. If you will be reading in or writing out data, then be in THAT directory. Use the MATLAB search path to categorize all of your functions, as functions tend not to change much. This is a far cleaner way to work than requiring the user to migrate to specific directories based on how they will be calling a given function.
Personally, I'd tend to suggest option 2 as the best. It is clean. It has only ONE main function that you need to work with. If you want to keep the functions district, put them as separate nested or sub functions inside the main function body. Inside of course, they will have distinct names, based on how they are driven.
OK, so a messy answer, but it should do it. My test function was 'echo'
funcstr='echo'; % string representation of function
Fs=which('-all',funcstr);
for v=1:length(Fs)
if (strcmp(Fs{v}(end-1:end),'.m')) % Don''t move built-ins, they will be shadowed anyway
movefile(Fs{v},[Fs{v} '_BK']);
end
end
for v=1:length(Fs)
if (strcmp(Fs{v}(end-1:end),'.m'))
movefile([Fs{v} '_BK'],Fs{v});
end
try
eval([funcstr '(''stringArg'')']);
break;
catch
if (strcmp(Fs{v}(end-1:end),'.m'))
movefile(Fs{v},[Fs{v} '_BK']);
end
end
end
for w=1:v
if (strcmp(Fs{v}(end-1:end),'.m'))
movefile([Fs{v} '_BK'],Fs{v});
end
end
You can also create a function handle for the shadowed function. The problem is that the first function is higher on the matlab path, but you can circumvent that by (temporarily) changing the current directory.
Although it is not nice imo to change that current directory (actually I'd rather never change it while executing code), it will solve the problem quite easily; especially if you use it in the configuration part of your function with a persistent function handle:
function outputpars = myMainExecFunction(inputpars)
% configuration
persistent shadowfun;
if isempty(shadowfun)
funpath1 = 'C:\........\x\fun';
funpath2 = 'C:\........\y\fun'; % Shadowed
curcd = cd;
cd(funpath2);
shadowfun = #fun;
cd(curcd); % and go back to the original cd
end
outputpars{1} = shadowfun(inputpars); % will use the shadowed function
oupputpars{2} = fun(inputparts); % will use the function highest on the matlab path
end
This problem was also discussed here as a possible solution to this problem.
I believe it actually is the only way to overload a builtin function outside the source directory of the overloading function (eg. you want to run your own sum.m in a directory other than where your sum.m is located.)
EDIT: Old answer no longer good
The run command won't work because its a function, not a script.
Instead, your best approach would be honestly just figure out which of the functions need to be run, get the current dir, change it to the one your function is in, run it, and then change back to your start dir.
This approach, while not perfect, seems MUCH easier to code, to read, and less prone to breaking. And it requires no changing of names or creating extra files or function handles.

'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!