I'm trying to learn the Lua language to develop plugins for my company's products. To help me learn (along with PiL book, Reference Manual, and numerous online resources), as I read I try to decipher current plugins we use.
One thing I've noticed is that local variables are listed at the very top and are not set to a specific value. For example: local SendVar and local EndVar.
But later on, many function's and local var's are used.
My question: I understand "Scope", global and local variables. But if there are no local function's within the plugin, are all local variables used within all functions?
I'm sorry for any confusion. But I'm trying to figure out how plugins are used within another program that uses other Lua plugins. I'm taking a wild guess when stating that unless local function's are otherwise stated, all local variables are used within that plugin file only.
Am I correct?
When in Lua you write a local statement, you are declaring that the following identifiers will denote local variables, whether or not those statements actually initializes the variables.
Moreover, local variables in Lua have block scope, i.e. they are visible in the block in which they are defined and in every enclosed block. Blocks are, for example, function bodies, then-end or else-end blocks, do-end blocks, etc.
Keep in mind, also, that variables in Lua don't have type, their value have.
-- declares `a` as a local variable (having no value, i.e. `nil` value)
local a
-- declares `b` as a local variable having 2 as value
local b = 2
-- declares `f` as local var having a function as value
local f = function(x) return x * x end
do
-- `a`, `b` and `f` are visible here, because this is a block enclosed
-- in the block where those vars were declared
local aa = 2
end
-- `aa` is not visible here, because it was declared in an inner block
Related
MEX is the framework Matlab uses to run C/C++ functions in Matlab (runs faster). In the documentation it says:
input parameters (found in the prhs array) are read-only; do not modify them in your MEX file. Changing data in an input parameter can produce undesired side effects.
Is this simply a warning about how changing a variable passed as a pointer will change that variable even outside of the function (unlike how Matlab works), or is there a more subtle way that this can mess up the Matlab/MEX interface?
Reason I am asking is I specifically want the MEX function to modify the arguments for real.
MATLAB uses lazy copying, which means that when you do b = a, variable b points to the same data as variable a, even though semantically you made a copy. When you now do a(1) = 0, for example, you modify variable a, and MATLAB first makes a copy, so that variable b is not affected by the assignment. This obviously saves a lot of memory, because many copies are made where the copy is not modified.
For example, when calling a function, a copy of input variables are placed in the function’s workspace. sum(a) causes a (lazy) copy of a to be made available inside the function. If the function doesn’t need to modify the variable, a copy is avoided. If it does modify it, then a copy is made so that a is not changed for the caller.
MEX-files work the same way, except that MATLAB cannot detect if you modify the input variable, so it cannot make the copy before you do. Hence the warning. You need to call mxDuplicateArray() to copy the array and make changes to your new copy.
The side effects that the documentation warns about is that the variable in the caller’s workspace is modified, along with all variables that it shares data with. For example imagine you make a MEX-file function modifyIn that modified the input, then:
a = zeros(500);
b = a;
% much later in the code…
modifyIn(b); % update b the way I want!
will very unexpectedly also modify a!
This blog post on Undocumented MATLAB talks about this issue in more detail, and talks about mxUnshareArray(), an undocumented function that you should only use if you are really comfortable with the possible crashes and other issues that could happen. Undocumented functions have a limited shelf life.
I would like to have a list of constants readily available to use in any script or function I write. For example, I have been defining constants like hbar (Planck's constant) at the start of any script that will be using it.
Instead of that, should I:
make a list of constants in a script and load that script every time
I want to use it,
or save constants in a workspace and load that,
or is it possible for me to have global variables that will be there even when I close and reopen Octave,
or something else?
If you use GNU Octave I would suggest using the miscellaneous package and the function physical_constant which already has 335 constants. In your case:
[val, uncertainty, unit] = physical_constant ("Planck constant over 2 pi")
val = 1.0546e-34
uncertainty = 4.7000e-42
unit = J s
If you want don't want this, then use functions, not global vars.
As you indicated, there are a few ways to solve this problem. To address your third option, which seems to be closest to the spirit of what you want, you've got at least two ways of handling this.
1.) If the variables need to be mutable. Create a function or script that initializes the variables to what you want them to be. I'm going to reference the MATLAB documentation but it should basically be the same.
function initglobals()
global the_answer
the_answer = 42;
end
Then any time you want to use these globals in a script, you first indicate to Octave that you'll be using the variable as a global:
...
global the_answer
disp(the_answer) %prints 42
...
For this to be more useful, I'd recommend generating a startup script and putting in your .octaverc docs. This startup script can call this function to initialize your globals.
2.) Your other choice, if the globals ought to be immutable (for example, a physics constant) is to define a function that returns the value you want.
function [out] = the_answer()
out = 42;
end
Then you can simply just use the_answer to access your constant.
In both cases you'll want to add these functions to your path. Create your collections of functions and put them somewhere, then add that location to your path. docs
Is it possible to retrieve a local variable from a programme-function i've run in matlab? i.e. i want to retrieve a variable from the code, which is not appeared in the outputs.
Thanks in advance
The following describes code to add to the function itself to make the variable available outside the local scope. When you can't change the function, from the outside there is nothing to be done about changing the scope of course (which is intended, correct behaviour!!).
Dirty ways:
global variables
global t
t=2.468;
For scalars, strings, simple values: assign to variables in base workspace using evalin:
t=2.468;
evalin('base', ['var_in_base=' num2str(t) ';']);
Any other variable, use assignin:
A=magic(20);
assignin('base','A',A);
Proper way:
Inspect them during debugging
If you really want them outside the local scope, add them as output variable!!
Look at Declare function. You can access local variables if you return them as return values. If you do not, you can't access them from outside.
So in
function [mean,stdev] = stat(x)
n = length(x);
mean = sum(x)/n;
stdev = sqrt(sum((x-mean).^2/n));
You have access to mean and stdev but there is no way to access n.
I don't know matlab at all, but from programmer's logic
that seems improper and impossible without hacking the code.
That being said, through Google I saw this:
When you call a script from a function, the script uses the function workspace.
Like local functions, nested functions have their own workspaces. However, these workspaces are unique in two significant ways:
Nested functions can access and modify variables in the workspaces of the functions that contain them.
All of the variables in nested functions or the functions that contain them must be explicitly defined. That is, you cannot call a function or script that assigns values to variables unless those variables already exist in the function workspace.
Base and Function Workspace
Not sure if this helps you at all, but it may clarify some points
Do you use
require "name"
or
local name = require "name"
Also, do you explicitly declare system modules as local variables? E.g.
local io = require "io"
Please explain your choice.
Programming in Lua 2ed says "if she prefers to use a shorter name for a module, she can set a local name for it" and nothing about local m = require "mod" being faster than require "mod". If there's no difference I'd rather use the cleaner require "mod" declaration and wouldn't bother writing declarations for pre-loaded system modules.
Either of them works. Storing it in a local will not change the fact that the module may have registered global functions.
Some libraries work only one way, and some only work the other way
The require "name" syntax was the one introduced in lua 5.1; as a note; this call does not always return the module; but it was expected a global would be created with the name of the library (so, you now have a _G.name to use the library with). eg, earlier versions of gsl-if you did local draw = require"draw" the local draw would contain true; and shadow the global draw created by the library.
The behaviour above is encouraged by the module function ==> now relatively deprecated, any well written new code will not use it.
The local name = require"name" syntax became preferred recently (about 2008?); when it was decided that modules setting any globals for you was a bad thing.
As a point: all my libraries do not set globals, and just return a table of functions; or in some other cases, they return an function that works as an initialiser for the root object.
tldr;
In new code, you should use the latter local name = require"name" syntax; it works in the vast majority of cases, but if you're working with some older modules, they may not support it, and you'll have to just use require"module".
To answer your added question:
do you require the system modules?: no; you just assume they are already required; but I do localise all functions I use (usually grouped into lines by the module they came from), including those from external libraries. This allows you to easily see which functions your code actually relies on; as well as removing all GETGLOBALs from your bytecode.
Edit: localising functions is now discouraged. To find accidental globals use a linter like luacheck
Sample module in (my) preferred style; will only work with the local name = require"name" syntax.
local my_lib = require"my_lib"
local function foo()
print("foo")
end
local function bar()
print("bar", my_lib.new())
end
return {
foo = foo;
bar = bar;
}
I would say it mainly boils down to what you prefer, but there are some exceptions depending on what you are writing. Creating a local reference will gain you some speed, but in most cases this isn't a meaningful optimization to do. You should also point your local to the function you are using and not the module table.
If you are writing on a library then I would recommend creating local references for all the global variables you use. Even if you aren’t using the module() function, which changes the global scope for the code that follows. The reason for this is that it prevents your library from calling globals which have been altered after the library was loaded.
Doing local io = require’io’ will ensure you that you get the table from package.loaded.io, even if _G.io has been replaced by another table. I generally don’t do this myself. I expect io to already be loaded and unmodified when I write Lua.
You also have to remember that there are several ways to write a Lua module. Some modules don't return their module table, while others don't create any global variable. The most common solution is to both create and return a global, but you can't always rely on this.
Ruby has this very interesting functionality in which when you create a class with 'Class.new' and assign it to a constant (uppercase), the language "magically" sets up the name of the class so it matches the constant.
# This is ruby code
MyRubyClass = Class.new(SuperClass)
puts MyRubyClass.name # "MyRubyClass"
It seems ruby "captures" the assignment and inserts sets the name on the anonymous class.
I'd like to know if there's a way to do something similar in Lua.
I've implemented my own class system, but for it to work I've got to specify the same name twice:
-- This is Lua code
MyLuaClass = class('MyLuaClass', SuperClass)
print(MyLuaClass.name) -- MyLuaClass
I'd like to get rid of that 'MyLuaClass' string. Is there any way to do this in Lua?
When assigning to global variables you can set a __newindex metamethod for the table of globals to catch assignments of class variables and do whatever is needed.
You can eliminate one of the mentions of MyLuaClass...
> function class(name,superclass) _G[name] = {superclass=superclass} end
> class('MyLuaClass',33)
> =MyLuaClass
table: 0x10010b900
> =MyLuaClass.superclass
33
>
Not really. Lua is not an object-orientated language. It can behave like one sometimes. But far from every time. Classes are not special values in Lua. A table has the value you put in it, no more. The best you can do is manually set the key in _G from the class function and eliminate having to take the return value.
I guess that if it REALLY, REALLY bothers you, you could use debug.traceback(), get a stack trace, find the calling file, and parse it to find the variable name. Then set that. But that's more than a little overkill.
With respect at least to Lua 5.2: You can capture assignments to A) the global table of a Lua State, as mentioned in a previous reply, and also B) to any other Lua Object whose __index and __newindex metamethods have been substituted (by replacing the metatable), this I can confirm as I'm currently using both these techniques to hook and redirect assignments made by Lua scripts to external C/C++ resource management.
There is a gotcha with regards to reading them back though, the trick is to NOT let the values be set in a Lua State.
As soon as they exist there, your hooks will fail to be called, so if you want to go down this path, you need to capture ALL get/set attempts, and NEVER store the values in a Lua State.