This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
isavegas's profile picture

Convert variables to table and back again

Started by isavegas, 28 December 2012 - 01:48 PM
isavegas #1
Posted 28 December 2012 - 02:48 PM
I've been playing in a creative world so I could learn how to use turtles and whatnot without having to waste any resources (fuel, etc…) and I managed to make a turtle deployer that deploys another turtle on the press of a button, and have it send a table (serialized) to the drone to tell it what to do (this is a test for my plan on making a "Master" program and having deployers that send off turtles tell them what part they need to run and how to do it.) The table is serialized and sent as a message, and the receiving turtle DOES get the message, however, it throws up an unexpected error.

Here are the relevent lines of code (the whole programs are over 75 lines long right now):
Drone Deployer- I cut out the functions that do not pertain to the subject matter, such as "deployDrone()"
Spoiler


function variableDeclare()
  rsInput = "back"
  drone = peripheral.wrap("front")
  x = 38
  y = 38
  table = {x,y}
droneCount = 0
end


function rnSend()
  droneID = peripheral.call("front","getID")
  print("Drone scanned")
  msg = textutils.serialize(table)
  print("Instructions encoded")
  sleep(.4)
  rednet.send(droneID, msg)
  print("Instructions sent")
end


function masterLoop()
  while true do
	if redstone.getInput(rsInput) == true then
	  term.clear()
	  deployDrone()
	  term.setCursorPos(1,1)
	  write(droneCount)
	  print(" drones have been sent")
	end
	sleep(1)
  end
end


if os.version() == "TurtleOS 1.4" then  --I use disk drives to contain startup programs, making it more flexible to control turtles.
  variableDeclare()
  rednet.open("right")
  masterLoop()
  else sleep(.1)
end

Drone-
Spoiler


function rednetStart()
  rednet.open("right")
  print("Watching RedNet...")
  id, msg = rednet.receive()
  print("Instructions received")
  write(table[1])
  write(",")
  print(table[2])
  table = textutils.unserialize(msg)
  x = toNumber(table[1])
  y = toNumber(table[2])
  print("Instructions decoded")
end


if os.version() == "TurtleOS 1.4" then
  rednetStart()
  masterLoop()   --This is the function that controls what the turtle actually DOES
  else sleep(.1)
end

The drone turtle is returning

Watching RedNet...
Instructions received
bios:156: bad argument: string expected, got nil

It might be a few days before I am able to get online again (in the process of changing internet companies, and we have to wait til the first to set up the new one.) I hope you can shine some light as to why it's not working. :P/>
Cozzimoto #2
Posted 28 December 2012 - 02:50 PM
make sure you unserialize the string into a blank table and make sure you are trying to send a string
isavegas #3
Posted 28 December 2012 - 03:18 PM
make sure you unserialize the string into a blank table and make sure you are trying to send a string


I am doing so.
"msg = textutils.serialize(table)"
"table = textutils.unserialize(msg)"
Pharap #4
Posted 28 December 2012 - 03:26 PM
I am doing so.
"msg = textutils.serialize(table)"
"table = textutils.unserialize(msg)"

you're doing the right things in the wrong order:

write(table[1])--table does not exist yet
  write(",")
  print(table[2])
  table = textutils.unserialize(msg)--this line must come first,otherwise all references to table are nil
Cozzimoto #5
Posted 28 December 2012 - 03:35 PM
that and it might help if you classify your table and an empty global table so it stores it correctly instead of guessing the computer is creating a var and making it a table. i find it easier for me when i debug that i label my vars what i need them instead of having a computer label them for me, cause ive had it wrong before on a few occasions when a computer tried to label it a wrong type of var and store data in it
isavegas #6
Posted 28 December 2012 - 03:42 PM
that and it might help if you classify your table and an empty global table so it stores it correctly instead of guessing the computer is creating a var and making it a table. i find it easier for me when i debug that i label my vars what i need them instead of having a computer label them for me, cause ive had it wrong before on a few occasions when a computer tried to label it a wrong type of var and store data in it

Classify it? No clue what you mean. I've only been programming a few days (the code is all mine though, by the way. No copy/paste from someone elses.) Are you saying that I need to do something like this?

table = {}
x = 38
y = 38
table[1] = x
table[2] = y

I am doing so.
"msg = textutils.serialize(table)"
"table = textutils.unserialize(msg)"

you're doing the right things in the wrong order:

write(table[1])--table does not exist yet
  write(",")
  print(table[2])
  table = textutils.unserialize(msg)--this line must come first,otherwise all references to table are nil

Sorry, just saw this. :P/> I'll try it! Anyways, I won't have internet for a few days, and can't test it right now, but thanks for the help!
Cozzimoto #7
Posted 28 December 2012 - 03:48 PM
you can even go as far ans making that more simpliar



table = {}

and you can keep it dynamic so whenever you are unserializing your string from rednet you can take it and just place it in your table you made earlier then reference it



table = textutils.unserialize(p2)
table[1] = x
table[2] = y
Pharap #8
Posted 28 December 2012 - 03:54 PM
that and it might help if you classify your table and an empty global table so it stores it correctly instead of guessing the computer is creating a var and making it a table. i find it easier for me when i debug that i label my vars what i need them instead of having a computer label them for me, cause ive had it wrong before on a few occasions when a computer tried to label it a wrong type of var and store data in it

Or alternatively use local to keep the reference off the global table, or actually reference _G.varname. Can't say I've ever had the issue you described though.


that and it might help if you classify your table and an empty global table so it stores it correctly instead of guessing the computer is creating a var and making it a table. i find it easier for me when i debug that i label my vars what i need them instead of having a computer label them for me, cause ive had it wrong before on a few occasions when a computer tried to label it a wrong type of var and store data in it

Classify it? No clue what you mean. I've only been programming a few days (the code is all mine though, by the way. No copy/paste from someone elses.) Are you saying that I need to do something like this?

table = {}
x = 38
y = 38
table[1] = x
table[2] = y

I am doing so.
"msg = textutils.serialize(table)"
"table = textutils.unserialize(msg)"

you're doing the right things in the wrong order:

write(table[1])--table does not exist yet
  write(",")
  print(table[2])
  table = textutils.unserialize(msg)--this line must come first,otherwise all references to table are nil

Sorry, just saw this. :P/> I'll try it! Anyways, I won't have internet for a few days, and can't test it right now, but thanks for the help!

No problem. When you get the internet back, I recommend looking into forum posts about the importance of using local.
If need be, you can probably ask any member to give you a tutorial, most will be happy to oblige. I'd say ask me, but that makes it sound like I'm saying I'm better than everyone else. Just go for someone you think is good that wouldn't be to busy, or just flick through the forums for more demos.

I must admit, I think a lot of the tutorials here are more lua-specific than actually teaching 'programming' (ie the concepts behind it)
Pharap #9
Posted 28 December 2012 - 03:59 PM
you can even go as far ans making that more simpliar



table = {}

and you can keep it dynamic so whenever you are unserializing your string from rednet you can take it and just place it in your table you made earlier then reference it



table = textutils.unserialize(p2)
table[1] = x
table[2] = y

Only issue with this is that you initialise a table, then change the reference on the next line so the newly made table has to be disposed of by the garbage collector no sooner has it been created. Using local in front of table = textutils.unserialise would be much better as the variable will be assigned local in a single swoop as well as being garbage collected when the program ends, as opposed to staying on _G and possibly interfering with future programs.
Luanub #10
Posted 28 December 2012 - 04:00 PM
Using table for the name of the table is probably not the best idea. There is a table API and if you go to use any of the functions(table.insert(), table.remove() etc..) you will probably get errors.

I got in the habbit of using the following naming convention for my vars when I first started using Lua. sMsg would be for a string that holds a message, tMsg for a table that holds a message(s).
Grim Reaper #11
Posted 28 December 2012 - 04:59 PM
Using table for the name of the table is probably not the best idea. There is a table API and if you go to use any of the functions(table.insert(), table.remove() etc..) you will probably get errors.

I got in the habbit of using the following naming convention for my vars when I first started using Lua. sMsg would be for a string that holds a message, tMsg for a table that holds a message(s).
He's right. However, an API is actually a table containing functions and constants, at least in Lua.

That naming convention is good, but I personally prefer to just using CamelCap (superAwesomeVariable) because, more often than not, the name of the variable explains its type and thus serves as a good alternative to using the first character of the type in your naming.

On to a solution to your problem.


If these two snippets of code are defined in different files, it would appear that 'table' doesn't appear to be defined and thus the interpreter will assume you're talking about the data contained in the native 'table' table. (As explained by luanub.)

Something that you need to take into consideration is the scope of your program. In this I mean that you have a function called 'variable declare'. When you execute this function, the variables you declare in it are local to the scope of that function and that function only because they haven't been declared in a scope greater than that of the function 'variable declare'. Considering that you reference the variables in other functions, I would suggest that you declare them outside of your functions like the following code would demonstrate:


-- Global scope variable declaration.
local rsInput = "back"
local drone = peripheral.wrap("front")
local x = 38
local y = 38
local table = {x, y}
local droneCount = 0


--[[ From:
function variableDeclare()
	rsInput = "back"
	drone = peripheral.wrap("front")
	x = 38
	y = 38
	table = {x,y}
	droneCount = 0
end--]]


You don't need to worry about these variables being accessible after the execution of your program for two reasons:
1) The shell executes program by using 'dofile' and loading the contents of your program into a function that the shell then executes that function within itself. This means that once your program is executed in the aforementioned function, its variables are garbage collected.
* Important note: Variables that are declared exclusively within a function (no such declaration has been made at a higher scope (global, for example, but not in other functions)) are exclusive to that function and are destroyed once the function is executed.

2) Less importantly, by declaring your variables in YOUR PROGRAM'S GLOBAL SCOPE, you eliminate the ability for other programs to access those variables because their outside of their scope.

Trying to access 'table' in a scope where it isn't defined (as you'd like it to be: there is a native table called 'table') will cause it to be considered a nil value.