variable value not accepted, but variable value + 0 accepted. Why?

In a board game, I have a scene where the player can click on the button for the level he wants to play. This enters the number value of the level in a local variable. This is sent to another Module handling the level about to be played. With the number value of the level passed onto it, data about the level is retrieved from another Module. Thus the next scene is created for the proper level. Very simple and it works well except for one detail that I do not understand:

  • the number of the level is retrieved from the params from the last scene. It works. No problem there. I used print() to check it.

local levelId = options.levelId

  • levelId is given for the creation of levelData. There is nothing wrong with that either.

local levelData = levelsParams.getLevelData(levelId)

Here is the problem. When used as above, I get: 

Corona Simulator Runtime error

Attempt to index local ‘levelData’ (a nil value)

But if I just add “+ 0”, it works:

local levelId = options.levelId + 0

local levelData = levelsParams.getLevelData(levelId)

Are there values similar to Int or String in Lua? Or something else?

I would appreciate any explanation on this.

What is levelsParams?

Is this a module?

Where did you get it?

Thanks

Rob

What I don’t understand is why (local levelId = options.levelId + 0) is accepted and (local levelId = options.levelId) is not accepted?

Unless I am mistaken, levelsParams is irrelevant to the problem. I actually put the following tables in the same scene above those lines and not in a separate Module, and the same phenomenon happens.

levelsParams is a very simple Module I wrote:


– levelsParams.lua


local M = {}


local levelsList ={}

local level1, level2, level3

  ---------------------

  level1 = {

    tiles = { {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,0,1,1,1,1},

              {1,1,1,0,0,1,1,1,1},

              {1,1,1,1,0,1,1,1,1},

              {1,1,1,1,0,1,1,1,1},

              {1,1,1,0,0,0,1,1,1},

              {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,1,1,1,1,1} }

            }

  table.insert( levelsList, level1 )

  ---------------------

  level2 = {

    tiles = { {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,1,1,1,1,1},

              {1,1,1,0,0,0,1,1,1},

              {1,1,1,1,1,0,1,1,1},

              {1,1,1,0,0,0,1,1,1},

              {1,1,1,0,1,1,1,1,1},

              {1,1,1,0,0,0,1,1,1},

              {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,1,1,1,1,1} }

            }

  table.insert( levelsList, level2 )

  ---------------------

  level3 = {

    tiles = { {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,1,1,1,1,1},

              {1,1,1,0,0,0,1,1,1},

              {1,1,1,1,1,0,1,1,1},

              {1,1,1,0,0,0,1,1,1},

              {1,1,1,1,1,0,1,1,1},

              {1,1,1,0,0,0,1,1,1},

              {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,1,1,1,1,1} }

            }

  table.insert( levelsList, level3 )

  -----------------------------

  function M.getLevelData(whichLevel)

    return levelsList[whichLevel]

  end

return M

Thank you for working with me on this,

Eques

Lua indexes tables in two ways:  Numerically (if the index is a number) or by a key (if the index is a string).  This leads to one of your other questions, in Lua there are distinct data types:  string, number, boolean, nil, table, and function (there are probably a few others, but those are the core), but Lua keeps track of that for you and you rarely have to worry about the type.

This may be one of those times that matters.

We can’t see where option.levelId is being initialized. If somewhere in your code you’re doing:

option.levelId = "3"

Then you’re explicitly telling Lua to make option.levelId a string. When you go to reference your table, you’re looking for:

levelsParams.getLevelData( "3" )

instead of:

levelsParams.getLevelData( 3 )

Your table, according to your code above is being indexed numerically (making it an array, and what I would expect), but if the value being passed to the function is a string, it’s looking for an entry with a key of “3” (a string, not a number).  When you append the + 0, it forces Lua to convert the “3” to a number instead of a string and you end up with a numeric key.

So look in your code and see if there is a place where you have quotes around a number you expect to be a number. If you have to you can use the Lua function tonumber() to force the value to be a number (same as adding + 0).

FYI, our forums supports code formatting. When sharing code, it’s best to click on the blue <> button in the row with Bold, Italic, etc. and paste your code into the popup window. It will make it easier to read your code.

Rob

Thank you Rob. You cleared it up for me.

Based on what I just learned from you, I went back to understand why this value was not a int in the first place, but a string. I had not realized it was in a piece of code you had written in the tutorial on building a level selection scene. On line 71, you wrote, “id = tostring( i ) ,”. Is there a reason for this? Because I have tried it with “id = tonumber( i ) ,”, and with “id = i ,” and they both work.

 -- Define the array to hold the buttons local buttons = {} -- Read 'maxLevels' from the 'myData' table. Loop over them and generating one button for each. for i = 1, myData.maxLevels do -- Create a button buttons[i] = widget.newButton({ label = tostring( i ), id = tostring( i ), onEvent = handleLevelSelect, emboss = false, shape="roundedRect", width = 48, height = 32, font = native.systemFontBold, fontSize = 18, labelColor = { default = { 1, 1, 1 }, over = { 0.5, 0.5, 0.5 } }, cornerRadius = 8, labelYOffset = -6, fillColor = { default={ 0, 0.5, 1, 1 }, over={ 0.5, 0.75, 1, 1 } }, strokeColor = { default={ 0, 0, 1, 1 }, over={ 0.333, 0.667, 1, 1 } }, strokeWidth = 2 })

That was written a long time a go. I’m not sure I had a real reason to convert either of those, because Lua should convert them as needed. However, I never really intended for the id to be used as a numeric index to another table. It would not hurt to remove the tostring() call on the ID.

That should solve it for you.

Rob

Great. Thank you. Yes, it is solved.

What is levelsParams?

Is this a module?

Where did you get it?

Thanks

Rob

What I don’t understand is why (local levelId = options.levelId + 0) is accepted and (local levelId = options.levelId) is not accepted?

Unless I am mistaken, levelsParams is irrelevant to the problem. I actually put the following tables in the same scene above those lines and not in a separate Module, and the same phenomenon happens.

levelsParams is a very simple Module I wrote:


– levelsParams.lua


local M = {}


local levelsList ={}

local level1, level2, level3

  ---------------------

  level1 = {

    tiles = { {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,0,1,1,1,1},

              {1,1,1,0,0,1,1,1,1},

              {1,1,1,1,0,1,1,1,1},

              {1,1,1,1,0,1,1,1,1},

              {1,1,1,0,0,0,1,1,1},

              {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,1,1,1,1,1} }

            }

  table.insert( levelsList, level1 )

  ---------------------

  level2 = {

    tiles = { {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,1,1,1,1,1},

              {1,1,1,0,0,0,1,1,1},

              {1,1,1,1,1,0,1,1,1},

              {1,1,1,0,0,0,1,1,1},

              {1,1,1,0,1,1,1,1,1},

              {1,1,1,0,0,0,1,1,1},

              {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,1,1,1,1,1} }

            }

  table.insert( levelsList, level2 )

  ---------------------

  level3 = {

    tiles = { {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,1,1,1,1,1},

              {1,1,1,0,0,0,1,1,1},

              {1,1,1,1,1,0,1,1,1},

              {1,1,1,0,0,0,1,1,1},

              {1,1,1,1,1,0,1,1,1},

              {1,1,1,0,0,0,1,1,1},

              {1,1,1,1,1,1,1,1,1},

              {1,1,1,1,1,1,1,1,1} }

            }

  table.insert( levelsList, level3 )

  -----------------------------

  function M.getLevelData(whichLevel)

    return levelsList[whichLevel]

  end

return M

Thank you for working with me on this,

Eques

Lua indexes tables in two ways:  Numerically (if the index is a number) or by a key (if the index is a string).  This leads to one of your other questions, in Lua there are distinct data types:  string, number, boolean, nil, table, and function (there are probably a few others, but those are the core), but Lua keeps track of that for you and you rarely have to worry about the type.

This may be one of those times that matters.

We can’t see where option.levelId is being initialized. If somewhere in your code you’re doing:

option.levelId&nbsp;= "3"

Then you’re explicitly telling Lua to make option.levelId a string. When you go to reference your table, you’re looking for:

levelsParams.getLevelData( "3" )

instead of:

levelsParams.getLevelData( 3 )

Your table, according to your code above is being indexed numerically (making it an array, and what I would expect), but if the value being passed to the function is a string, it’s looking for an entry with a key of “3” (a string, not a number).  When you append the + 0, it forces Lua to convert the “3” to a number instead of a string and you end up with a numeric key.

So look in your code and see if there is a place where you have quotes around a number you expect to be a number. If you have to you can use the Lua function tonumber() to force the value to be a number (same as adding + 0).

FYI, our forums supports code formatting. When sharing code, it’s best to click on the blue <> button in the row with Bold, Italic, etc. and paste your code into the popup window. It will make it easier to read your code.

Rob

Thank you Rob. You cleared it up for me.

Based on what I just learned from you, I went back to understand why this value was not a int in the first place, but a string. I had not realized it was in a piece of code you had written in the tutorial on building a level selection scene. On line 71, you wrote, “id = tostring( i ) ,”. Is there a reason for this? Because I have tried it with “id = tonumber( i ) ,”, and with “id = i ,” and they both work.

 -- Define the array to hold the buttons local buttons = {} -- Read 'maxLevels' from the 'myData' table. Loop over them and generating one button for each. for i = 1, myData.maxLevels do -- Create a button buttons[i] = widget.newButton({ label = tostring( i ), id = tostring( i ), onEvent = handleLevelSelect, emboss = false, shape="roundedRect", width = 48, height = 32, font = native.systemFontBold, fontSize = 18, labelColor = { default = { 1, 1, 1 }, over = { 0.5, 0.5, 0.5 } }, cornerRadius = 8, labelYOffset = -6, fillColor = { default={ 0, 0.5, 1, 1 }, over={ 0.5, 0.75, 1, 1 } }, strokeColor = { default={ 0, 0, 1, 1 }, over={ 0.333, 0.667, 1, 1 } }, strokeWidth = 2 })

That was written a long time a go. I’m not sure I had a real reason to convert either of those, because Lua should convert them as needed. However, I never really intended for the id to be used as a numeric index to another table. It would not hurt to remove the tostring() call on the ID.

That should solve it for you.

Rob

Great. Thank you. Yes, it is solved.