'When are functions assigned to a variable actually computed?
I'm doing some troubleshooting on a Lua function I wrote yesterday as part of a game development effort using the Love2D API. The function is designed to handle mob entities stepping around an obstruction in a tile-based roguelike type system with PG terrain. Code is below, though I'm not primarily looking for syntax help here, it's just for context. The troubleshooting raised an interesting question in my mind that I couldn't find the answer to in Lua's documentation.
For the curious, this particular function checks "left" and "right" of an obstruction for any given direction in a set of 8 directions, sees whether the square in that direction contains walkable terrain, and then walks onto it if so. If both directions are clear, it flips a coin. If both are blocked, it gives up (for now, for testing purposes).
I'm defining this inside of a (confirmed working) Entity class, hence all the "self" sugar. Move, canMove, and Wander are all also confirmed working methods of Entity.
ObstructionHandler = function(self, x_direction, y_direction)
local direction = {
x = x_direction,
y = y_direction
}
local direction_list = {{0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}}
local check1 = nil
local check2 = nil
local move1 = nil
local move2 = nil
for i = 1, #direction_list do
if direction.x == direction_list[i][1] and direction.y == direction_list[i][2] then
if i == 1 then
check1 = self:canMove(direction_list[#direction_list][1], direction_list[#direction_list][2])
move1 = self:Move(direction_list[#direction_list][1], direction_list[#direction_list][2])
else
check1 = self:canMove(direction_list[i - 1][1], direction_list[i - 1][2])
move1 = self:Move(direction_list[i - 1][1], direction_list[i - 1][2])
end
if i == #direction_list then
check2 = self:canMove(direction_list[1][1], direction_list[1][2])
move2 = self:Move(direction_list[1][1], direction_list[1][2])
else
check2 = self:canMove(direction_list[i + 1][1], direction_list[i + 1][2])
move2 = self:Move(direction_list[i + 1][1], direction_list[i + 1][2])
end
if check1 and check2 then
if math.random(0,1) <= 0.5 then
move1
else -- this is where the error pops
move2
end
elseif check1 then
move1
elseif check2 then
move2
else
self.boredom = self.boredom + 1
self:Wander()
end
end
end
end
The error I receive is that an equal sign is expected near "else". I've seen these sorts of things pop up before when I call a function improperly, or when there's a failure to close a parenthesis somewhere, whatever. After checking for that sort of thing, I tried moving the "self:" sugar from the declaration to the place where I actually call the functions, i.e.:
...
if i == #direction_list then
check2 = canMove(direction_list[1][1], direction_list[1][2])
move2 = Move(direction_list[1][1], direction_list[1][2])
else
check2 = canMove(direction_list[i + 1][1], direction_list[i + 1][2])
move2 = Move(direction_list[i + 1][1], direction_list[i + 1][2])
end
if self:check1 and self:check2 then -- this is where the error pops in this version
if math.random(0,1) <= 0.5 then
self:move1
else
self:move2
end
elseif self:check1 then
self:move1
elseif self:check2 then
self:move2
else
self.boredom = self.boredom + 1
self:Wander()
end
...
What I found really interesting in doing this is that it changed the error. When running it like this, Love returns the error "function arguments expected near 'and'". I double-checked canMove and Move, and they are getting all the arguments they need, here. However, this got me thinking: when is Lua (and/or Love) actually computing the results of a function when that function is assigned to a variable?
If I say something like a = f(x), is it running f(x) there and then, and assigning the output to a at that time? Or does it wait until I later call on a to run f(x)? Or is it both, like is it redoing that work if I start with a declaration and then later call on it?
If any intrepid souls want to help fix my code, that's awesome, but I'll figure that out myself in time; what I'm primarily interested in is this hair-splitting thing about assignation and computation, because now that it's on my mind, it's driving me nuts not knowing.
Solution 1:[1]
move
is not a valid Lua statement. You cannot just write an identifier on its own. You need to combine it with other things.
Adding self:
doesn't change that. It merely replaces the local move1
by a table element. Still this is an invalid expression.
The only thing that changes is that Lua now expects arguments as the colon syntax is only used in combination with functions.
If move1
is a function value you can call
move1()
or if it was a method of the table self
you could call
self:move1()
But just writing move1
is syntactically incorrect.
Same for move2
.
If I say something like a = f(x), is it running f(x) there and then, and assigning the output to a at that time? Or does it wait until I later call on a to run f(x)? Or is it both, like is it redoing that work if I start with a declaration and then later call on it?
Function calls happen at runtime. So does the function definition which is also just an assignment. Your program is executed line by line from top to bottom.
Solution 2:[2]
first things first, your calling a variable without the parentheses. so change self:move1
to self:move1()
and it might fix the error
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | freeve4 |