LUA question about visibility

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Lbenet
Prole
Posts: 2
Joined: Sat May 18, 2019 8:24 am

LUA question about visibility

Post by Lbenet » Sat May 18, 2019 8:46 am

Hello,

Well, I didn't see a presentation forum, so "Hello" to everybody.

I am new to Lua, so I have been reading the manual reference but I don't get some concepts. I come from C++ and SFML, with the feeling by now it is a more rigid language (although I have never dominated it). Seeing how Love2D is like, I think it will be better for my goals.

Don't hesitate to show me another Lua books, reference guides or forums if the question doesn't fit here, and fit better there. Ah! Also I am not native english speaker, so I am sorry about my english.

So, my question... I am building an application to write chemistry equations by clicking on a periodic table. The question is about visibility. I have the next code:

Code: Select all

local periodic_table

function love.load()
	periodic_table = require 'periodic_table'
	love.window.setMode(1500, 900)
	periodic_table:load()
end
There, in periodic_table I have the next code:

Code: Select all

periodic_table = {}

function periodic_table:load()
	local element = require("element")
	-- lots of code more
end
And the question is that in main I can do the next:

Code: Select all

function love.draw()
	periodic_table:draw()
	element.WIDTH = 5
end
Why I can change "element.WIDTH", if it was a local object of "periodic table" inside the "load" function? I think I could not access to element because it is not in the scope, but I can do it and it has effect on the "element" object. "WIDTH" is an existent key of "element".
Really I am not interested in change "element" but I want to learn what is happening. In C++ I worked with several books wich defined the language in great detail, but I have other feelings with Lua.

grump
Party member
Posts: 587
Joined: Sat Jul 22, 2017 7:43 pm

Re: LUA question about visibility

Post by grump » Sat May 18, 2019 1:38 pm

Lbenet wrote:
Sat May 18, 2019 8:46 am
And the question is that in main I can do the next:

Code: Select all

function love.draw()
	periodic_table:draw()
	element.WIDTH = 5
end
Why I can change "element.WIDTH", if it was a local object of "periodic table" inside the "load" function? I think I could not access to element because it is not in the scope, but I can do it and it has effect on the "element" object. "WIDTH" is an existent key of "element".
The only explanation for this behavior is that the actual code is different from the code you have shown. The table named element does not exist outside periodic_table:load with this code, and can't be altered from outside the function. Check if you have a global variable with the same name defined somewhere.

User avatar
pgimeno
Party member
Posts: 1906
Joined: Sun Oct 18, 2015 2:58 pm
Location: Valencia, ES

Re: LUA question about visibility

Post by pgimeno » Sat May 18, 2019 2:08 pm

grump is right. It's just guesswork, but one likely explanation is that 'element' is defined as a global inside element.lua, just like periodic_table is defined as a global in the snippet you have shown of periodic_table.lua. Change it to this if you don't want it global:

Code: Select all

local periodic_table = {}
...
Similarly, in element lua, if you have this, which is what I suspect:

Code: Select all

element = {}
...
then just change it to this:

Code: Select all

local element = {}
...
That way, they will be local to the file they are defined in, rather than global.

KayleMaster
Party member
Posts: 212
Joined: Mon Aug 29, 2016 8:51 am

Re: LUA question about visibility

Post by KayleMaster » Sat May 18, 2019 8:05 pm

I'm not sure if code is missing, or you just didn't quite grasp Lua.

Code: Select all

periodic_table = {}

function periodic_table:load()
	local element = require("element")
	-- lots of code more
end
You're requiring this module from love.load with

Code: Select all

periodic_table = require 'periodic_table'
But because you don't have local in front of "periodic_table = {}" that is now a global variable.
The proper way to do this is:

Code: Select all

local periodic_table = {}

function periodic_table:load()
	local element = require("element")
	-- lots of code more
end

return periodic_table
Next, you're defining an element in the load function, I assume element will have the same structure (local element = {} - do stuff with element - return element), however, that element is only visible to the function.
Your code is pretty wrong with the access of "element.WIDTH". You don't have traces of element in your main.lua.

What you want to do is this:

Code: Select all

local periodic_table = {}

function periodic_table:load()
	self.element = require("element")
	-- lots of code more
end

return periodic_table
Now you access the element using:

Code: Select all

function love.draw()
	periodic_table:draw()
	periodic_table.element.WIDTH = 5
end
Why you can access the element? Probably because of the same mistake you did with defining your periodic table - you missed local in front of it and it became a global variable.

However you need to look up how require works. It only runs the file it requires the first time. Every second time it just returns what it returned the first time. If you have multiple elements, I'd advise you to look at PIL's tutorial for classes/objects or use something like middleclass.

Lbenet
Prole
Posts: 2
Joined: Sat May 18, 2019 8:24 am

Re: LUA question about visibility

Post by Lbenet » Sun May 19, 2019 7:11 am

Thank you for all responses!

I said that I came from C++, but it is true that I only have made simple things and I have some problems to grasp the OOP concepts or at least how to organise it, but I had good documentation about the language (there are tons of books) so I advanced step-by-step. But Lua seems to be faster to code, so I choosed it.

So the point is that I wrote this code:

Code: Select all

function tabla:load()

	local elemento = require 'elemento'

	table.insert(self, elemento:new("H", "Hidrogeno", 1.008, 1, 2.1, 2, 2, "BLANCO"))
	table.insert(self, elemento:new("Li", "Litio", 6.941, 3, 1.0, 3, 2, "BLANCO"))
	table.insert(self, elemento:new("Na", "Sodio", 22.990, 11, 0.9, 4, 2, "BLANCO"))

end
But I didn't declare element as local in its file: I though it was enough declaring it as a local one time when I "require" the file in the function (I though "local" was applied to the complete file). So, in the file I had:

Code: Select all

elemento = {}
-- more code
Changing to:

Code: Select all

local elemento = {}
-- more code
All works as expected, I can not access to "elemento".
Thank you!

User avatar
raidho36
Party member
Posts: 1951
Joined: Mon Jun 17, 2013 12:00 pm

Re: LUA question about visibility

Post by raidho36 » Sun May 19, 2019 8:42 am

The "require" function simply loads the file into memory (and runs it). If the file returned something at the end, then this is returned from the "require" function. The file in question is loaded exactly once, and then the same value is returned from "require" it every time you call it. You can use it the way you use it, but the way it works is more clearly telegraphed when you code it as following:

Code: Select all

local class = require ( "class" )

local instance1 = class ( "foo" )
local instance2 = class ( "bar" )

grump
Party member
Posts: 587
Joined: Sat Jul 22, 2017 7:43 pm

Re: LUA question about visibility

Post by grump » Sun May 19, 2019 9:34 am

raidho36 wrote:
Sun May 19, 2019 8:42 am

Code: Select all

local class = require ( "class" )

local instance1 = class ( "foo" )
local instance2 = class ( "bar" )
Either your terminology is off, or I don't understand what this is supposed to do. Why does the class function return instances?

User avatar
raidho36
Party member
Posts: 1951
Joined: Mon Jun 17, 2013 12:00 pm

Re: LUA question about visibility

Post by raidho36 » Sun May 19, 2019 10:39 am

It's a common practice to call the class to create new instances of the class, provided "__call" metamethod is defined. It's equivalent of calling class:new but uses Lua builtin dispatch system instead of actually calling "new" manually.

User avatar
pgimeno
Party member
Posts: 1906
Joined: Sun Oct 18, 2015 2:58 pm
Location: Valencia, ES

Re: LUA question about visibility

Post by pgimeno » Sun May 19, 2019 11:23 am

Lbenet wrote:
Sun May 19, 2019 7:11 am
But I didn't declare element as local in its file: I though it was enough declaring it as a local one time when I "require" the file in the function (I though "local" was applied to the complete file).
'require' does not work like 'include' in C/C++: it does not preserve the scope of the current block; instead it creates a new top-level scope, therefore everything you declare within the file which isn't local will be global.

Similarly, there's a limit of 200 active locals per file, but the count resets for files you require().

I am saying 'file' above, but I really mean 'chunk', which is the term that the Lua manual uses (a chunk is a more general concept, as it can come from a string, for example). And the same applies to 'require', 'dofile', 'load', 'loadfile' and 'loadstring'.

(Edited to place the correct maximum of active locals, thanks guys)
Last edited by pgimeno on Mon May 20, 2019 10:58 am, edited 2 times in total.

User avatar
raidho36
Party member
Posts: 1951
Joined: Mon Jun 17, 2013 12:00 pm

Re: LUA question about visibility

Post by raidho36 » Sun May 19, 2019 1:56 pm

pgimeno wrote:
Sun May 19, 2019 11:23 am
there's a limit of 256 active locals per file, but the count resets for files you require().
Last I heard the limit was exactly 200 for any given scope.

Post Reply

Who is online

Users browsing this forum: Google [Bot] and 11 guests