a zero length list?

Discussion in 'AutoCAD' started by hutch, Dec 28, 2004.

  1. hutch

    hutch Guest

    for some functions a nil works okay for a zero lengh list.
    but what other way can I create/initialize a zero length list?
     
    hutch, Dec 28, 2004
    #1
  2. hutch

    Tom Smith Guest

    for some functions a nil works okay for a zero lengh list

    They are the same.

    Command: (listp nil)
    T

    Nil is a list.

    Command: (eq nil '())
    T
    Command: (eq nil (list))
    T

    It's the same as an empty list. You can denote an empty list more explicitly
    by quoting it or by using the list function with no arguments, as shown.

    It would be interesting to see an example where nil doesn't seem to serve to
    describe an empty list.
     
    Tom Smith, Dec 28, 2004
    #2
  3. There is no other way. NIL represents the
    empty list, exclusively.

    You create/initialize an empty list every time
    you use a variable, because every variable's
    initial value is NIL.
     
    Tony Tanzillo, Dec 28, 2004
    #3
  4. hutch

    hutch Guest

    when you run (nth 1 mylistl) you get an error if mylist is nil.
    .... now I suppose I could have tested to see if the list was nil first but that is not the point.
     
    hutch, Dec 28, 2004
    #4
  5. Which is exactly what it should do. You are asking for
    the 2nd element in a list of 0 elements. That's not much
    different than asking for the 9th element in a 4 element
    list. Either case, should result in an error.
     
    Tony Tanzillo, Dec 29, 2004
    #5
  6. hutch

    Tom Smith Guest

    If mylist might be empty, then your program needs to cover that eventuality, along the lines of

    (if mylist
    (do-something-with mylist)
    )

    which will return nil if mylist is empty.
     
    Tom Smith, Dec 29, 2004
    #6
  7. hutch

    ECCAD Guest

    How about:
    (setq mylist (list))
    Defines 'mylist' as type 'list', with nothing in it..Length 0

    Yo.

    Bob
     
    ECCAD, Dec 29, 2004
    #7
  8. hutch

    Tom Smith Guest

    (setq mylist (list))

    Bob, I mentioned that earlier. To my eye, (list) without arguments isn't
    quite as clear as a quoted empty list '(), but they're the same thing.
    Tony's point is interesting. Any new variable at all, if it hasn't been
    bound to a value, evaluates to nil and therefore is a list.

    Command: (eval newvar)
    nil
    Command: (listp newvar)
    T
    Command: (length newvar)
    0

    So if you want newvar to be a list, you don't have to do anything at all,
    just start working with it as such.

    Command: (setq newvar (append newvar '(a b c)))
    (A B C)
     
    Tom Smith, Dec 29, 2004
    #8
  9. ??

    (setq mylist (list)) => nil
    (type mylist) => nil

    Matt

     
    Matt Stachoni, Dec 31, 2004
    #9
  10. hutch

    Doug Broad Guest

    Tony and all,

    Though we take the nth behavior as a given, and must program
    accordingly, I would hardly say nth's evaluation is consistent with
    other functions that return similar values.

    Examples: (cadr nil) -> nil
    (caddr nil) -> nil

    Commonly, the cadr of the list is taken to mean the second
    element of the list. To be consistent, it would seem that
    nth should return a similar value (not an error).

    Nil is commonly used to represent false. Depending on the application
    nil returned as the nth value of a list could indicate non-existance of
    that element without stopping the program.

    A more accomodating version of nth could be appropriate for
    a particular application:

    ;;A less testy form that allows the the ndx to be
    ;;greater than the length of the list
    (defun snth (ndx lst) ;DCB
    (cond
    ((or
    (/= (type ndx) 'int)
    (atom lst)
    (< ndx (length lst)))
    (nth ndx lst)) ;;cause an appropriate error if necessary.
    (t nil))) ;;ndx is past end of list.


    Happy New Year.
     
    Doug Broad, Dec 31, 2004
    #10
  11. hutch

    Tom Smith Guest

    Doug, now I'm getting confused. First off, I've got a terrifying feeling
    that Tony may be wrong on a point, which would upset my whole world view.

    Command: (nth 1 nil)
    ; error: bad argument type: consp nil

    Fine, there's no second element of a zero-length list.

    Command: (nth 9 '(0 1 2 3))
    nil

    Oops! There's no 9th element of a 4-element list, but there's no error
    either! The error only happens when the list is empty. In fact, I can't see
    a difference in behavior between nth and your snth. They both error on an
    empty list, and return nil if the index is too great.

    Second, I had thought that the presumed error behavior on too high an index
    actually made some sense. For instance, a list might contain nil as an
    element.

    Command: (nth 0 '(t nil))
    T
    Command: (nth 1 '(t nil))
    nil
    Command: (nth 2 '(t nil))
    nil

    The return value is ambiguous here, I think -- you can't distinguish between
    nil actually being the second element, and the index being too high. To
    determine whether a certain element exists and really is nil, you'd need to
    always check the length too. Your thoughts?
     
    Tom Smith, Dec 31, 2004
    #11
  12. hutch

    Tom Smith Guest

    (setq mylist (list)) => nil
    That's just the weirdness of nil.

    (listp nil) => T
    (atom nil) => T
    (type nil) => nil

    Nil doesn't have a type. Bob's (setq mylist (list)) does define mylist as a
    list, but an empty list is nil and has no type. And as Tony impied, the setq
    wasn't necessary anyway -- the inital value of mylist would have been the
    same nil anyway.
     
    Tom Smith, Dec 31, 2004
    #12
  13. hutch

    Doug Broad Guest

    Tom,

    Good testing. How about this one?
    (nil is both an atom and a list)

    ;;Another form that allows the the ndx to be
    ;;greater than the length of the list
    (defun snth2 (ndx lst)
    (cond
    ((or
    (/= (type ndx) 'int)
    (not (listp lst))
    (< ndx (length lst)))
    (nth ndx lst)) ;;cause an appropriate error if necessary.
    (t nil))) ;;ndx is past end of list.

    The issues of whether a certain result is appropriate (nil or error)
    depend more on the application than a general statement.

    In most cases, it might be appropriate to error out when
    the index is too high. There might possibly be applications where
    returning nil versus error might be better.

    I agree that one drawback of allowing a nil return for an item out
    of range could easily lead to ambiguity for the case where nil elements
    are allowed.
     
    Doug Broad, Dec 31, 2004
    #13
  14. hutch

    Tom Smith Guest

    Good testing. How about this one?
    Yeah, I pointed that out to Matt. And weirder still (or maybe as a result of
    that), an empty list does not have a type.

    (type '()) => nil ( It ain't nothin')

    Atom is an odd duck in AutoLISP anyway, I've always thought. It doesn't have
    the traditional p suffix like other predicates, and AFAIK it's not any
    different from (not (listp <item>)), so it seems a bit redundant.

    I'll have to cogitate on the various nth issues. I can't recall when I've
    had problems with its return values. Generally when I've dealt with big
    lists I've done it recursively, or using a foreach, or else used an
    association list where the order didn't matter.
     
    Tom Smith, Dec 31, 2004
    #14
  15. Sorry, but I fail to see your point. Nil _is_ the value
    of the CDR of the last element of every list with the
    exception of 'dotted lists' (simply because every normal
    list is terminated by nil - while dotted lists are terminated
    by the last element).

    When you create a list, you can do it using either of
    the following two basic semantic conventions, the
    first and most common one being 'short-hand' for the
    second:

    (setq mylist '(1 2 3))

    (setq mylist '(1 2 3 . NIL))

    So in reality (and what the PRINT function hides
    from you), is the real composition of a normal or
    'non-dotted' list:

    (1 2 3 . NIL)

    Which (print) displays as simply

    (1 2 3)

    Given that, I fail to see any relevance between the
    use of NIL to terminate a list (the result of CDR), and
    what NTH should do when its given an invalid index.

    I don't see any point to debating a fundamental and
    widely accepted principles of software engineering and
    language/api design, such as this question. In that
    sense, you would find yourself in the minority, especially
    when you consider that it isn't a language-specific issue.

    So, I see no legitimate reason for NTH to return anything
    but an error if its given an invalid index. I also see no
    relevance between that and the result of CDR or its
    derivatives.
     
    Tony Tanzillo, Jan 1, 2005
    #15
  16. The error should happen in any case where the index
    is not valid (IMO). It doesn't work that way, but it
    should. Try using just about any other language that
    supports vector type data structures with indexed access
    methods, and you'll see that an error is always triggered
    when an invalid index is used.

    The point being that a result of NIL, can mean one of
    two things: The value of the list element at the specified
    index is NIL, or the specified index is invalid. This kind of
    behavior is what leads to buggy code, and it means you
    must include your own runtime test using (length) if you
    want robust code that properly fails when an index is
    invalid.

    The most notorious and difficult to find bugs in LISP, are
    often a result of LISP's non-declarative, typeless nature.
    For example, if you define a function that expects an
    integer argument, and don't check to ensure that the
    argument passed to it really is an integer, then the bug
    that results can manifest miles away from the defective
    code. In a declarative language, where you must declare
    the types of arguments and variables, a bug like that
    will never see the light of day (e.g., the compiler will
    detect it).

    Perhaps that's why grown-up, industrial strength LISP
    implementations like Common LISP, support variable
    and argument type declarations and integral type
    checking.
     
    Tony Tanzillo, Jan 1, 2005
    #16
  17. hutch

    Doug Broad Guest

    Tony,

    Yes I knew all that as I certainly hope you know by now.

    My point was that car/cdr derivatives return different values
    than nth (when the intention is to access particular elements)and
    that that should be considered when designing a particular
    application. For instance, when 2d and 3d point lists are allowed
    and the application needs to determine the z coordinate, it would
    usually be unfortunate if it errored out rather than using an
    assumed (current z) elevation if that were acceptable.

    ;Code examples
    (setq z (cond ((caddr p))(0.0))) ;OK for 2d and 3d points.
    (setq z (cond ((nth 2 p)) (0.0))) ;Problematic if 2d points permitted.
    (setq z (cond ((= (length p) 3) (nth 2 p)) (0.0)));Seems silly just to avoid error.

    There are many similar such examples that I could cite where
    default values could be allowed and for which derivatives of cdr/car
    may be tedious to implement.

    Certainly if I had a fixed length array in another language I would
    expect that to fail if I tried to access an element past the end. To do
    otherwise would risk memory leaks... But LISP lists can be variable in
    length and the variability of the length can be used logically in many ways.
     
    Doug Broad, Jan 1, 2005
    #17
  18. Tony,
    Having it both ways is not an option. Either the
    indexed accessor is going to fail with an invalid
    index, or its not. What you are saying is that by
    not failing, there is some usefulness to that.

    What I am saying is that by not failing, there is
    a problem with that, in most cases where a LIST
    is being used like an array.

    Since there are alternative ways of testing a
    list whose length is not predictable or where the
    number of elements is not assumed, they should
    be used for that case, and NTH should be used
    for the case where there is an assumption about
    the length of the list, and so it should fail if an
    invalid index is given.

    The decision to use NTH from the outset should
    take into consideration the intent that is conveyed
    by its use (e.g., it implies that the LIST is used like
    an array/vector, not as a list of arbitrary length).
     
    Tony Tanzillo, Jan 1, 2005
    #18
  19. I was really questioning the statement
    Where mylist is not of type LIST.

    Matt

     
    Matt Stachoni, Jan 3, 2005
    #19
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.