lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Mon, Apr 20, 2015 at 6:24 AM, Robert Virding <rvirding@gmail.com> wrote:
> On 19 April 2015 at 00:19, Andrew Starks <andrew.starks@trms.com> wrote:
>>
>>
>>
>> On Saturday, April 18, 2015, Jan Behrens
>> <jbe-lua-l@public-software-group.org> wrote:
>>>
>>> On Sat, 18 Apr 2015 21:45:01 +0300
>>> <tonyp@acm.org> wrote:
>>>
>>> > As you can see in the sample code below, print does not show the
>>> > implicit nil (when it is last in the list of things to print), yet it
>>> > shows the explicit one.  However, in every other regard, nil seems to
>>> > behave the same in both cases.
>>> >
>>> > Can someone explain why there is a difference in 'nil' treatment
>>> > between these two? (I can see the compiler produces slightly
>>> > different code for each case but if they are equivalent, shouldn?t it
>>> > produce the exact same code for both cases?)
>>>
>>> It will be shown if you write:
>>>
>>> print(implicit()==nil, implicit(), implicit() or 'hidden')
>>> -->  true    nil     hidden
>>>
>>> or
>>>
>>> print(implicit()==nil, implicit() or 'hidden', (implicit()))
>>> -->  true    hidden  nil
>>>
>>> Generally "nil" and "none" (none = no value) are distinct when you call
>>> a function or return from a function. However, "none" gets implicitly
>>> converted to "nil" if you store it in a variable (or table) or if you
>>> put parenthesis around it (or use it in an expression where a single
>>> value is expected).
>>>
>>> If you use a function call as last(!) argument to another function
>>> call, e.g. f(arg1, arg2, g()), then multiple arguments returned from
>>> the last function will be passed to the outer function:
>>>
>>> function g()
>>>   return "Hello", "World"
>>> end
>>>
>>> print("Note:", g())
>>> -->  Note:   Hello   World
>>>
>>> That's why
>>>
>>> print(implicit()==nil, implicit() or 'hidden', implicit())
>>>
>>> won't print "nil", because implicit() is last in the argument list,
>>> which means that any variable number of return values (possibly zero
>>> return values) will be passed to the print function in addition to the
>>> two first arguments.
>>>
>>> >
>>> > And, is the difference evident only in print or elsewhere also?
>>>
>>> I think "print" and "select" are the two notable cases. You can use
>>> "select" to write your own functions to distinguish between "nil" and
>>> "none":
>>>
>>> function test(...)
>>>   if select("#", ...) == 0 then
>>>     return "no value given"
>>>   elseif ... == nil then
>>>     return "nil value given"
>>>   else
>>>     return "non-nil value given"
>>>   end
>>> end
>>>
>>> test()
>>> -->  no value given
>>> test(nil)
>>> --> nil value given
>>> test(false)
>>> --> non-nil value given
>>>
>>> >
>>> > I?m mostly interested if I should expect the exact same execution
>>> > path for code receiving either nil, or not?  Because obviously print
>>> > has a different execution for each case.
>>>
>>> If you store a return value in a local variable or table, then "none"
>>> always gets automatically converted to "nil". If you want to perform
>>> this conversion explicitly, use parenthesis. This is also helpful to
>>> truncate a variable number of return values. Compare:
>>>
>>> print("Pos:", string.find("Hello World", "World"))
>>> -->  Pos:    7       11
>>>
>>> print("Pos:", (string.find("Hello World", "World")))
>>> -->  Pos:    7
>>>
>>>
>>> >
>>> > Thank you.
>>>
>>> Kind Regards,
>>> Jan Behrens
>>>
>>>
>>> >
>>> > function implicit()
>>> >   return                      --implicit nil
>>> > end
>>> >
>>> > function explicit()
>>> >   return nil                  --explicit nil
>>> > end
>>> >
>>> > print(implicit()==nil,implicit() or 'hidden',implicit())
>>> > print(explicit()==nil,explicit() or 'shown',explicit())
>>> > print(implicit() == explicit())
>>> >
>>> > --- And here?s what the compiler output looks like for the two
>>> > functions ---
>>> >
>>> > function <implicit> (2 instructions at 004CC030)
>>> > 0 params, 2 slots, 0 upvalues, 0 locals, 0 constants, 0 functions
>>> >         1       [2]     RETURN          0 1
>>> >         2       [3]     RETURN          0 1
>>> >
>>> > function <explicit> (3 instructions at 004CE790)
>>> > 0 params, 2 slots, 0 upvalues, 0 locals, 0 constants, 0 functions
>>> >         1       [6]     LOADNIL         0 0
>>> >         2       [6]     RETURN          0 2
>>> >         3       [7]     RETURN          0 1
>>>
>>
>> There is one other case where nil/none appear. It almost never matters,
>> but it thwarted me from being too creative with tables: __index is always
>> adjust to one return value. So:
>>
>> __index = function(t, i, x)
>>     --x is always absent (empty/nil), btw. This would almost certainly
>> never matter, but it's true. I'm not sure how I know this, actually.it
>> wouldn't happen from trying `t[1, 2]`, because that's an error. Anyway...
>>  end
>>
>> f = function()
>> end
>>
>> print (select("#", __index()), select("#", f()))
>> -->1   0
>>
>> So you can never signal the difference between nothing and `nil` from your
>> index metamethod. Again, not complaining, I'm just sayin'.
>>
>
> Where does 'none' come from? I cannot find any mention of it in the 5.2
> manual.
>
> Robert
>
>

(Heads up, don't top-post on lua-l.)

The name is an invention for the sake of this discussion. The manual's
discussion is about how different numbers of return values are
handled. Specifically, a function can return any number of values,
from zero to however much can fit on the stack, and the return values
are coerced to a single value (nil if the function returned zero
values) if the results are forced into a context that only accepts a
single value (such as an expression or a non-final parameter to a
function call).

/s/ Adam