On Mon, 26 Oct 2015, Sven Schreiber wrote:
Am 26.10.2015 um 19:38 schrieb Allin Cottrell:
> On Mon, 26 Oct 2015, Sven Schreiber wrote:
>> <hansl>
>> open denmark # dummy dataset
>>
>> list lh = null
>>
>> if isnull(lh)
>> print "yep" # doesn't get printed
>> endif
>> </hansl>
>>
>> I actually can understand conceptually that the list 'lh' is
"empty"
>> rather than non-existing, but then I think either there should be this
>> (new) keyword 'empty' for lists, or isnull(lh) should return True/1 in
>> this case.
>
> The above looks funny, I agree. However, it clearly corresponds to the
> documentation of isnull():
>
> "Returns 0 if name is the identifier for a currently defined object, be
> it a scalar, a series, a matrix, list, string or bundle; otherwise
> returns 1."
>
> Is your suggestion that one should be able to say
>
> list lh = empty # instead of "= null"
>
> ?
Perhaps this might be a solution, yes; see also below. I stumbled over this
in real life in the context of optional function arguments, cf. the paragraph
from the user guide:
"
Optional list arguments
If a list argument to a function is optional, this should be indicated
by appending a default value of null, as in
function scalar myfunc (scalar y, list X[null])
In that case, if the caller gives null as the list argument (or simply omits
the last argument) the named list X inside the function will be empty. This
possibility can be detected using the nelem() function, which returns 0 for
an empty list.
"
So the doc is absolutely correct and even consistent. However, the syntax
itself is confusing IMO. When you call this example function myfunc() from
the guide and omit the optional list argument, there is no list X. But still
isnull(X) will return 0.
Ah, there is a list, but it's empty.
This is in contrast to other optional argument types (as also
correctly
explained in the doc), and this difference is probably the most important
issue here. Example:
<hansl>
function void noi(matrix *in[null])
if isnull(in)
print "yep" # get's printed!
endif
end function
noi()
</hansl>
I agree, that's inconsistent. I can't remember what the rationale
was supposed to be for creating an empty list pseudo-argument when
the caller omits an optional list argument, but at this point it
seems like a mistake. This case should be treated in the same way as
the matrix case; and the appropriate test for the function author to
use would be isnull(List) rather than nelem(List) == 0.
The problem seems to be a semantic inconsistency between the
"empty" concept and the 'null' property in hansl across variable
types. If you mark a list argument as optional with [null], then
nelem(X) == 0. But try to compute nelem(in) in my example with the
matrix, then gretl spits out an error "undefined symbol 'in'"!
I (now) think the "undefined symbol" response should occur in both
cases -- with an isnull() test called for to dodge the error.
So yes, one solution could be:
- If an optional list argument is not provided in a function call, make
isnull(X) true there. Perhaps even raise an error on attempting nelem()
there.
The error on using nelem() would be logically required.
- For an empty list in general, change the corresponding keyword from
"null"
to "empty"; and an empty list would not be null, but of course nelem(X) == 0.
- (How to deal with backwards compatibility, I don't know right now.)
And BTW, I just checked the situation with bundles, which is also awkward and
might need to distinguish between empty and null, too. See this example to
finish off an already long message:
<hansl>
function void nob(bundle *in[null])
if isnull(in) # true like with matrix type
print "yep" # get's printed!
endif
end function
nob()
OK, so bundle works like matrix: list is the odd man out.
bundle b2 = null
if isnull(b2) # false like with list type
print "b2 no" # not printed!
endif
</hansl>
Again, that's precisely what the doc says: "isnull()" means
non-existent. But then, either "null" should not be offered as an
initializer or isnull(), as a test for non-existence, should be
renamed.
Allin