Modifying Lua arguments in C function - c

A Lua script is using one of my C defined functions as bellow:
function lua_func()
local var = 5
-- Do some stuff here, possibly using var.
c_func(var)
-- Do other stuff here, that must not use var.
end
This C function takes an argument that the caller has created and does what it needs.
This argument to the C function must be of single-use, i.e. after the C function has used it, I don't want it to be accessible any more to the rest of the Lua script.
I am looking for a way for the C function to "consume" this argument. To use it, and then set it to nil, so it is no longer usable.
Is this possible, and if so how?

Variant 1:
function lua_func()
do
local var = 5
-- Do some stuff here, possibly using var.
c_func(var)
end
-- Do other stuff here, that must not use var.
end
Variant 2:
function lua_func()
local var_container = {5}
-- Do some stuff here, possibly using var.
c_func(var_container) -- it assigns nil to var_container[1] before exit
-- Do other stuff here, that must not use var.
end
Variant 3:
function lua_func()
local var = 5
local destructor = function() var = nil end
-- Do some stuff here, possibly using var.
c_func(var, destructor) -- it invokes destructor() before exit
-- Do other stuff here, that must not use var.
end

Related

Array allocation in julia closure

I wonder is it a good idea to allocate temporary arrays in let-block, which wraps some function?
Some toy example: instead of
function foo(x)
y = zeros(100)
for i in 1 : 100
y[i] = 2*x[i] - 1
end
do_something(y)
end
I will write something like:
let
const y = zeros(100) # otherwise foo will be type-unstable due to 'global' y
function foo(x)
for i in 1 : 100
y[i] = 2*x[i] - 1
end
do_something(y)
end
end
It can be easily checked via #benchmark macro that in the second case memory for y-array will be allocated only once, which significantly improves performance (in my not-toy case). I'm wondering is it a "julian-way" to do such things?
I will give you an answer for Julia 1.0. For earlier versions of Julia the situation would be a bit different.
Point 1. Your code with let will not run under Julia 1.0 as let creates local scope and in local scope you are not allowed to use const.
Point 2. It is fully OK to do something like this in global scope:
const y = zeros(100) # otherwise foo will be type-unstable due to 'global' y
function foo(x)
for i in 1 : 100
y[i] = 2*x[i] - 1
end
do_something(y)
end
and you will have good performance as Julia 1.0 knows that y has constant type and will optimize it. The consequence is that you will have y in global scope and foo in methods table (i.e. you can call foo using its name).
Point 3. You can also use let block like this:
const foo = let y = zeros(100)
function inner_foo(x)
for i in 1 : 100
y[i] = 2*x[i] - 1
end
do_something(y)
end
end
This time y is defined only in local scope and does not leak out to global scope. Also inner_foo is not defined in global scope therefore you have to assign the return value of let block to a variable foo that then can be used to make calls (I make it a const to improve performance if it gets used in some functions later on)
Point 4. Note, however, that this almost identical code will not be as good, as Julia 1.0 has problems with type inference of variable y (hopefully this will be fixed in the future)
const foo = let
y = zeros(100)
function inner_foo(x)
for i in 1 : 100
y[i] = 2*x[i] - 1
end
do_something(y)
end
end
In summary: the decision if you use let block depends mostly on what you have to be visible in global scope (as what is defined in let is not visible in global scope) and if you use let block it is best to define variables you want to use as a part of let block definition.

Overriding assignment of value in Lua

I am using Lua v5.2.2 within a C application (embedded environment/MCU).
I need to expose some "parameters" in Lua, that for reading and writing you need to directly access the hardware (thus a C call is needed). I am looking however for other means to implement this than using plain old getters and setters.
I am mostly exploring the meta-programming power of Lua, but also I believe I can create a simpler interface for the user.
What I want to achieve is behaviour like the following:
my_param = createParameter{name="hw_param1", type="number", min=0, max=100}
my_param = 5
result = my_param + 3
On the first line a new parameter is created. This is a call towards a C function. Userdata is pushed to stack with a properly initialized struct. The hardware is also initialized as needed. A new table is returned.
On the second line an assignment is done to the parameter object. I want this to call a C function with a single argument (that of the assignment), so the value can be stored to the hardware registers.
On the third line the parameter is read. I again need a call towards a C function that will get the value of the parameter from the hardware registers, and that will return the result.
Note that the actual value of this parameter may change outside the scope of Lua, so reading the value once during initialization is not correct. The C function must be called each time to get the actual value. Similarly writing to the value must cause an immediate write to the hardware.
How can I accomplish this? Specifically can I alter the metatable of the parameter to achieve lines 2 and 3? (I am aware of how to implement line 1).
Also is it necessary to return a table from the constructor? May I, for example, return a primitive Lua type (e.g. a number) that will behave like above?
Yes, you can modify the metatable metamethods.
Line 2 would completely change the variable's value that it holds.
However, if you were to set a field in the parameter object like: my_param.x = n, the __newindex metamethod would get invoked; which you could overwrite the metamethod to behave as you would like. In your case you would make it set the parameter's field and update it with a C function call.
Regarding line 3, same principle applies, instead this time you would just use the __add metamethod, and manipulate the object when __add is invoked.
http://lua-users.org/wiki/MetamethodsTutorial
This isn't exactly what you're asking for, but it's close:
function createParameter(t)
param = {}
param.data = t
backingTable = {}
metatable = {}
function metatable.__index(t, k)
-- You can intercept the value here if you
-- want and pass it on to your C fuction.
return backingTable[k]
end
function metatable.__newindex(t, k, v)
-- You can intercept the value here if you
-- want and pass it on to your C fuction.
backingTable[k] = v
end
setmetatable(param, metatable)
return param
end
--------------------------------------------------------
my_param = createParameter{name="hw_param1", type="number", min=0, max=100}
my_param.value = 5
result = my_param.value + 3
print(result) -- prints 8
print(my_param.data.name) -- prints hw_param1
You might be able to do something tricky by assigning a metatable to the global table _G, but I think that would be kind of tricky to get set up right and could lead to unexpected outcomes.
Edit:
If you really hate having to have a level of indirection, and you really want to be able to set it directly, here's how you can do it by setting the global table.
globalMetatable = {}
globalParamNames = {}
globalParams = {}
function globalMetatable.__index(t, k)
if globalParamNames[k] then
-- You can intercept the value here if you
-- want and pass it on to your C fuction.
print("Read from param " .. k)
return globalParams[k]
else
rawget(_G, k)
end
end
function globalMetatable.__newindex(t, k, v)
if globalParamNames[k] then
-- You can intercept the value here if you
-- want and pass it on to your C fuction.
print("Wrote to param " .. k)
globalParams[k] = v
else
rawset(_G, k, v)
end
end
setmetatable(_G, globalMetatable)
function createParameter(t)
globalParamNames[t.varname] = true
end
--------------------------------------------------------
createParameter{varname="my_param", name="hw_param1", type="number", min=0, max=100}
my_param = 5
result = my_param + 3
print(result) -- prints 8
print(my_param) -- prints 5

Using eval in Julia to deal with varargs

I have just started using Julia. I am trying to use eval (in Julia) in order to define a set of variables in a function. Let's say I want to set v1 equal to 2:
function fun_test(varargs...)
v1 = 0;
if length(varargs) > 0
j = collect(linspace(1,length(varargs)-1,length(varargs)/2));
for i in j
expr_vargs = parse("$(varargs[i]) = $(varargs[i+1]);");
eval(expr_vargs);
end
end
println(v1)
end
Calling the function as:
fun_test("v1", "2");
It doesn't work, since println returns 0 (the initial value of v1). However, if I run an analogous eval call in the Julia's terminal, then it works.
Could you please clarify why it doesn't work and how to fix it?
eval runs in toplevel scope, not in function scope. It is not possible to dynamically update bindings in function scope. Without knowing your precise use case, I suspect there is a way to do things without dynamic rebinding. In particular, v1, v2, etc. is probably best made into an array, V.
Nevertheless, if you really must, you can always define v1 as a global variable in a submodule:
module FunTest
v1 = 0
function fun_test(varargs...)
if length(varargs) > 0
j = collect(linspace(1,length(varargs)-1,length(varargs)/2));
for i in j
#eval $(varargs[i]) = $(varargs[i+1])
end
end
println(v1)
end
export fun_test
end
using .FunTest
fun_test(:v1, 2) # result: 2
(I have also modified your code to avoid parseing strings, which is best done through expression interpolation.)

Defining Table or Array name as name from Previously Defined String in Matlab

So I would like to optimize my code such that I can look through an array such as
{'one','two','three'}
and create corresponding variables defined as tables or arrays
such as
one = table()
two = table()
three = table()
I am aware of the eval function however I would like to use this function in a loop s.t I allocate values to the new variable right after i create it
If I am understanding your question properly, given a cell array consisting only of strings, you wish to create variables in your workspace where each variable is declared as a string using the names from this cell array.
You could use eval, but I'm going to recommend something other than eval. eval should be avoided and instead of iterating those reasons, you can read Loren Shure's article on eval.
In any case, I would recommend you place these variables as dynamic fields inside a structure instead. Do something like this:
s = struct()
strs = {'one', 'two', 'three'};
for idx = 1 : numel(strs)
s.(strs{idx}) = table();
end
In this case, s would be a structure, and you can access the variable by the dot operator. In this case, you can access the corresponding variables by:
d = s.one; %// or
d2 = s.two; %// or
d3 = s.three;
If you want to place this into a function per se, you can place this into a function like so:
function [s] = createVariables(strs)
s = struct();
for idx = 1 : numel(strs)
s.(strs{idx}) = table();
end
This function will take in a cell array of strings, and outputs a structure that contains fields that correspond to the cell array of strings you put in. As such, you'd call it like so:
strs = {'one', 'two', 'three'};
s = createVariables(strs);
However, if you really really... I mean really... want to use eval, you can create your workspace variables like so:
strs = {'one', 'two', 'three'};
for idx = 1 : numel(strs)
eval([strs{idx} ' = table();']);
end
To place this into a function, do:
function [] = createVariables(strs)
for idx = 1 : numel(strs)
eval([strs{idx} ' = table();']);
end
However, be warned that if you run the function above, these variables will only be defined in the scope that the function was run in. You will not see these variables when the function exits. If you want to run a function so that the variables get defined in the workspace after you run the function, then eval is not the right solution for you. You should thus stick with the dynamic field approach that I talked about at the beginning of this post.
In any case, this will create one, two and three as workspace variables that are initialized to empty tables. However, I will argue with you that the first line of code is easier to read than the second piece of code, which is one of the main arguing points as to why eval should be avoided. If you stare at the second piece of code long enough, then you can certainly see what we're trying to achieve, but if you read the first piece of code, you can ascertain its purpose more clearly.

Classic asp: Function call by reference doesn't work with an array

I have an array witch I pass to a function by reference to sort it. However, seems like the array is passed byval. Can anyone solve what's the problem? (Also sort workarounds accepted)
1) The script below passes an array by-reference to the sort function.
2) Sort function outputs the sorted array values.
3) The script outputs the sorted array values. However they are not sorted.
The script outputs:
300,200,100,,
100,200,300,
'declare variables
mitta(1) = 1
mitta(2) = 2
mitta(3) = 3
sort(mitta) ' see the function below
' show variables
For i = 1 To 3
response.write mitta(i) & ","
next
' sort function
function sort(byref a)
dim num,i,j,temp
num = ubound(a)+1
For i = 0 To num - 1
For j = i + 1 To num - 1
If a(i) < a(j) Then
temp = a(i)
a(i) = a(j)
a(j) = temp
End If
Next
Next
' show sorted variables
For i = 0 To num - 1
response.write a(i) & ","
a(i) = 0
next
end function
By wrapping mitta in parentheses in the function call sort(mitta), you're actually passing it by value, despite the function declaration. From http://blogs.msdn.com/b/ericlippert/archive/2003/09/15/52996.aspx:
The rules are
3.1) An argument list for a function call with an assignment to the
returned value must be surrounded by
parens: Result = MyFunc(MyArg)
3.2) An argument list for a subroutine call (or a function call with no
assignment) that uses the Call keyword
must be surrounded by parens: Call
MySub(MyArg)
3.3) If 3.1 and 3.2 do not apply then the list must NOT be surrounded by
parens.
And finally there is the byref rule:
arguments are passed byref when
possible but if there are “extra”
parens around a variable then the
variable is passed byval, not byref.
Now it should be clear why the
statement MySub(MyArg) is legal but
MyOtherSub(MyArg1, MyArg2) is not. The
first case appears to be a subroutine
call with parens around the argument
list, but that would violate rule 3.3.
Then why is it legal? In fact it is a
subroutine call with no parens around
the arg list, but parens around the
first argument! This passes the
argument by value. The second case is
a clear violation of rule 3.3, and
there is no way to make it legal, so
we give an error.
See also the MSDN reference for ByRef and ByVal Parameters. Instead, you should call sort either with:
sort mitta
or:
Call sort(mitta)
call sort(mitta)
That's it, just add the keyword call. Complete reference is available here.
BTW, your code has problems. The arrays are 0 based.
When you pass an object as parameter, you are passing a pointer to the object, not the object itself (this apply to all languages I know). So it does not matter if you pass it ByVal or ByRef, because by definition you are always passing a pointer (a reference to the object)

Resources