the difference between loadstring and a normal function definition in Lua? - lua

I'm playing with Lua, following the link: https://www.lua.org/pil/8.html. And I got confused a bit...
> i = 100
> local i=3
> f=loadstring("i=i+1")
> print(i)
100
> g=function() i=i+1 end
> print(i)
100
> f()
> print(i)
101
> g()
> print(i)
102
I mean, why neither f nor g use the local i?

You already have an answer for that in one of your previous questions.
> local i=3
Since you are using Lua interpreter in interactive mode, the local i is only visible in the chunk I have quoted above. Hence, both f and g increase global i as they don't see local i from the chunk quoted.
Consider writing your Lua code to a file and then executing them via e.g.: lua file.lua.

Related

Do the const and close keywords in Lua actually do anything?

I was excited to learn that, as of Lua 5.4, Lua supports constant (const) and to-be-closed (close) variables! However, upon testing these keywords, they don't seem to do anything at all. I wrote the following code to sample the features to get a better grasp of their exact usage:
function f()
local const x = 3
print(x)
x = 2
print(x)
end
f()
function g()
local close x = {}
setmetatable(x, {__close = function() print("closed!") end})
end
g()
I titled the file constCheck.lua and ran it with lua constCheck.lua. The output is as follows:
3
2
I was expecting an error on my call to f(), or at least for it to print 3 twice, instead it seemed to reassign x with no issue at all. Further, I was expecting the call to g() to print out "closed!" when x left scope at the end of the function, but this did not happen. I can't find very many examples of these keywords' usage. Am I using them properly? Do they work?
Note: lua -v => Lua 5.4.0 Copyright (C) 1994-2020 Lua.org, PUC-Rio
This is <const> not const, and <close> not close
See https://lwn.net/Articles/826134/
do
local x <const> = 42
x = x+1
end
-- ERROR: attempt to assign to const variable 'x'
And some example https://github.com/lua/lua/blob/master/testes/code.lua#L11
local k0aux <const> = 0
https://github.com/lua/lua/blob/master/testes/files.lua#L128
local f <close> = assert(io.open(file, "w"))
From the Lua 5.4 Reference Manual : 3.3.7 - Local Declarations
Each variable name may be postfixed by an attribute ( a name between angle brackets):
attrib ::= [‘<’ Name ‘>’]
There are two possible attributes: const, which declares a constant
variable, that is, a variable that cannot be assigned to after its
initialization; and close, which declares a to-be-closed variable
So you would have to write local x <const> = 3 for example.
Your code local const x = 3 is equivalent to
local const = nil
x = 3
So you're actually creating a local nil value const and a global number value x.

In Lua Random number generation issue

We are performing task as Accept a number as the seed value for math.randomseed(), and generate a random integer (interval [1,6]) using math.random() during each iteration of a loop, and continue the loop till the number is 6.
For which we had written code as
i = io.read()
local count = 0
math.randomseed(i)
for x = 1, 4 do
value = math.random(1, 6)
print(value)
count = count + 1
end
print(count)
We failed to pass test because
Input (stdin)
Run as Custom Input
0
Your Output (stdout)
3
5
5
6
2
Expected Output
3
5
5
6
4
Please help us
OP code seems to be having loop problems. I encourage the OP to read the Lua documentation about Control Structures, where Lua's while, repeat until, and goto are described, as well as the following manual section about Lua's For Statement. It is difficult to write any program in any language without understanding the fundamental control structures of the language.
OP problem can be solved in a variety of ways.
Using for
-- for version
i = io.read()
math.randomseed(i)
local count
for i = 1, math.huge do
local value = math.random(1, 6)
print(value)
count = i
if value == 6 then break end
end
print(count)
Here math.huge is the largest representable number in Lua, typically the special value inf, making this effectively an infinite loop. The variable i keeps track of how many random numbers have been generated, but since i will not be visible outside of the loop, the count variable is needed to copy the value of i so that it can be printed at the end.
Using while
-- while version
i = io.read()
math.randomseed(i)
local value = math.random(1, 6)
local count = 1
while value < 6 do
print(value)
count = count + 1
value = math.random(1, 6)
end
print(value)
print(count)
Here the looping construct begins with a test, so a test value must be created before the loop begins. This means that the count must be initialized to 1 before the loop begins, and it also means that the call to math.random will be duplicated. Not pretty.
Using repeat until
-- repeat until version
i = io.read()
math.randomseed(i)
local count = 0
repeat
local value = math.random(1, 6)
print(value)
count = count + 1
until value == 6
print(count)
Here the test comes at the end of the loop construct. This allows the code to call math.random only once.
Using goto
-- goto version
i = io.read()
math.randomseed(i)
local count = 0
::loop::
local value = math.random(1, 6)
print(value)
count = count + 1
if value < 6 then goto loop end
print(count)
You probably should not use goto to solve this problem, but you can. You have to be careful with goto in Lua; you can't jump into a block, out of a function, or into the scope of a local variable.
As you can see, there are some subtleties to these looping constructs, and using them requires some familiarity with the details.
All four versions produce identical outputs for the same inputs:
$ lua loops.lua
42
2
5
3
2
2
4
6
7

attempt to compare nil with number stack traceback?

I'm playing with Lua following this link: https://www.lua.org/pil/4.2.html and get confused about a point.
Lua 5.2.4 Copyright (C) 1994-2015 Lua.org, PUC-Rio
> x=10
> local i=1
> while i<=x do
>> local x = i*2
>> print(x)
>> i=i+1
>> end
stdin:1: attempt to compare nil with number
stack traceback:
stdin:1: in main chunk
[C]: in ?
I guess this error message indicates that something is wrong with the expression while i<=x. Any comments are greatly appreciated.
EDIT: I just realize that it's probably because it does not work in a terminal.
It did not work out in an interactive terminal. Because local i=1 is understood by terminal as a chunk by itself once you hit enter. That is why the "attempt to compare nil with number" error; because i is not defined, i.e., nil in this case. To correct it, put the first two lines and the while loop inside of a do chuck as the following.
> do
>> x = 10
>> local i=1
>> while i<=x do
>> local x = i*2
>> print(x)
>> i = i+1
>> end
>> end
2
4
6
8
10
12
14
16
18
20
>
Actually the problem is in local i=1 try
> local i = 1
> print(i)
The problem is that when running the console, it seems that the line is a chunk and the variable is local inside that chunk.
you can fix that by using a global variable or you can do this
> local i = 1 do
>> print(i)
>> end
Which results in chunk structure like this [local i [print(i)]] therefore i can be accessed. Note also that local x = i*2 is valid since it is inside the while - do chunk.
Your code would also work correctly, if it was inside a Lua file.
I could reproduce the problem in Lua 5.3.4 as well.
If you read on in the Lua docs, chapter 4.2 – Local Variables and Blocks, you'll get to the sentence
Beware that this example will not work as expected if you enter it in interactive mode. The second line, local i = 1, is a complete chunk by itself.
This addresses exactly the issue in question. So it seems that the Lua interpreter has limited support for an outmost chunk (that is clearly present in a Lua file). But this behaviour seems to me acceptable and understandable in view of the compactness of language and interpreter.
So, when in interactive mode,
either leave out the local before variable i to make it work:
Lua 5.3.4 Copyright (C) 1994-2017 Lua.org, PUC-Rio
Lua>x=10
Lua>i=1
Lua>while i<=x do
...>local x=i*2
...>print(x)
...>i=i+1
...>end
or start enclose the whole by a block:
Lua 5.3.4 Copyright (C) 1994-2017 Lua.org, PUC-Rio
Lua>do
...>local x=10
...>local i=1
...>while i<=x do
...>local x=i*2
...>print(x)
...>i=i+1
...>end
...>end
Both options will produce to the regular (and expected) output:
2
4
6
8
10
12
14
16
18
20

Why does Lua loadstring() not work on the demo site?

I am trying to test out the Lua loadstring function.
This example is taken direction from the Lua documentation:
f = loadstring("i = i + 1")
However, when I try to run it at:
https://www.lua.org/cgi-bin/demo
I get the following error:
input:1: attempt to call a nil value (global 'loadstring')
loadstring is not available in Lua past version 5.1. The demo you linked is running Lua 5.3. You can prove this by running the program print(_VERSION).
In Lua 5.2 an later your code should use load, here is an example program you can run that loads a chunk from a string:
local f = load("return 2 + 2")
print(f())
It is Lua 5.4 and load is there.
Look...
tdump=[[for k,v in pairs(_G) do print(k,v) end]]
load(tdump)()
I think the Lua 5.4 CGI is cutted down of functions because of security reasons.
Look...
tdump=[[for k,v in pairs(_G.io) do print(k,v) end]]
load(tdump)()
...there is only: write()

Simulate parallelism in Lua

I am trying to use lua to prototype some parallel algorithm. With this I mean to write code in pure Lua, perform tests on it, debug it, etc. Then, when I am confident that it works, I can translate it to a true multithread library, or even to another language (e.g. OpenCL kenel). Obviously I am not concerned in any way with the performance of the prototype code.
I thought to use a coroutine that yield at each line, with some boilerplate to randomly select the next "Thread" to run. For example:
local function parallel_simulation(...)
local function_list = {...}
local coroutine_list = {}
local thread_number = #function_list
for i = 1, thread_number do
coroutine_list[i] = coroutine.create(function_list[i])
end
while 0 < thread_number do
local current = math.random(1, thread_number)
local worker = coroutine_list[current]
coroutine.resume(worker)
if 'dead' == coroutine.status(worker) then
thread_number = thread_number - 1
table.remove(coroutine_list, current)
end
end
end
----------------------------------------------------------
-- Usage example
local Y = coroutine.yield
local max = 3
local counter = 0
local retry = 99
local function increment()
Y() local c = counter
Y() while max > c do
Y() c = counter
Y() c = c + 1
Y() counter = c
Y() end
end
for i=1,retry do
counter = 0
parallel_simulation(increment, increment)
if max ~= counter then
print('Test SUCCESS ! A non-thread-safe algorithm was identified .', i, counter)
return
end
end
error('Test FAIL ! The non-thread-safe algorithm was not identified .')
This is just an idea, any solution involving pure Lua is welcome! What makes me very uncomfortable with this solution, are all that Y(). Is there any way to avoid them? (debug.sethook does not allow to yield...)
EDIT 1 - More meaningful example was provided
EDIT 2 - Hopefully, I clearified what I am trying to accomplish
A simple alternative to putting Y() in front of each line is to use gsub and load:
Y = coroutine.yield
max = 3
counter = 0
code = [[
function increment()
local c = counter
while max > c do
c = counter
c = c + 1
counter = c
end
end]]
code = code:gsub("\n ", "\n Y() ") -- replace two spaces in find/replace with whatever tab character(s) you use
assert(load(code))()
local retry = 99
-- rest of code here
(Use load or loadstring depending on your Lua version)
Note that the variable declarations Y/max/counter must be global or else the loaded function will not have access to them. Similarly, the function in code must be global or else increment will not exist outside the loaded code.
Such a solution assumes that all instructions on each line are atomic/thread-safe, of course.
An improvement I would recommend making to parallel_simulation is to add some way of changing how the next thread is chosen. ex, perhaps the error will only be revealed if one of the threads is early on in execution and another one is almost done - though this state could theoretically be reached through sufficient random trials, having an argument that allows you to adjust which threads are more likely to be chosen next (ex using weights) should make it much more likely.

Resources