Skip to content

Using Lua scripts (Part 10): Table parameters

brothersadcase edited this page Sep 28, 2019 · 4 revisions

x: Table parameters

Tables in Lua are extremely useful and versatile, so I'm going to focus on using them to send information.

We have a bar meter drawing function separate to our main function and I have been through a few methods of getting the information the function needs from the main function via the curved brackets () in the function call to the function itself.

I have so far shown how we can do this by sending strings.

  • Call function dosomething in main and send info: dosomething (1, 0, 0, 1,"mono",12).
  • dosomething receives info and sets it to strings function. dosomething (red, green, blue, alpha, font, foontsize).

This is a nice straightforward way of passing the information, BUT it has some drawbacks.

You have to send EVERYTHING the function needs EVERY time you call the function if you don't send it everything and miss something out, or put it in the wrong order then you will get unexpected behavior from the function as it sets its strings to the wrong values or, more likely, you will get a nil error.

We can set tables to get around this. This way does requires some extra work initially but, once set up, you have the ability to, for example, specify default values for strings in advance and then only send the function the required information.

Say you wanted 5 bar indicators. You want them all to have gray backgrounds; You want them all to be the same height and width; and you want their indicators to be green from 0 to 45, yellow to 75 and then red.

The only thing that will be different between each bar will be the value it displays and the x, y coordinates. Possibly we want our bars all to line up in a row, so we may only need to change the x while keeping y the same.

So to cut down on typing and save time all we want to send to the function is the value to display and the x coordinate of the meter.

When a function becomes complicated, the list of things it needs to operate can become very large. In addition, the script may allow you to do several different things (eg draw a square or a circle) so you would only want to send the information that the specific part of the script (if you want to draw a circle you don't want to have to specify settings for a square that you wont use!).

Using Tables

There are different kinds of tables: indexed tables, "dictionary" tables and mixed tables (which have both)).

For this use of sending information we will be using "dictionary" tables, which usually take this general form:

Name of table
'='
Open the table with curly brackets ('{').
Enter data separated by commas. 
Close the table with '}'.

As I mentioned before, once you have your table open (table = {), you can space out and use multiple lines to enter the data on and allow for the use of comments ... as long as you use commas in the right place!

table = { -- Set table and open.
	red = 1,
	green = 0,
	blue = 0,
	alpha = 1, -- Alpha of 0 = full transparent, 1 = full opaque.
	font = "mono",
	fontsize = 12,
} -- closes table.

NOTE: it isn't a good idea to call a table "table", just as it is a bad idea to call a string "string". Just as with strings, give your tables unique names with the table name giving some information about what that table contains.

Now when we want to send info to our "dosomething" function we can do this I'll be using a better name for the table below.

-- setup function dosomething in main and call function
dosettings = { -- set table and open
	red = 1,
	green = 0,
	blue = 0,
	alpha = 1, -- alpha of 0 = full transparent, 1 = full opaque
	font = "mono",
	fontsize = 12,
} -- closes table
dosomething (dosettings)

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

-- dosomething receives the table, and puts the info into another table
function dosomething (settings)

NOTE the name of the table you put your settings into (dosettings in the above) and the table name you set for the function itself to use (settings in the above example) don't have to be the same.

Function "dosomething" just puts the info inside table "dosettings" and puts it into table "settings" in the same order.

NOW WE HAVE TO GET THE INFO OUT. This is where the extra work comes in :).

When sending the strings, the strings were immediately available to the function. When sending tables we need to get the info out and into strings.

This will all happen in the "dosomething" function.

There are several ways we can get the info out of a dictionary type table:

  • Using a period. This method takes the form tablename.stringname

We know our tablename, "settings". And when we look at what was set in the table, we see that we were setting strings.

dosettings = { -- set table and open
	red = 1,
	green = 0,
	blue = 0,
	alpha = 1, -- alpha of 0 = full transparent, 1 = full opaque
	font = "mono",
	fontsize = 12,
} -- closes table

So red, green, blue, alpha, font and fontsize are the names of the strings within the table.

So, we want to get our color values out of the table and into strings ... we would do the following:

redvalue = settings.red
greenvalue = settings.green
bluevalue = settings.blue
alphavalue = settings.alpha

NOW: String "redvalue" has a value of 1. String "greenvalue" has a value of 0. String "bluevalue" has a value of 0. String "alphavalue" has a value of 1.

And we can use these string in the function like so: cairo_set_source_rgba (cr, redvalue, greenvalue, bluevalue, alphavalue).

BUT we said earlier that we didnt want to have to send "dosomething" colorvalues every time we want to use the function.

When we call the function we only want to specify the font and fontsize

-- In main function call dosomething.
dosettings = { -- Open.
	fontsize = 12,
	font = "Sans",
} -- Close.

NOTE: with dictionary type tables, the order in which you enter your data doesn't matter.

HOWEVER, "dosomething" still needs color and alpha values if we have the line inside "dosomething".

redvalue = settings.red redvalue will be nil and we will get an error when we try and use it to set the color.

Conky: llua_do_call: function conky_test execution failed: /home/benjamin/lua/codetest.lua:11: error in function 'cairo_set_source_rgba'.
     argument #2 is 'nil'; 'number' expected. 

This error message pops up in the terminal. ALWAYS RUN CONKY FROM TERMINAL WHEN TESTING! :D.

Its quite helpful ... it tells us the name of the file that is causing the problem, it tells us the line number in that file where the error occurs and it tells us where in that line the error is.

Here is my code, lines 10 and 11:

red = nil
cairo_set_source_rgba (cr, red, 1, 1, 1)

And we can see the error on line 11, the second data position within the set source brackets ().

WE NEED TO CATCH THE NIL BEFORE ITS USED. The error occurred on line 11 (when we tried to use the string) not on line 10 (where the string was set to nill).

We can catch nil values using IF statements.

redvalue = settings.red
if redvalue == nil then
	redvalue = 1
end

You will usually find these short statements written on a single like like so.

redvalue = settings.red
if redvalue == nil then redvalue = 1 end

So the above is where our default settings come into play. If, when calling "dosomething" you don't want to specify color values instead you want to default to white.

If you dont set "red" in the function call in the main function then in "dosomething" settings.red will be nill and so redvalue will be nil. If redvalue is nil then the IF evaluation "if redvalue == nil then" is passed and the code inside the if is executed, setting redvalue to 1.

To expand that idea a bit we could set up default settings in the main script then use them in the function.

function conky_main
	-- Setup lines.
	-- Set default values for color, alpha, font and fontsize.
	default_red = 1
	default_green = 1
	default_blue = 1
	default_alpha = 1
	default_font = "mono"
	default_fontsize = 12

	-- Setup and call dosomething function.
	dosettings = {
		fontsize = 14
	}
	dosomething (dosettings)
	-- Closeout lines.
end -- Of main function.

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

function dosomething (settings)
	redvalue = settings.red
	if redvalue == nil then redvalue = default_red end

	greenvalue = settings.green
	if greenvalue == nil then greenvalue = default_green end

	bluevalue = settings.blue
	if bluevalue == nil then bluevalue = default_blue end

	alphavalue = settings.alpha
	if alphavalue == nil then alphavalue = default_alpha end

	fontvalue = settings.font
	if fontvalue == nil then fontvalue = default_font end

	fontsizevalue = settings.fontsize
	if fontsizevalue == nil then fontsizevalue = default_fontsize end

	-- Use strings to do something.
end

If we want the default we simply dont send the value in the function call.

If we want something other than the default then we need to set it in the call. If we set fontsize = 14 then when we look at the relevant lines in dosomething.

fontsizevalue = settings.fontsize
if fontsizevalue == nil then fontsizevalue = default_fontsize end

settings.fontsize is not equal to nil, it is equal to 14. The IF evaluation is not passed and the code inside the IF is not executed so when we use fontsizevalue in the function it retains its value of 14.

Clone this wiki locally