• Subject: Re: vararg, table and nil - again
• From: Rici Lake <lua@...>
• Date: Thu, 28 Jun 2007 15:05:50 -0500

```
On 28-Jun-07, at 2:31 PM, PA wrote:

```
```Hello,

```
I guess I'm still completely confused about how to deal with vararg, table and nil values...
```
(1) vararg can have nil values
```
```
Yes

```
(2) table behavior seems to be, errr, confusing when confronted with nil values
```
Yes, again.

```
```
local aTable = { nil, true }
print( #aTable )
> 2
-- Hmmm... two keys...
```
```
That use of # is not precisely defined, though. It could return 0.
Specifically, #t returns some i such that:
t[i+1] == nil
and
i == 0  or  t[i] ~= nil

Try aTable = { nil, true, nil }

```
```

print( table.maxn( aTable ) )
> 2
-- table.maxn agrees, two keys
```
```
maxn is the largest positive numeric key or 0
a = {[math.pi] = "pi"}; print(table.maxn(a))

```
```print( table.getn( aTable ) )
> 2
-- Even table.getn seems to agree, two keys
```
```
getn is the same as # (and deprecated)
```
```

for aKey, aValue in pairs( aTable ) do
print( aKey, aValue )
end
> 2       true
-- The pairs iterator seems to think there is only one key though
```
```
pairs() gives you all keys which don't map to nil

```
```

for aKey, aValue in ipairs( aTable ) do
print( aKey, aValue )
end
-- And ipairs doesn't see any keys at all
```
```
ipairs iterates with integer keys starting at 1 until a key
is found which maps to nil.
```
```
```
This is all good and well, if slightly confusing... that said... how does one build a vararg at runtime considering all this?!?
```
One idiom is the following:

local args = {n=select('#', ...), ...}

for i = 1, args.n do --[[something]] end

----

There are a couple of things in your code:

```
```    for anIndex = 1, select( '#', ... ) - 1 do
```
```
Why are you subtracting 1? Do you want to drop the last argument?

```
```someArguments[ #someArguments + 1 ] = aValue
```
```
This is actually a useful idiom, but it doesn't do what you
think it does, I think.

Let's say that someArguments is a dense array; it has no embedded nils.
That's trivially true for someArguments = {}

Now, we apply induction:

If you do
someArguments[#someArguments + 1] = "some non nil value"
then someArguments is still a dense array and #someArguments is
the number of non-nil elements.

If you do
someArguments[#someArguments + 1] = nil
```
then someArguments is unchanged (since someArguments[#someArguments+1] was nil, by the definition of #). So someArguments is still a dense array, and #someArguments is the number of non-nil elements (i.e. it hasn't changed either.)
```
Consequently, at every step, someArguments is a dense array, and the
loop has the effect of collecting the non-nil values of aValue.

However, I gather that's not what you wanted; you wanted to map
the string "" to nil, without changing the indices of the following
elements. If you'd set things up as above, you could do this:

function replace_empty_with_nil(...)
local args = {n=select("#", ...), ...}
for i = 1, args.n do
if args[i] == "" then args[i] = nil end
end
return args
end

Note that the returned value has the 'n' key set to its length,
which can then be given to unpack:

someArguments = replace_empty_with_nil(f())
aHandler(unpack(someArguments, 1, someArguments.n))

<Digression>
If this seems like a reversion to Lua 4 and the old 'n'
field, so be it.... you could use a different key if you liked
</Digression>

```

• Follow-Ups:
• References: