Thats Amazing! (Closure)
Thats Amazing! (Closure)
My God, Lua where have you been all my life!
So any of you guys know some cool ways I could use closure in a game?
or some simple examples would be awesome \(^m^)/
Re: Thats Amazing! (Closure)
Why did you do, "return {get=get, set=set}"?
Re: Thats Amazing! (Closure)
Good question (^_^)
You need to access the functions
outside the local function f()
what return {get = get, set = set} does is:
return a table with index get and value function get() and index set with value function set().
remember functions are first class values in Lua, this means we can treat them just like values and return them just like we would a normal value
{} is the table constructor
table = { index_a = "value 1", index_b = "value 2" }
is syntax sugar for
table = {}
table.index_a = "value 1" --same as table["index_a"] = "value 1"
table.index_b = "value 2"
so function f() returns the table with access to get() and set() within its scope
r = {} --think of r as a table
r.get = get --variable get = function()
r.set = set --variable set = function(new_v)
outside our function (f()) scope we can set multiple variables to call f()
local t,u = f(), f() --assign multiple variables, the () calls a function
and then access the local functions get() and set() with the returned table indexes that where stored in variables t,u
print(t.get())
print(u.get())
functions in Lua are also ambiguous which means they have no fixed name and by assigning variables t,u = f(),f() --multiple assignment
we are not copying the function f() or just storing its values but instead referring to it with the variables t and u.
--an example to demonstrate this
foo = print
foo('used just like print(...)")
==> used just like print(...)
notice how foo now has access to print. (infact print is just a name used to reffer to its ambigouse function in Lua)
One more thing, also notice how I used
do
--local scope
end
this is only for the interactive Lua shell, where every-line is its own scope unless you explicitly create a do end chunk. you don't need to worry about that in LOVE though bear in mind the scope in which your code is in.
You can learn more here:
http://lua-users.org/wiki/FunctionsTutorial
http://lua-users.org/wiki/ScopeTutorial
You need to access the functions
Code: Select all
local function get()
--code
end
local function set(new_v)
--code
end
what return {get = get, set = set} does is:
return a table with index get and value function get() and index set with value function set().
remember functions are first class values in Lua, this means we can treat them just like values and return them just like we would a normal value
{} is the table constructor
table = { index_a = "value 1", index_b = "value 2" }
is syntax sugar for
table = {}
table.index_a = "value 1" --same as table["index_a"] = "value 1"
table.index_b = "value 2"
so function f() returns the table with access to get() and set() within its scope
r = {} --think of r as a table
r.get = get --variable get = function()
r.set = set --variable set = function(new_v)
outside our function (f()) scope we can set multiple variables to call f()
local t,u = f(), f() --assign multiple variables, the () calls a function
and then access the local functions get() and set() with the returned table indexes that where stored in variables t,u
print(t.get())
print(u.get())
functions in Lua are also ambiguous which means they have no fixed name and by assigning variables t,u = f(),f() --multiple assignment
we are not copying the function f() or just storing its values but instead referring to it with the variables t and u.
--an example to demonstrate this
foo = print
foo('used just like print(...)")
==> used just like print(...)
notice how foo now has access to print. (infact print is just a name used to reffer to its ambigouse function in Lua)
One more thing, also notice how I used
do
--local scope
end
this is only for the interactive Lua shell, where every-line is its own scope unless you explicitly create a do end chunk. you don't need to worry about that in LOVE though bear in mind the scope in which your code is in.
You can learn more here:
http://lua-users.org/wiki/FunctionsTutorial
http://lua-users.org/wiki/ScopeTutorial
Re: Thats Amazing! (Closure)
A use of closure: Put local variables at the top of your file. The variables are usually private constants or settings for your module. All your functions in that file will have access to the variables at the top once you call them.
Code: Select all
-- myfile.lua
local SOMETHING_COOL = 'cool'
function test()
print(SOMETHING_COOL)
SOMETHING_COOL = SOMETHING_COOL:rep(2)
end
-- anotherfile.lua
require 'myfile'
test() -- cool
test() -- coolcool
Re: Thats Amazing! (Closure)
Optimization note: Lua's closures use more memory than a table+metatable does. That's because it closes over the entire stack-frame, and not the variables directly. So, if you're going to do a closure here and there, that's fine. If you're going to write a particle system with tens of thousands of concurrent entities each with it's own closure, you're going to see some pretty hard garbage collection cycling.
Re: Thats Amazing! (Closure)
o.k..
I get confused with closure in tail calls. would the particle system use closure if for example it was to run itself over and over for a certain time, and each time calling upvalues from within itself or is it only closure when upvalues are from somewhere completely different like another function...
so we wont use closure with recursion but its OK with normal tail calls and general code right?
I get confused with closure in tail calls. would the particle system use closure if for example it was to run itself over and over for a certain time, and each time calling upvalues from within itself or is it only closure when upvalues are from somewhere completely different like another function...
so we wont use closure with recursion but its OK with normal tail calls and general code right?
Re: Thats Amazing! (Closure)
It sounds like I may have confused you a bit so I'll explain more.Ekamu wrote:o.k..
I get confused with closure in tail calls. would the particle system use closure if for example it was to run itself over and over for a certain time, and each time calling upvalues from within itself or is it only closure when upvalues are from somewhere completely different like another function...
so we wont use closure with recursion but its OK with normal tail calls and general code right?
Where ever you have the function keyword, you have a closure, which closes over the lexical environment that it appears in. So, lets look at this code:
Code: Select all
function createClosures()
local t = {}
for i = 1, 10 do
t[#t+1] = function() return i end
end
return t
end
So, to make this a bit more apparent, consider the particle thing I mentioned before:
Code: Select all
function createParticle()
local self, x, y = {}, 0, 0
function self:draw()
-- drawing code here
end
function self:update(dt)
-- updating code here
end
return self
end
particles = {}
for i = 1, 10000 do particles[i] = createParticle() end
Just for good measure, here's the lightest particle system you could make in Lua:
Here I made 3 tables, 20002 variables, 3 functions, and either 1 or 3 closures (I'm not sure if lua 5.1 shares that lexical environment, but I know lua 5.2 does). This code tends to be a bit more messy, so you only use this style for things where performance is crucial.particles = { x={}, y={}, N=0 }
function particles.create()
particles.N = particles.N + 1
particles.x[particles.N] = 0
particles.y[particles.N] = 0
end
function particles.draw()
for i = 1, particles.N do
-- drawing code
end
end
function particles.update(dt)
for i = 1, particles.N do
-- updating code
end
end
for i = 1, 10000 do particles.create() end
- Roland_Yonaba
- Inner party member
- Posts: 1563
- Joined: Tue Jun 21, 2011 6:08 pm
- Location: Ouagadougou (Burkina Faso)
- Contact:
Re: Thats Amazing! (Closure)
As a complementary reading on the topic, which illustrates nicely Inny's comments, see this article on OO with closures, and this benchmark.
Re: Thats Amazing! (Closure)
Thanks for the link and summary.
so basically in a numeric for loop each iteration creates a new closure, this is bad for something like a particle system where performance is crucial right?
this is the same for any loop, not just numeric for loops.
Also those links on OOP and closure are great but I'm not yet there. I still need to cover Meta-methods, Environments and Modules. I like learning things in order and step by step but I will definitely read more about OOP very soon.
so basically in a numeric for loop each iteration creates a new closure, this is bad for something like a particle system where performance is crucial right?
this is the same for any loop, not just numeric for loops.
Also those links on OOP and closure are great but I'm not yet there. I still need to cover Meta-methods, Environments and Modules. I like learning things in order and step by step but I will definitely read more about OOP very soon.
Who is online
Users browsing this forum: Amazon [Bot], Bing [Bot] and 3 guests