Behavior of load() when chunk function returns nil - lua

From the Lua 5.1 documentation for load():
Loads a chunk using function func to get its pieces. Each call to func must return a string that concatenates with previous results. A return of an empty string, nil, or no value signals the end of the chunk.
From my testing, this is not actually true. Or, rather, the documentation is at a minimum misleading.
Consider this example script:
function make_loader(return_at)
local x = 0
return function()
x = x + 1
if x == return_at then return 'return true' end
return nil
end
end
x = 0
repeat
x = x + 1
until not load(make_loader(x))()
print(x)
The output is the number of successive calls to the function returned by make_loader() that returned nil before load() gives up and returns a function returning nothing.
One would expect the output here to be "1" if the documentation is to be taken at face value. However, the output is "3". This implies that the argument to load() is called until it returns nil three times before load() gives up.
On the other hand, if the chunk function returns a string immediately and then nil on subsequent calls, it only takes one nil to stop loading:
function make_loader()
local x = 0
return {
fn=function()
x = x + 1
if x == 1 then return 'return true' end
return nil
end,
get_x=function() return x end
}
end
loader = make_loader()
load(loader.fn)
print(loader.get_x())
This prints "2" as I would expect.
So my question is: is the documentation wrong? Is this behavior desirable for some reason? Is this simply a bug in load()? (It seems to appear intentional, but I cannot find any documentation explaining why.)

This is a bug in 5.1. It has been corrected in 5.2, but we failed to incorporate the correction in 5.1.

I get slightly different results from yours, but they are still not quite what the documentation implies:
function make_loader(return_at)
local x = 0
return function()
x = x + 1
print("make_loader", return_at, x)
if x == return_at then return 'return true' end
return nil
end
end
for i = 1, 4 do
load(make_loader(i))
end
This returns the following results:
make_loader 1 1
make_loader 1 2
make_loader 2 1
make_loader 2 2
make_loader 2 3
make_loader 3 1
make_loader 3 2
make_loader 4 1
make_loader 4 2
For 1 it's called two times because the first one was return true and the second one nil. For 2 it's called three times because the first one was nil, then return true, and then nil again. For all other values it's called two times: it seems like the very first nil is ignored and the function is called at least once more.
If that's indeed the case, the documentation needs to reflect that. I looked at the source code, but didn't see anything that could explain why the first returned nil is ignored (I also tested with empty string and no value with the same result).

Related

Lua math.random explain

sorry for asking this question but I couldn't understand it
-- but i don't understand this code
ballDX = math.random(2) == 1 and 100 or -100
--here ballDY will give value between -50 to 50
ballDY = math.random(-50, 50)
I don't understand the structure what is (2) and why it's == 1
Thank you a lot
math.random(x) will randomly return an integer between 1 and x.
So math.random(2) will randomly return 1 or 2.
If it returns 1 (== 1), ballDX will be set to 100.
If it returns 2 (~= 1), ballDX will be set to -100.
A simple way to make a 50-50 chance.
That is a very common way of assigning variables in Lua based on conditionals. It’s the same you’d do, for example, in Python with “foo = a if x else b”:
The first function, math.random(2), returns either 1 or 2. So, if it returns 1 the part math.random(2) == 1 is true and so you assign 100 to the variable ballDX. Otherwise, assign -100 to it.
In lua
result = condition and first or second
basically means the same as
if condition and first ~= nil and first ~= false then
result = first
else
result = second
end
So in your case
if math.random(2) == 1 then
ballDX = 100
else
ballDX = -100
end
in other words, there is a 50/50 chance for ballDX to become 100 or -100
For a better understanding, a look at lua documentation helps a lot :
https://www.lua.org/pil/3.3.html
You can read:
The operator or returns its first argument if it is not false; otherwise, it returns its second argument:
So if the random number is 1 it will return the first argument (100) of the "or" otherwise it will return the second argument (-100).

What does this code mean (if v then return v end)?

So I have this piece of code and it is this:
do
local function index(n,m)
return n*(n+1)//2 + m
end
local binomtable = {}
function binom3(n,m)
if n<0 or m<0 or m>n then return 0 end
if n=0 or m=0 or m=n then return 1 end
local i = index(n,m)
local v = binomtable[i]
if v then return v end
v = binom3(n-1,m-1) + binom3(n-1,m)
binomtable[i] = v
return v
end
end
and I would like to know what
if v then return v end
means.
Thank you!
The short answer is that if v then return v end returns the value v if it is truthy, i.e., if it is neither false nor nil. Otherwise the function continues by calculating a value for v, storing that value in binomtable, and finally returning it. The more interesting question is, why is the function doing all of this?
In the posted code, binom3 is a recursive function. With the recursive calls v = binom3(n-1,m-1) + binom3(n-1,m) there will be a lot of duplication of effort, meaning a lot of wasted space and time. Consider:
binom3(4, 2)
--> binom3(3, 1) + binom3(3, 2)
--> binom3(2, 0) + binom3(2, 1) + binom3(2, 1) + binom3(2, 2)
--> 1 + binom3(1, 0) + binom3(1, 1) + binom3(1, 0) + binom3(1, 1) + 1
Note how in the second reduction there are two identical terms:
binom3(2, 1) + binom3(2, 1)
There is no reason to calculate the term binom3(2, 1) twice, and doing so means that the pair of terms:
binom3(1, 0) + binom3(1, 1)
also must be calculated twice, as seen in the third reduction. It would be smart to calculate binom3(2, 1) only once, and to save the result for later use in the larger calculation. When m and n are larger and the number of calculations explodes exponentially this becomes a very important issue for performance both in the amount of memory required and in the amount of time required.
The posted code is using memoization to improve performance. When a calculation is made, it is stored in the table binomtable. Before any calculation is made, binomtable is consulted. First, v is set to the value of binomtable[i]; if this value is any truthy value (any integer is a truthy in Lua), then that value is simply returned without the need for recursive calculation. Otherwise, if nil is returned (i.e., no value has yet been stored for the calculation), the function continues with a recursive calculation. After completing the calculation, the new value is stored in binomtable for use the next time it is needed. This strategy saves a lot of wasted computational effort, and can make a huge difference in the performance of such recursive algorithms.
For your specific question of what
if v then return v end
means, is that if v, a variable, is not nil or false it is to return the value of the v variable and stop executing that function.
--Similar
function myfunc(input)
local MyVar = "I am a string and am not nil!"
if MyVar then
return "hi"
else
return "hello"
end
print("I am not seen because I am unreachable code!")
end
if this function was called it would always return "hi" instead of "hello" because MyVar is true, because it has a value. Also the print function below that will never get called because it stops executing the function after a return is called.
Now for your codes case it is checking a table to see if it has an entry at a certain index and if it does it returns the value.

How can a Lua function return nil, even if the returned value is not nil inside the function?

I have created a function that (pseudo)randomly creates a table containing numbers. I then loop this function until at least correct result is found. As soon as I've confirmed that at least one such result exists, I stop the function and return the table.
When I create tables containing small values, there are no issues. However, once the random numbers grow to the range of hundreds, the function begins to return nil, even though the table is true the line before I return it.
local sort = table.sort
local random = math.random
local aMin, aMax = 8, 12
local bMin, bMax = 200, 2000
local function compare( a, b )
return a < b
end
local function getNumbers()
local valid = false
local numbers = {}
-- Generate a random length table, containing random number values.
for i = 1, random( aMin, aMax ) do
numbers[i] = random( bMin, bMax )
end
sort( numbers, compare )
-- See if a specific sequence of numbers exist in the table.
for i = 2, #numbers do
if numbers[i-1]+1 == numbers[i] or numbers[i-1] == numbers[i] then
-- Sequence found, so stop.
valid = true
break
end
end
for i = 1, #numbers-1 do
for j = i+1, #numbers do
if numbers[j] % numbers[i] == 0 and numbers[i] ~= 1 then
valid = true
break
end
end
end
if valid then
print( "Within function:", numbers )
return numbers
else
getNumbers()
end
end
local numbers = getNumbers()
print( "Outside function:", numbers )
This function, to my understanding, is supposed to loop infinitely until I find a valid sequence. The only way that the function can even end, according to my code, is if valid is true.
Sometimes, more often than not, with large numbers the function simply outputs a nil value to the outside of the function. What is going on here?
You're just doing getNumbers() to recurse instead of return getNumbers(). This means that if the recursion gets entered, the final returned value will be nil no matter what else happens.
In the else case of the if valid then, you are not returning anything. You only return anything in the valid case. In the else case, a recursive call may return something, but then you ignore that returned value. The print you see is corresponding to the return from the recursive call; it isn't making it out the original call.
You mean to return getNumbers().

How to put floating points in LUA [duplicate]

I'd like to format a number to look like 1,234 or 1,234,432 or 123,456,789, you get the idea. I tried doing this as follows:
function reformatint(i)
local length = string.len(i)
for v = 1, math.floor(length/3) do
for k = 1, 3 do
newint = string.sub(mystring, -k*v)
end
newint = ','..newint
end
return newint
end
As you can see, a failed attempt, my problem is that I can't figure out what the error is because the program I am running this in refuses to report an error back to me.
Here's a function that takes negative numbers, and fractional parts into account:
function format_int(number)
local i, j, minus, int, fraction = tostring(number):find('([-]?)(%d+)([.]?%d*)')
-- reverse the int-string and append a comma to all blocks of 3 digits
int = int:reverse():gsub("(%d%d%d)", "%1,")
-- reverse the int-string back remove an optional comma and put the
-- optional minus and fractional part back
return minus .. int:reverse():gsub("^,", "") .. fraction
end
assert(format_int(1234) == '1,234')
assert(format_int(1234567) == '1,234,567')
assert(format_int(123456789) == '123,456,789')
assert(format_int(123456789.1234) == '123,456,789.1234')
assert(format_int(-123456789.) == '-123,456,789')
assert(format_int(-123456789.1234) == '-123,456,789.1234')
assert(format_int('-123456789.1234') == '-123,456,789.1234')
print('All tests passed!')
Well, let's take this from the top down. First of all, it's failing because you've got a reference error:
...
for k = 1, 3 do
newint = string.sub(mystring, -k*v) -- What is 'mystring'?
end
...
Most likely you want i to be there, not mystring.
Second, while replacing mystring with i will fix the errors, it still won't work correctly.
> =reformatint(100)
,100
> =reformatint(1)
,000
That's obviously not right. It seems like what you're trying to do is go through the string, and build up the new string with the commas added. But there are a couple of problems...
function reformatint(i)
local length = string.len(i)
for v = 1, math.floor(length/3) do
for k = 1, 3 do -- What is this inner loop for?
newint = string.sub(mystring, -k*v) -- This chops off the end of
-- your string only
end
newint = ','..newint -- This will make your result have a ',' at
-- the beginning, no matter what
end
return newint
end
With some rework, you can get a function that work.
function reformatint(integer)
for i = 1, math.floor((string.len(integer)-1) / 3) do
integer = string.sub(integer, 1, -3*i-i) ..
',' ..
string.sub(integer, -3*i-i+1)
end
return integer
end
The function above seems to work correctly. However, it's fairly convoluted... Might want to make it more readable.
As a side note, a quick google search finds a function that has already been made for this:
function comma_value(amount)
local formatted = amount
while true do
formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2')
if (k==0) then
break
end
end
return formatted
end
You can do without loops:
function numWithCommas(n)
return tostring(math.floor(n)):reverse():gsub("(%d%d%d)","%1,")
:gsub(",(%-?)$","%1"):reverse()
end
assert(numWithCommas(100000) == "100,000")
assert(numWithCommas(100) == "100")
assert(numWithCommas(-100000) == "-100,000")
assert(numWithCommas(10000000) == "10,000,000")
assert(numWithCommas(10000000.00) == "10,000,000")
The second gsub is needed to avoid -,100 being generated.
I remember discussing about this in the LÖVE forums ... let me look for it...
Found it!
This will work with positive integers:
function reformatInt(i)
return tostring(i):reverse():gsub("%d%d%d", "%1,"):reverse():gsub("^,", "")
end
On the link above you may read details about implementation.

Strange table error in Lua

Okay, so I've got a strange problem with the following Lua code:
function quantizeNumber(i, step)
local d = i / step
d = round(d, 0)
return d*step
end
bar = {1, 2, 3, 4, 5}
local objects = {}
local foo = #bar * 3
for i=1, #foo do
objects[i] = bar[quantizeNumber(i, 3)]
end
print(#fontObjects)
After this code has been run, the length of objects should be 15, right? But no, it's 4. How is this working and what am I missing?
Thanks, Elliot Bonneville.
Yes it is 4.
From the Lua reference manual:
The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, n can be zero. For a regular array, with non-nil values from 1 to a given n, its length is exactly that n, the index of its last value. If the array has "holes" (that is, nil values between other non-nil values), then #t can be any of the indices that directly precedes a nil value (that is, it may consider any such nil value as the end of the array).
Let's modify the code to see what is in the table:
local objects = {}
local foo = #bar * 3
for i=1, foo do
objects[i] = bar[quantizeNumber(i, 3)]
print("At " .. i .. " the value is " .. (objects[i] and objects[i] or "nil"))
end
print(objects)
print(#objects)
When you run this you see that objects[4] is 3 but objects[5] is nil. Here is the output:
$ lua quantize.lua
At 1 the value is nil
At 2 the value is 3
At 3 the value is 3
At 4 the value is 3
At 5 the value is nil
At 6 the value is nil
At 7 the value is nil
At 8 the value is nil
At 9 the value is nil
At 10 the value is nil
At 11 the value is nil
At 12 the value is nil
At 13 the value is nil
At 14 the value is nil
At 15 the value is nil
table: 0x1001065f0
4
It is true that you filled in 15 slots of the table. However the # operator on tables, as defined by the reference manual, does not care about this. It simply looks for an index where the value is not nil, and whose following index is nil.
In this case, the index that satisfies this condition is 4.
That is why the answer is 4. It's just the way Lua is.
The nil can be seen as representing the end of an array. It's kind of like in C how a zero byte in the middle of a character array is actually the end of a string and the "string" is only those characters before it.
If your intent was to produce the table 1,1,1,2,2,2,3,3,3,4,4,4,5,5,5 then you will need to rewrite your quantize function as follows:
function quantizeNumber(i, step)
return math.ceil(i / step)
end
The function quantizeNumber is wrong. The function you're looking for is math.fmod:
objects[i] = bar[math.fmod(i, 3)]

Resources