I would like to be able to have a chunk of Lua code (a "script") that could be shared among enemy types in a game but where each instance of a script gets a unique execution environment. To illustrate my problem, this is my first attempt at what a script might look like:
time_since_last_shoot = 0
tick = function(entity_id, dt)
time_since_last_shoot = time_since_last_shoot + dt
if time_since_last_shoot > 10 then
enemy = find_closest_enemy(entity_id)
shoot(entity_id, enemy)
time_since_last_shoot = 0
end
end
But that fails since I'd be sharing the global time_since_last_shoot variable among all my enemies. So then I tried this:
spawn = function(entity)
entity.time_since_last_shoot = 0;
end
tick = function(entity, dt)
entity.time_since_last_shoot = entity.time_since_last_shoot + dt
if entity.time_since_last_shoot > 10 then
enemy = find_closest_enemy(entity)
shoot(entity, enemy)
entity.time_since_last_shoot = 0
end
end
And then for each entity I create a unique table and then pass that as the first argument when I call the spawn and tick functions. And then somehow map that table back to an id at runtime. Which could work, but I have a couple concerns.
First, it's error prone. A script could still accidentally create global state that could lead to difficult to debug problems later in the same script or even others.
And second, since the update and tick functions are themselves global, I'll still run into issues when I go to create a second type of enemy which tries to use the same interface. I suppose I could solve that with some kind of naming convention but surely there's a better way to handle that.
I did find this question which seems to be asking the same thing, but the accepted answer is light on specifics and refers to a lua_setfenv function that isn't present in Lua 5.3. It seems that it was replaced by _ENV, unfortunately I'm not familiar enough with Lua to fully understand and/or translate the concept.
[edit] A third attempt based on the suggestion of #hugomg:
-- baddie.lua
baddie.spawn = function(self)
self.time_since_last_shoot = 0
end
baddie.tick = function(self, dt)
entity.time_since_last_shoot = entity.time_since_last_shoot + dt
if entity.time_since_last_shoot > 10 then
enemy = find_closest_enemy(entity)
shoot(entity, enemy)
entity.time_since_last_shoot = 0
end
end
And in C++ (using sol2):
// In game startup
sol::state lua;
sol::table global_entities = lua.create_named_table("global_entities");
// For each type of entity
sol::table baddie_prototype = lua.create_named_table("baddie_prototype");
lua.script_file("baddie.lua")
std::function<void(table, float)> tick = baddie_prototype.get<sol::function>("tick");
// When spawning a new instance of the enemy type
sol::table baddie_instance = all_entities.create("baddie_instance");
baddie_instance["entity_handle"] = new_unique_handle();
// During update
tick(baddie_instance, 0.1f);`
This works how I expected and I like the interface but I'm not sure if it follows the path of least surprise for someone who might be more familiar with Lua than I. Namely, my use of the implicit self parameter and my distinction between prototype/instance. Do I have the right idea or have I done something weird?
For your first issue (accidentally creating globals), you can rely on a linter like luacheck or a module that prevents you from creating globals like strict.lua from Penlight.
And then, why not just make things local? I mean both time_since_last_shoot and tick. This leverages closures, one of the most useful features of Lua. If you want different tick functions, each with its own variables, you can do something like this:
local function new_tick()
local time_since_last_shoot = 0
return function(entity_id, dt)
time_since_last_shoot = time_since_last_shoot + dt
if time_since_last_shoot > 10 then
local enemy = find_closest_enemy(entity_id)
shoot(entity_id, enemy)
time_since_last_shoot = 0
end
end
end
local tick_1 = new_tick()
local tick_2 = new_tick()
Of course, you could also use the environment for this, but here I think local variables and closure are a better solution to the problem.
The way _ENV works in 5.3 is that global variable are "syntactic" sugar for reading fields from the _ENV variable. For example, a program that does
local x = 10
y = 20
print(x + y)
is equivalent to
local x = 10
_ENV.y = 20
_ENV.print(x + _ENV.y)
By default, _ENV is a "global table" that works like you would expect global variables to behave. However, if you create a local variable (or function argument) named _ENV then in that variable's scope any unbound variables will point to this new environment instead of point to the usual global scope. For example, the following program prints 10:
local _ENV = {
x = 10,
print=print
}
-- the following line is equivalent to
-- _ENV.print(_ENV.x)
print(x)
In your program, one way to use this technique would be to add an extra parameter to your functions for the environment:
tick = function(_ENV, entity, dt)
-- ...
end
then, any global variables inside the function will actually just be accessing fields in the _ENV parameter instead of actually being global.
That said, I'm not sure _ENV is the best tool to solve your problem. For your first problem, of accidentally creating globals, a simpler solution would be to use a linter to warn you if you assign to an undeclared global variable. As for the second problem, you could just put the update and tick functions in a table instead of having them be global.
Related
I'm reviewing some toy examples from Lua and I found the following one over there with respect to environments:
M = {} -- the module
complex = {} -- global complex numbers registry
mt = {} --metatable for complex numbers
function new (r, i)
local cp = {}
cp = {r=r, i=i}
return setmetatable(cp,mt)
end
M.new = new -- add 'new' to the module
function M.op (...)
--Why does not it work?
local _ENV = complex
return ...
end
function M.add (c1, c2)
return new(c1.r + c2.r, c1.i + c2.i)
end
function M.tostring (c)
return string.format("(%g,%g)", c.r, c.i) --to avoid +-
end
mt.__tostring = M.tostring
mt.__add = M.add
complex.a = M.new(4,3)
complex.b = N.new(6,2)
--nil
M.op(a+b)
--It works
M,op(complex.a+complex.b)
The use of _ENV has no effect. However, if I use complex = _G, both lines work. How do set a local environment for M.op. I'm not asking for specific libraries, I just want to know why it does not work and how to fix it.
M.op(a+b)
This line doesn't do what you expect, because it uses values of a and b that are available when this method is called. It doesn't matter that you set _ENV value inside the method, as by the time the control gets there, the values referenced by a and b have already been retrieved and since both values are nil in your code, you probably get "attempt to perform arithmetic on global..." error.
how to fix it.
I'm not sure what exactly you want to fix, as you already reference the example that works. If you assign complex.a you can't assume that a will have the same value without mapping complex table to _ENV.
I have actually been wondering about this question for a long time, and I can recall reading something somewhere on the internet about loading all local variables into a table, but I could never find it again.
What I am wondering is if there is basically any way to dynamically create a local variable, similar to how you can dynamically create a global variable.
In Lua you can create dynamic global variables simply by saying:
local my_env = getfenv(1);
for i = 1, 10 do
my_env["OMG_DYNAMIC_GLOBAL_VARIABLE_"..i] = i * i;
end
But I have always wondered if there is a way to essentially do the same or a similar thing for local variables. Something like
for i = 1, 10 do
local["OMG_DYNAMIC_LOCAL_VARIABLE_"..i] = i * i;
end
would kind of be pseudo code for what I am trying to do.
As a second part to my question, I am wondering if there is any way to possibly iterate through every local variable in the current scope? I guess pseudo code for what I am trying to do would look something like:
local a = 123;
local b = 321;
LocalVars = {(local)}; --the table with the local variables in it.
for i,v in pairs(LocalVars) do print(i, v); end
I would appreciate any help regarding either part of my question.
Thanks
the table with the local variables in it
There is no table with local variables. Local variables do not exist in compiled Lua. There are simply locations on the Lua stack and/or upvalues. Even the names of local variables are lost during the compilation process.
Local variables are always static constructs of the Lua source code. They never exist within a table. If you need a non-static construct, use a table. That's what tables are for. That's (part of) why Lua globals are in a table.
I don't see the advantage of what you proposed over a regular local table except for syntactic sugar.
local locals = {}
locals.a = 123
locals.b = 321
for i,v in pairs(locals) do
print(i, v)
end
The syntax you proposed does not make the program clearer or easier to read in any way. In fact it even creates new problems. Does the following print c as well or does it not because it is in a nested local scope?
for i,v in pairs(LocalVars) do
local c = 1729
print(i, v)
end
How to define a variable(constant) in Lua and how to call it in other Lua script in Cocos2d-x?
In my way:
main.lua
local r = require("src/Square")
local constant= r:getConstant()
Square.lua
function Square:getConstant()
return 10
end
Are there any other more elegant way? Any suggestions will be appreciated.
You can make it a global variable:
constant = r:getConstant()
but the variable will not be constant. Lua does not know the concept of immutable/readonly/const variables.
There are tricks to use a Lua table's metatable to prevent the value from changing, though that requires the value to be in the table, and you can't prevent the table from being changed (ie set to nil or its metatable replaced).
Simply using a function that returns a constant value is the easier way to ensure const-ness of the value.
What I've also done in the past is to use a notation that marks constant values, for instance:
_constant = 10
local _localConstant = 11
The _ prefix denotes the variable as a constant. Alternatively an ALL-CAPS style analogue to #define macros works well if these are known constants in C/C++ or commonly known frameworks (ie DBL_EPSILON or M_PI_2). It is just a reminder for the programmer(s).
Lastly, there's the "const" table which is a global table defining some supposed-to-be constant values:
const = {thisIsTen = 10, thatIsEleven = 11}
Using the table makes it clear those are constants:
result = 100 * const.thisIsTen
If you're looking for a const(constant) value that's read-only and can not be changed, you'll need to make a function for it (Which you already have). You also have to know that lua gets returns of basic types (number, boolean, nil, string) by value not by reference (Only if you return them by creation).
Here's the replacement for your function:
square.lua
Square = {}
Square.__index = Square
local _const = 10
function Square:GetConst()
local const = _const
return const
end
-- Test function
function Square:MoveUp()
_const = _const + 2
end
return Square
main.lua
local sr = Require("src/Square")
print(sr:GetConst()) -- 10
local plus = sr:GetConst() + 4
print(sr:GetConst(), plus) -- 10 14
sr:MoveUp()
print(sr:GetConst()) -- 12
Also take a note that the Square can be changed into a local function(Recommended), so in that case there won't be any troubles with next times creation of object.
I just started with Lua as part of a school assignment. I'd like to know if there's an easy way to implement profiling for Lua? I need something that displays allocated memory, variables in use regardless of their type, etc.
I've been finding C++ solutions which I have been able to compile successfully but I don't know how to import them to the Lua environment.
I also found Shinny but I couldn't find any documentation about how to make it work.
There are several profilers available that you can check, but most of them target execution time (and are based on debug hook).
To track variables, you will need to use debug.getlocal and debug.getupvalue (from your code or from debug hook).
To track memory usage you can use collectgarbage(count) (probably after collectgarbage(collect)), but this only tells you total memory in use. To track individual data structures, you may need traverse global and local variables and calculate the amount of space they take. You can check this discussion for some pointers and implementation details.
Something like this would be the simplest profiler that tracks function calls/returns (note that you should not trust absolute numbers it generates, only relative ones):
local calls, total, this = {}, {}, {}
debug.sethook(function(event)
local i = debug.getinfo(2, "Sln")
if i.what ~= 'Lua' then return end
local func = i.name or (i.source..':'..i.linedefined)
if event == 'call' then
this[func] = os.clock()
else
local time = os.clock() - this[func]
total[func] = (total[func] or 0) + time
calls[func] = (calls[func] or 0) + 1
end
end, "cr")
-- the code to debug starts here
local function DoSomethingMore(x)
x = x / 2
end
local function DoSomething(x)
x = x + 1
if x % 2 then DoSomethingMore(x) end
end
for outer=1,100 do
for inner=1,1000 do
DoSomething(inner)
end
end
-- the code to debug ends here; reset the hook
debug.sethook()
-- print the results
for f,time in pairs(total) do
print(("Function %s took %.3f seconds after %d calls"):format(f, time, calls[f]))
end
I'm just getting started with Lua. In the example I'm learning from (the Ghosts & Monsters Corona open source), I see this pattern repeatedly.
local director = require("director")
local mainGroup = display.newGroup()
local function main()
mainGroup:insert(director.directorView)
openfeint = require ("openfeint")
openfeint.init( "App Key Here", "App Secret Here", "Ghosts vs. Monsters", "App ID Here" )
director:changeScene( "loadmainmenu" )
return true
end
main()
Is this some sort of convention experienced Lua programmers recommend or are there genuine advantages to doing it this way? Why wouldn't you just skip the function all together and do this:
local director = require("director")
local mainGroup = display.newGroup()
mainGroup:insert(director.directorView)
local openfeint = require ("openfeint")
openfeint.init( "App Key Here", "App Secret Here", "Ghosts vs. Monsters", "App ID Here" )
director:changeScene( "loadmainmenu" )
Is there some implicit benefit to the first style over the second? Thanks!
Is this some sort of convention experienced Lua programmers recommend or are there genuine advantages to doing it this way?
It's not typical. The advantage is that object state is private, but that's not enough of an advantage to recommend it.
I see this pattern repeatedly.
I've never seen it before, and it happens only once in the source you posted.
EDIT: Adding a response to a question asked in the comments below this post.
A function which accesses external local variables binds to those variables and is called a 'closure'. Lua (for historical reasons) refers to those bound variables as 'upvalues'. For example:
local function counter()
local i = 1
return function()
print(i)
i = i + 1
end
end
local a, b = counter(), counter()
a() a() a() b() --> 1 2 3 1
a and b are closures bound to different copies of i, as you can see from the output. In other words, you can think of a closure as function with it's own private state. You can use this to simulate objects:
function Point(x,y)
local p = {}
function p.getX() -- syntax sugar for p.getX = function()
return x
end
function p.setX(x_)
x = x_
end
-- for brevity, not implementing a setter/getter for y
return p
end
p1 = Point(10,20)
p1.setX(50)
print(p1.getX())
Point returns a table of closures, each bound to the locals x and y. The table doesn't contain the point's state, the closures themselves do, via their upvalues. An important point is that each time Point is called it creates new closures, which is not very efficient if you have large quantities of objects.
Another way of creating classes in Lua is to create functions that take a table as the first argument, with state being stored in the table:
function Point(x,y)
local p = {x=x,y=y}
function p:getX() -- syntax sugar for p.getX = function(self)
return self.x
end
function p:setX(x)
self.x = x
end
return p
end
p1 = Point(10,20)
p1:setX(50) -- syntax sugar for p1.setX(p1, 50)
print(p1:getX()) -- syntax sugar for p1.getX(p1)
So far, we're still creating new copies of each method, but now that we're not relying on upvalues for state, we can fix that:
PointClass = {}
function PointClass:getX() return self.x end
function PointClass:setX(x) self.x = x end
function Point(x,y)
return {
x = x,
y = y,
getX = PointClass.getX,
setX = PointClass.getY,
}
end
Now the methods are created once, and all Point instances share the same closures. An even better way of doing this is to use Lua's metaprogramming facility to make new Point instances automatically look in PointClass for methods not found in the instance itself:
PointClass = {}
PointClass.__index = PointClass -- metamethod
function PointClass:getX() return self.x end
function PointClass:setX(x) self.x = x end
function Point(x,y)
return setmetatable({x=x,y=y}, PointClass)
end
p1 = Point(10,20)
-- the p1 table does not itself contain a setX member, but p1 has a metatable, so
-- when an indexing operation fails, Lua will look in the metatable for an __index
-- metamethod. If that metamethod is a table, Lua will look for getX in that table,
-- resolving p1.setX to PointClass.setX.
p1:setX(50)
This is a more idiomatic way of creating classes in Lua. It's more memory efficient and more flexible (in particular, it makes it easy to implement inheritance).
I frequently write my own Lua scripts this way because it improves readability in this case:
function main()
helper1( helper2( arg[1] ) )
helper3()
end
function helper1( foo )
print( foo )
end
function helper2( bar )
return bar*bar
end
function helper3()
print( 'hello world!' )
end
main()
This way the "main" code is at the top, but I can still define the necessary global functions before it executes.
A simple trick, really. I can't think of any reason to do this besides readability.
The first style could be used too improove readability, but I would rather give the function some meaningful name instead of main or just go without the function.
By the way, I think it's always a good practice to name blocks of code, i.e. put them into functions or methods. It helps explain your intend with that piece of code, and encourages reuse.
I don't see much point to the first style as you've shown it. But if it said something like if arg then main() end at the bottom, the script might (just might) be useful as a loadable "library" in addition to being a standalone script. That said, having a main() like that smacks of C, not Lua; I think you're right to question it.