Tables; whichever way you look at it, however which way you use them, they’re incredibly useful.
They can store bulks of information, are simple to access and easy to work with.
Well, until an entry doesn’t seem to exist…
or an entry isn’t what you thought it was…
or you’ve passed it over a remote, but some of the values aren’t there, or aren’t the same as on the server…
or you reference a table inside your table, but the reference to that table isn’t right, or it is and the keys inside don’t match what you thought it was, and then you’ve got to…
Keeping track of more complex tables gets complicated fast. Smaller tables are easier to keep track of, but once the entries start getting more complex, debugging can be a bit of a nightmare.
Sometimes its best to just look at the table itself.
To that end, I give you DeepDive, a debugging function that iterates through any given table, printing its full contents in an indented and formatted fashion. It’s all a single-string print, so other prints won’t impact the final result.
Just copy+paste the code into a ModuleScript, keeping it wherever is most accesible, and call it if you’re finding a problem is occuring.
DebugModule Code
local Debugging = {}
function IsEmpty(tbl)
local HasContents = false
for _,_ in pairs(tbl) do
HasContents = true
break
end
return HasContents
end
function Debugging.DeepDive(Name, tbl, Depth)
local PreviousTables = {}
function DeepDive(Name, tbl, Depth)
local OurList
if tonumber(Name) then
OurList = "["..Name.."] = {"
else
OurList = Name.." = {"
end
local HasContents = IsEmpty(tbl)
if HasContents == false then
warn("Table is empty")
return OurList.."}"
elseif PreviousTables[tbl] then
warn("Cyclicle table structure")
return OurList..' "Table references earlier table, see entry: '..PreviousTables[tbl]..'" }'
end
PreviousTables[tbl] = Name
OurList = OurList.."\n"
for Key, Value in pairs(tbl) do
if type(Value) == "table" then
local StepDepth = Depth + 1
OurList = OurList..string.rep("\t", StepDepth)..DeepDive(Key, Value, StepDepth)..";".."\n"
elseif Value ~= nil then
local isNumber = tonumber(Value)
local isBool = tostring(Value) == "false" or tostring(Value) == "true"
local OurValue = isNumber and tostring(Value) or isBool and tostring(Value) or '"'..tostring(Value)..'"'
local KeyIsNumber = tonumber(Key)
if not KeyIsNumber then
OurList = OurList..string.rep("\t", Depth + 1)..Key.." = "..OurValue..";".."\n"
else
OurList = OurList..string.rep("\t", Depth + 1).."["..Key.."] = "..OurValue..";".."\n"
end
end
end
if Depth == 0 then
print(OurList.."}")
else
return OurList..string.rep("\t", Depth).."}"
end
end
DeepDive(Name, tbl, Depth)
end
return Debugging
Example use-case, checking the default data a player will receive
This is my table, + the DeepDive function call;
Output
Output copy + pasted into a script.
Ofcourse, this is intended to be used for tables that aren’t clearly laid out, but it’s always useful to see what the DeepDive actually finds via these prints.
In the future, I intend to include flags for common table related problems, like flagging the improperly formatted array (Bonus points to those of you who spotted it), if an object can’t be passed over remotes, or if any of the values won’t be able to be saved into a DataStore.
Is there any more information that should be included in the print? Are there any more common problems that this should warn against?
Look forward to hearing what you all make of this!