Page 1 of 2

[Solved] Wildcard index for a table

Posted: Mon Oct 31, 2016 9:39 pm
by PiFace
I got this problem while trying to make a placeholder/wildcard index for a table. Example: there's a table called t, with keys 1,3,9,13,100 (any number could be used) storing some value, but then I try to work with a value that was supposed to be on key 99. Of course t[99] will be nil, right? But as that kind of situation could happen any time, I need a placeholder value, preferably inside that same table, with a key that would not be used during the game (0, for example, or "placeholder", doesnt matter). What is the right approach for this? I've been trying to use the __index metamethod but errors wont stop popping, either stack overflow happens, or the table always uses the placeholder even when the value in a key is not nil.

TL;DR: how do I redirect a key with nil value in a table to a key with a placeholder value?

(I'm on the phone now, so I'll post a snippet later if needed)

Re: Wildcard index for a table

Posted: Mon Oct 31, 2016 9:48 pm
by pgimeno
Do you mean a default value? Like "if the index doesn't exist then return this"?

If so, it's simple:

Code: Select all

setmetatable(yourtable, {__index = function() return default_value end})
Example:

Code: Select all

yourtable = {[1] = "pineapple", [3] = "banana", [9] = "mango", [13] = "eggplant", [100] = "brocoli"}
local default_value = "orange"
setmetatable(yourtable, {__index = function() return default_value end})
print(yourtable[100]) -- prints "brocoli"
print(yourtable[99]) -- prints "orange"

Re: Wildcard index for a table

Posted: Mon Oct 31, 2016 9:51 pm
by sherpal
Using the __index metamethod is the right thing to do. Consider the following example:

Code: Select all

a = {
  __index = function(tab, key)
    return a.prototype
  end,
  prototype = 'this is the prototype value',
}

a[1] = 2
a.hello = 'hi'

setmetatable(a,a)

print(a[2])
print(a[1])
print(a.is_this_defined)
print(a.hello)
The __index method is called each time the field of a you're trying to access is nil.

Re: Wildcard index for a table

Posted: Mon Oct 31, 2016 10:00 pm
by kikito
You can also use "or <default value>". Like so:

Code: Select all

local tbl = {a=1}

print(tbl['a'] or 0) -- 1
print(tbl['b'] or 0) -- 0

Re: Wildcard index for a table

Posted: Tue Nov 01, 2016 1:01 am
by raidho36
That's preferable even, since if table returns default value if key doesn't exist, there's no way to tell if any element is having default value or doesn't exist.

Re: Wildcard index for a table

Posted: Tue Nov 01, 2016 1:12 am
by PiFace
Thank you guys! __index should have done the work a loong time ago, but I just forgot that there was a function somewhere else that was doing the following:
- it checked if the key held an image, if it did, it just skipped everything so it wouldn't load it again
- if it was nil, then it loaded a new image

But with __index it would always be different to nil, so no new images would be loaded, but I fixed that by checking if table[key]==table[0] (the key 0 was the default value)

Re: [Solved] Wildcard index for a table

Posted: Tue Nov 01, 2016 2:16 am
by raidho36
Or you could just check if it was nil, without doing everything else.

Re: [Solved] Wildcard index for a table

Posted: Tue Nov 01, 2016 2:17 pm
by PiFace
raidho36 wrote:Or you could just check if it was nil, without doing everything else.
I was actually doing that before, but that table is called in many different parts of the code, and I could use it elsewhere too, so it's more practical to use __index to avoid checking nil everytime I had to use the table. Checking nil would have to be there all the time, whereas with __index I have to check the default value only in 1 function.

Re: [Solved] Wildcard index for a table

Posted: Tue Nov 01, 2016 6:31 pm
by raidho36
But you didn't gain anything by that - if index metamethod is set, then it checks if value is nil and invokes the index.

Re: [Solved] Wildcard index for a table

Posted: Tue Nov 01, 2016 6:53 pm
by Nixola
But if the default value changes, it's one place to change instead of several scattered through the code.