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

RE: function-type-rest-list-element

  From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>

  But the analogy to VECTOR is false!  (VECTOR element-type) does not
  mean a vector all of whose current elements are of type element-type.
  Nor does it mean a vector constrained such that that all elements
  that can be stored into it are of type element-type.  The ambiguous
  language on CLtL p.47 might lead you to think that's what it means,
  but CLtL p.45 makes it clear.  For declaration, (VECTOR element-type)
  [via (ARRAY element-type (*))] means a one-dimensional array
  of the most specialized type that is capable of holding objects of
  type element-type.  Therefore, unless element-type is STRING-CHAR
  or BIT, or a subtype of one of them, this guarantees exactly nothing
  about the types of the elements of the vector.
  Maybe the element-type argument to these type-specifiers should mean
  something else, but that's what it means in Common Lisp as currently

The discussion of ARRAY type specifiers on p.45 is talking about the
permissible and expected representations of arrays, not of the possible
types of the elements of such arrays.  So what's on p.45 doesn't make
anything clear here.

What would you expect to be the type of the result of the following code:
 (let ((a ...))
   (declare (type (vector foo) a))
   (aref a 3))
I believe that in every implementation, the result should be of type FOO,
for any type FOO.  What is discussed on p.45 says that A might not be of
type (VECTOR FOO).  But this is unrelated to the question of whether
the elements of the array have any particular type.

Setting an element of A to be something that's not of type FOO is
an error.  The representation might allow it, because the new value
might be (TYPEP x (ARRAY-ELEMENT-TYPE A)), but that doesn't make it
correct.  It's just a matter of whether the array happened to
remember the precise type it was created with.

I haven't read any clean-up mail, so if you've talked about this
issue and resolved it somehow, please tell me.

    There's no reason why someone might not write a function type
    specifier with &REST being a supertype of LIST.  It just can't
    conflict with LIST.

  Yes, but I don't see what that could be useful for.

I was just referring to the statement in the first paragraph of the
Discussion: "the &REST argument declaration, if any, always be LIST
or a subtype of LIST..."

  Here's an interesting thought experiment that might shed some light on
  what the FUNCTION declaration, and the &REST type specifier nested
  within in, might be for.  Suppose you had an implementation that thought
  materializing &REST arguments as lists was too inefficient, especially
  if you didn't bother to do the (fairly simple) flow analysis needed to
  figure out that the list has dynamic extent and doesn't have to be
  consed in the heap.  So in your implementation, you made a new
  lambda-list keyword &REST2, which is just like &REST except that the
  value to which the parameter variable is bound is a stack-allocated
  object of some implementation-dependent type, and the only legal
  operations on it are LENGTH2, NTH2, DOLIST2, and APPLY2 (all just like
  the standard functions with similar names except that they take one
  of these funny objects as an argument where the standard functions
  take a list).
  The caller of a function doesn't need to know or care whether the
  function accepts its arguments with &REST or with &REST2.  If the
  FUNCTION declaration is for the benefit of callers, then the FUNCTION
  declaration should be independent of whether the callee is written with
  &REST or with &REST2.
  From this I conclude that the &REST type specifier nested within a
  FUNCTION declaration shouldn't say anything about lists.

One can't expect people to write function type specifiers in Common
Lisp with knowledge about the particular implementation's lambda-list-
keywords.  So I agree with you there.  But it's the only thing one
could write.

Indeed, there might not be any relationship between the lambda-list
in a function type specifier and the real lambda-list.
 (proclaim '(ftype (function (&key (:key1 integer :key2 string)) ...) f))
 (defun f (&optional k1 v1 k2 v2) ...)
should be OK if F is always called (F :KEY2 x) and the like.

Presumably the reason for having lambda-list-keywords in function type
specifiers is to indicate the range of number of arguments permissible.

The problem here is in trying to use lambda-list syntax for describing
function calls.  Already there's a slight contortion by having the
actual keywords be included in the function type for &KEY arguments.
So it isn't quite as simple as just taking the real lambda-list,
deleting all the init forms and &AUXen, and replacing parameter names
with their types.  But I think this way of looking at how function
type specifiers are derived is easier than starting with just a
positional approach (i.e., the second arg, if supplied, has to be of
type X, etc.) and then modifying it to also convey number-of-args and
keyword information.  Thus one would prefer having the type specifier
for the &REST argument be the real type specifier for the &REST argument.