Making print() Great: Recursive Printing Option


#1

To preface this post, I do know that there have been similar threads to this in the past, but I could not find one that was more recent than early 2016. The feature explained below is standard in every similar loosely-typed language that I've dealt with. Lua is the only one I've worked with that lacks it.

I've been happy with Lua's print() options for a long time...

...And then I began using HTTP calls that return JSON in my projects. I've noticed for a long time that trying to call print() on a table is a very unfortunate process, but hey! I should always know what kind of layout my table has, right? I made it after all.

Well, with JSON I’ve realized just how much that’s not true. Right now, it is extremely hard to debug any errors that I run into with data stored in a table.

What’s needed is a recursive print() that can support printing both an object itself, and all of its contents.

While it is possible for us to simulate such a feature with a function that recursively calls three or more nested for-loops to print any possible values at any possible level of the item, this would be a highly inefficient approach to what should be a very useful tool. Not every project involves complicated tables, but the ones that do tend to use lots of them and to use them often.


#2

You could change it from a regular table to a custom class with custom meta methods. Using __tostring you can define the behavior when an object is printed. All that’s left then is defining __tostring as a method that recursively prints the class’ table.


#3

For this functionality, I use a library called Inspect. Super useful!

Usage

local inspect = require(path.to.inspect)
print(inspect(myTable))

#4

This could work. I just wrote this now, so it isn’t tested and I may have misspelled something, but it should get the job done.

function recursiveToString(object)
    if typeof(object) == "table" then
        local str = "{\n"
        for i,v in pairs(object) do
            if typeof(i) == "string" then
                str = str .. i .. " = "
            else
                str = str .. "[" .. tostring(i) .. "] = "
            end

            str = str .. tostring(v) .. ",\n"
        end
        str = str .. "}"
        return str
    else
        return tostring(object)
    end
end

function recursivePrint(object)
    print(recursiveToString(object))
end

#5

I do agree there should be a better way to see information inside tables instead of having to create our own lookup functions but if anyone needs a really good way to print out tables, here is the method I currently use, as well as an example:

local ExamplePlayerData = {
	Money = 100,
	Level = 10,
	Exp = 55,
	Stats = {
		HP = 250,
		Dmg = 50,
		Speed = 25,
		Kills = 9001,
		Deaths = 1337,
	},
	LoadOut = {
		Weapon1 = {
			Name = "Dominus Sword",
			Type = "Legendary",
		},
		Weapon2 = {
			Name = "Gold Gun",
			Type = "Rare",
		},
		Weapon3 = {
			Name = "Bronze Dagger",
			Type = "Common",
		},
	},
	MissionsDone = 16,
	TimePlayed = 777,
}

local function recursivePrint(tbl, indent)
	if not indent then indent = 0 end
	if type(tbl) ~= "table" then return end
	for k,v in pairs(tbl) do
		local s = string.rep("     ", indent)..k..": "
		if type(v) == "table" then
			print(s)
			recursivePrint(v, indent + 1)
		else
			print(s..tostring(v))
		end
	end
end

recursivePrint(ExamplePlayerData)

Which will print out something like:
image
Note: I used 5 spaces for the indenting because when I used tab, it indented too much but feel free to experiment. I know some people might change the font used so the indenting will have a different behavior than I got.


#6

Well, thanks for the above recommendations of course. I was already planning on scripting one myself to analyze an issue I’m facing this moment.

But even still, Roblox paints itself as being the ideal game engine for new and old developers alike. Even more, its clear focus is on being the perfect learning environment where first time creators can get a jump start. It doesn’t make sense therefore to require such advanced knowledge of what could be and I’m sure often are brand new scripters. Even Javascript, with all the hate it gets from programmers for relatively poor performance and ugly formatting requirements, only needs a simple “console.log(table);”


#7

#8

This pretty much how Lua works. There are other languages like Python that allow you to print lists and dictionaries with no trouble, but Lua doesn’t quite work that way.

In short; In Lua the parameters you pass to the print() function are first transformed into strings, then concatenated and then sent to the standard output. In the case of tables/dictionaries, their transformation translates them seemingly into address strings. Since the table/dictionary data is transformed it would be difficult if not impossible to translate it further into a nicely formatted output.

There is not much Roblox can do about this as for as I know. As other have mentioned above, your best bet is to use a module that first transforms your objects into nicely readable strings before sending it to the output.