How to idiomatically support closing values with pairs()? - loops

I'm new to Lua (language version 5.4 if it matters, there doesn't seem to be a tag for that version on SO yet) and I'm trying to find the most idiomatic way to implement iteration (for loop) over a userdata object.
The Lua 5.4 Reference Manual says regarding a loop statement for var_1, ยทยทยท, var_n in explist do body end:
The loop starts by evaluating explist to produce four values: an iterator function, a state, an initial value for the control variable, and a closing value.
The idiomatic way to loop seems to be using the pairs(t) function. This also works for userdata via the __pairs metamethod. However:
If t has a metamethod __pairs, calls it with t as argument and returns the first three results from the call.
Why only three instead of four? If I have a complex userdata object that needs to allocate some resource for a loop, I'll need that closing value so I know when to deallocate that resource in case the loop ends early, right? Does that mean I cannot use pairs in such a case or am I missing something?
I could of course provide a new function, say pairs4, but that doesn't seem to be very idiomatic.

Because that's how it has always worked since at least Lua 5.0. pairs always returned 3 values because for previously only took 3 values.
"to-be-closed variables" are a new feature of Lua 5.4, as is the fourth value for generic for. Why pairs wasn't updated to match is unknown. It is possible that pairs returns all of the values from the __pairs metamethod, but I haven't looked at the implementation to verify this.
In this case, I would suggest writing a pairs_close that returns 4 arguments from the __pairs metamethod.

Related

How do I get my Julia code to assign the scalar value of a variable to an array without changing it as they variable mutates later on?

For my simulation, I have a field that is called particle.current_theta. When this field is a single variable, I assign it a new value that is called just "theta" on my line 177. This theta has its value changed further down within my code, on lines 202 and 206. I want what I have printed in my terminal as tree_theta and current_theta to be very similar to each other but not quite identical (This part of the code basically detects whether or not my particle is entering or exiting a region). You can see all this in the image below:
Now, I need to make the field I have called particle.current_theta a [1x1] array, and assign the entry in my [1x1] array the "theta" value, as usual. However, simply making particle.current_theta a [1x1] array radically changes its value within the terminal and causes my simulation to break. You can see how the value for particle.theta (printed in terminal as "current theta") is now drastically different in the code below:
I suspect that making particle.currenttheta an array is making it mutate whenever theta is changed in some of those lines below. How do I prevent that from happening, and get results that are identical to using just a single variable. To be precise, I want particle.current_theta to save the numerical information that theta has at line 177 of code but not be changed afterwards. Because of the large size of my code now and the function calls within function calls, it would be infeasible for me to be able to create a mwe that replicates this issue. However, all help and advice is appreciated, and I will respond to and clarify any questions that people may have.
If theta is a scalar (and it appears to be), then it's unlikely that changing its value is what is changing particle.currenttheta. What is more likely is that you're passing the currenttheta to some function, and changing the value of the passed argument inside the function. Julia arrays are passed to functions "by reference", in the sense that a copy is not made, and instead any changes made inside the function change the original array. When you had currenttheta as a scalar (which are passed "by value" instead), when you pass that to a function, changes made inside the function do not affect the original currenttheta's value.
So if you're passing currenttheta to a function somewhere and don't want it to be modified inside the function, pass copy(particle.currenttheta) in that call instead.
If you're not doing that, or that doesn't solve the problem, we need more of the code to figure out where the change might actually be happening. If not the whole of it, at least the parts that handle currenttheta, and the parts that print it. (Also, it would massively help with clarity if you would use consistent names in the output. Sometimes it's treetheta and current theta, other times it's theta and particle.currentheta, and it's not clear where these are being printed from and what the difference - if any - is.)

Remove all numbers from a string using LAMBDA recursive function

I've been following the guide on Exceljet for how to create a recursive LAMBDA function that removes all numbers from a string. For example, A1B2C3D4E5 becomes ABCDE.
The only thing I wanted differently was to have the string containing the character omissions stored inside the function rather than the cell. So, I took away the chars parameter from the opening line and used the LET function to store the string.
The problem is I keep getting a #VALUE! error and can't work out why.
=LAMBDA(str,sub,
LET(chars,"0123456789",
IF(chars="",str,
ReplaceChars(
SUBSTITUTE(str,LEFT(chars),sub),
MID(chars,2,LEN(chars)-1),
sub
)
)
))
A nested LET() in a recursive LAMBDA() is going to be troublesome since every time you'd use the variable in the recursion you'd start from scratch. Replacing characters will therefor never stop (if my interpretation of this is correct). But in your case you don't even need to make a recursive LAMBDA() to replace numbers, for example:
=LAMBDA(str,LET(X,MID(str,SEQUENCE(LEN(str)),1),CONCAT(IF(ISNUMBER(X*1),"",X))))
Core of this function is now:
=LET(X,MID(A1,SEQUENCE(LEN(A1)),1),CONCAT(IF(ISNUMBER(X*1),"",X)))
which can be used outside of LAMBDA() just fine. We can even replace this with
=LET(X,MID(A1,SEQUENCE(LEN(A1)),1),CONCAT(IF(ISNUMBER(FIND(X,"0123456789")),"",X)))
to do the same thing with any character you want to replace.
Now you can call =REPLACECHARS(A1). However, IMHO the beauty of the use of variables is now lost and the original approach (for example here would have my personal preference.

Is it possible to track changes to a variable in MATLAB?

Say you have a recursive function that changes part of a global variable.
Eg. Global variable is a 3D array from 1 to 20 (i.e (:,:,20), and in one recursion (:,:,3) and (:,:,5) are changed, and in the next recursion (:,:,7) and (:,:,8) are changed. Is it possible to see when each value for one of the elements is created, so see that in the first recursion the 3rd and 5th element were assigned a value, and in the second recursion the 7th and 8th were?
There are a couple of ways I can think of.
Pass an extra argument to your function that acts as an accumulator and return this at the end. This is standard recursion practice if you're dealing with recursion so I won't explain further (though happy to if you ask). If you haven't dealt with accumulators before, then I'd avoid this as it's not the simplest concept to wrap your head around.
Append to a global variable from inside your function that acts as a counter and keeps track of what you want it to.
Alternatively, create a persistent variable inside your function to act as the counter instead. You can either return this all the way back to the first call (as you would with an accumulator), or use it to update a global variable outside your function.
You can avoid globals if you're happy to make your recursive function a closure returned by a generator function, such that it has state relating to your counter variable.
Happy to expand on any of the above.

Variant array passed from UserForm to Module in VBA is null/empty

I have a UserForm with a ListBox for the user to select values. Those values are populated in UserForm_Initialize() via a function call to the base module, which returns an array as variant. This works without problems.
If the user selects some values and presses a button, the buttons Click event calls another function in the base module to pass on the user-entered array and compute things. This does not work at all. The value received in the base module is always nonexistent (not even null, but I don't know the correct VBA term, nothing is there at all).
Things I have tried so far:
Passing all arguments ByVal: Did not make a difference
Using global shared variables: This did work, but I don't want to rely on them if all I do is pass a single array to a single function. This also introduces state into the code which has to be managed, especially when reusing the function
Accessing the functions by full qualifiers: Did not make a difference. The functions are found and executed correctly, but the argument variables are empty, therefore the functions fail later on when doing the calculations.
My question is: How can I pass arrays from UserForms to Modules (not vice versa) without relying on global variables and without losing the array content?
This question may be related to this question about passing a String from Form to Module, but the accepted answer does not help in my case (using global variables).
When adding the code as requested in the comments, I stumbled upon that fact that I could print the content of the array, but it would not show anything in the debugger and the size would be 0.
The size issue was because I used Len(array) instead of Application.CountA(array) and I had a leftover On error resume next from earlier still in the code, which meant that no error was raised and size was always set to zero... This was the reason for the strange behaviour.

Using C variable inside Lua alongside nested functions

This is a sort of followup to my previous question about nested registered C functions found here:
Trying to call a function in Lua with nested tables
The previous question gave me the answer to adding a nested function like this:
dog.beagle.fetch()
I also would like to have variables at that level like:
dog.beagle.name
dog.beagle.microchipID
I want this string and number to be allocated in C and accessible by Lua. So, in C code, the variables might be defined as:
int microchipIDNumber;
char dogname[500];
The C variables need to be updated by assignments in Lua and its value needs to be retrieved by Lua when it is on the right of the equal sign. I have tried the __index and __newindex metamethod concept but everything I try seems to break down when I have 2 dots in the Lua path to the variable. I know I am probably making it more complicated with the 2 dots, but it makes the organization much easier to read in the Lua code. I also need to get an event for the assignment because I need to spin up some hardware when the microchipIDNumber value changes. I assume I can do this through the __newindex while I am setting the value.
Any ideas on how you would code the metatables and methods to accomplish the nesting? Could it be because my previous function declarations are confusing Lua?
The colon operator (:) in Lua is used only for functions. Consider the following example:
meta = {}
meta["__index"] = function(n,m) print(n) print(m) return m end
object = {}
setmetatable(object,meta)
print(object.foo)
The index function will simply print the two arguments it is passed and return the second one (which we will also print, because just doing object.foo is a syntax error). The output is going to be table: 0x153e6d0 foo foo with new lines. So __index gets the object in which we're looking up the variable and it's name. Now, if we replace object.foo with object:foo we get this:
input:5: function arguments expected near ')'
This is the because : in object:foo is syntactic sugar for object.foo(object), so Lua expects that you will provide arguments for a function call. If we did provide arguments (object:foo("bar")) we get this:
table: 0x222b3b0
foo
input:5: attempt to call method 'foo' (a string value)
So our __index function still gets called, but it is not passed the argument - Lua simply attemps to call the return value. So don't use : for members.
With that out of the way, let's look at how you can sync variables between Lua and C. This is actually quite involved and there are different ways to do it. One solution would be to use a combination of __index and __newindex. If you have a beagle structure in C, I'd recommend making these C functions and pushing them into the metatable of a Lua table as C-closures with a pointer to your C struct as an upvalue. Look at this for some info on lua_pushcclosure and this on closures in Lua in general.
If you don't have a single structure you can reference, it gets a lot more complicated, since you'll have to somehow store pairs variableName-variableLocation on the C side and know what type each is. You could maintain such a list in the actual Lua table, so dog.beagle would be a map of variable name to one or two something's. There a couple of options for this 'something'. First - one light user data (ie - a C pointer), but then you'll have the issue of figuring out what that is pointing to, so that you know what Lua type to push in for __index and what to pop out for __newindex . The other option is to push two functions/closures. You can make a C function for each type you'll have to handle (number, string, table, etc) and push the appropriate one for each variable, or make a uber-closure that takes a parameter what type it's being given and then just vary the up-values you push it with. In this case the __index and __newindex functions will simply lookup the appropriate function for a given variable name and call it, so it would be probably easiest to implement it in Lua.
In the case of two functions your dog.beagle might look something like this (not actual Lua syntax):
dog.beagle = {
__metatable = {
__index = function(table,key)
local getFunc = rawget(table,key).get
return getFunc(table,key)
end
__newindex = function(table,key,value)
local setFunc = rawget(table,key).set
setFunc(table,key,value)
end
}
"color" = {
"set" = *C function for setting color or closure with an upvalue to tell it's given a color*,
"get" = *C function for getting color or closure with an upvalue to tell it to return a color*
}
}
Notes about the above: 1.Don't set an object's __metatable field directly - it's used to hide the real metatable. Use setmetatable(object,metatable). 2. Notice the usage of rawget. We need it because otherwise trying to get a field of the object from within __index would be an infinite recursion. 3. You'll have to do a bit more error checking in the event rawget(table,key) returns nil, or if what it returns does not have get/set members.

Resources