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