Jump to content




unpack nil values


  • You cannot reply to this topic
3 replies to this topic

#1 hbomb79

  • Members
  • 352 posts
  • LocationOrewa, New Zealand

Posted 18 June 2016 - 08:25 AM

When trying to unpack a table containing nil values using unpack I realised that this doesn't work as it will stop once the first nil value has been encountered, not dissimilar to ipairs.

Inline with the Lua documentation, I created my own implementation that handles nil values just how I need it to with the catch that the tables length must be supplied (n):

function unpack (t, i, n)
  i = i or 1
  if i > n then return end
  return t[i], unpack(t, i + 1, n) --# stack overflow occurs here
end

The issue is I am encountering stack overflows, unlike the built in `table.unpack`.

If I unpack `{nil, nil, "value"}` I get `{}`, with my custom unpack I get `{[3] = "value"}`. My goal is to create a function that does this without overflowing the stack when too many values are supplied.


For context: I need to be able to unpack nil values because I am using an argument resolution system that loops through each given argument (vararg).

The function is configured to take arguments x, y, and z. If I only want to define 'z', I can call it with `nil, nil, "value"` in normal Lua. I need this to be possible from a table as I am parsing the arguments through XML.

#2 Bomb Bloke

    Hobbyist Coder

  • Moderators
  • 7,099 posts
  • LocationTasmania (AU)

Posted 18 June 2016 - 09:16 AM

table.maxn(myTable) gets you the highest numeric index in your table (regardless as to where the first nil index is); no need to supply "n".

I suspect you don't need to do any of this, because of the automatic "arg" table constructed when building a vararg function:

local function varArgFunction(...)
	print(arg.n)  --> 2
end

varArgFunction(nil, "fruit")

But if you really require it:

function unpack(tbl, strt, fnsh)
	if not strt then strt = 1 end
	if not fnsh then fnsh = table.maxn(tbl) end
	if strt > fnsh then return end

	local str, cnt = {}, 1
	for i = strt, fnsh do
		str[cnt] = "tbl[" .. i .. "]"
		cnt = cnt + 1
	end
	
	return loadstring("local tbl = ... return " .. table.concat(str, ","))(tbl)
end

Edited by Bomb Bloke, 18 June 2016 - 09:21 AM.


#3 hbomb79

  • Members
  • 352 posts
  • LocationOrewa, New Zealand

Posted 18 June 2016 - 09:22 AM

I do need this because I am constructing the vararg dynamically, I cannot hard code the 'nil's into the function call; instead they need to be dynamically unpacked. If I don't use an unpack and pass just unpack the table normally I get an empty result (as stated in the 'for context' section)

I will work on implementing your answer, thanks for your help. I had not thought of using a solution like the one you have produced.

EDIT: Tested and it works great. Thanks for your help Bomb Bloke

Edited by Hbomb_79, 18 June 2016 - 09:47 AM.


#4 theoriginalbit

    Semi-Professional ComputerCrafter

  • Moderators
  • 7,332 posts
  • LocationAustralia

Posted 18 June 2016 - 01:45 PM

View PostBomb Bloke, on 18 June 2016 - 09:16 AM, said:

...
You and your loadstring, its definitely not needed here.

Take the following code
function setCoords( ... )
  local coords = { ... }
  local x, y, z = unpack( coords )
  print("coords: ", tostring(x), tostring(y), tostring(z))
end

setCoords(1, nil, 5)
this would fail as per your issue Hbomb, x would be 1, but everything else would be nil.

However, unpack is amazing, and can take a start and end index for the unpack, combining this with table.maxn solves the issue
function setCoords( ... )
  local coords = { ... }
  local x, y, z = unpack( coords, 1, table.maxn(coords) )
  print("coords: ", tostring(x), tostring(y), tostring(z))
end

setCoords(1, nil, 5)

EDIT: it should also be noted that as per Bomb's other suggestion you can also use arg.n
function setCoords( ... )
  local x, y, z = unpack( arg, 1, arg.n )
  print("coords: ", tostring(x), tostring(y), tostring(z))
end

setCoords(1, nil, 5)

Edited by theoriginalbit, 18 June 2016 - 01:48 PM.






1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users