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

Issue: DECLARE-TYPE-FREE (Version 8)



I previously sent out version 7, but the subject line said Version 6.
Sorry.

This is another try at wording. This time I said "during the 
execution of any expression within the scope of the declaration."

That is, the declaration implies an assertion at a given time, 
but the time is "the evaluation of expressions" within the
scope of the declaration. This is the strongest assertion, and
allows specialized variable representation.

I think FUNCTION-TYPE-ARGUMENT-TYPE-SEMANTICS
interacts with this.


!
Forum:         Cleanup
Issue:         DECLARE-TYPE-FREE
References:    CLtL p.158
	       DECLARATION-SCOPE
Related issues: FUNCTION-TYPE-ARGUMENT-TYPE-SEMANTICS
	       DECLARATION-SCOPE
Category:      CLARIFICATION/ADDITION

Edit history:  Version 1, 18-Sep-88, Moon
               Version 2, 22-Sep-88, Moon
                (small edits to reflect mail discussion)
               Version 3, 22-Sep-88, Masinter
               Version 4, 27-Sep-88, JonL 
	       Version 5, 30-Sep-88, Masinter (cost to implementors)
	       Version 6, 06-Oct-88, Pitman (minor edits in Discussion)
	       Version 7,  5-Dec-88, Masinter (scope->extent)
	       Version 8,  7-Dec-88, Masinter (back to scope)

Problem description:

  Section 9.2 of CLtL, p158, says that a declaration specifier like
  (TYPE type var1 var2 ...) "... affects only variable bindings".  
  Since declarations can occur in contexts other than establishing 
  "variable bindings", most people interpret this statement to mean 
  that type declarations not in such context are either (1) completely 
  to be ignored, or (2) invalid CL  syntax.  Thus both of the following 
  forms would be suspect in that the type declarations could not have 
  any effect:

    (if (and (typep x 'fixnum) (typep y 'fixnum))
	(locally (declare (fixnum x y))		    ;LOCALLY does not bind
	  ...algorithm using x and y...)	    ; any variables.
	...similar algorithm using x and y...)

    (let ((y 'foo))
      (setq y 10)
      (let ((x 5))				    ;'y' is not being bound in
        (declare (fixnum y))			    ; this particular context.
        (incf y)
         ...random algorithm...))


Proposal (DECLARE-TYPE-FREE:ALLOW):
  
  Specify that a type declaration does not only "affect variable bindings";
  rather, type declarations are legal in all declarations. The interpretation
  of a type declaration is that, during the execution of any expression 
  within the scope of the declaration,  it is an error for the value of
  the declared variable not to be of the declared type. For declarations
  that are associated with variable bindings, the type declaration also
  applies to the initial binding of the variable. In the special case
  of a declaration for which there are no executable expressions
  within the scope of the declaration (e.g., (locally (declare (integer x)))),
  the result is as if there were executable expressions.


Examples:

;; this is an error:
;; the assertion that x is a fixnum is violated between the two 
;; calls to (zap)

	(let ((x 12) (y 'foo))
	  (flet ((zap () (rotatef x y)))
	    (locally (declare (fixnum x))
	      (zap)
	      (zap)
	      x)))

;; this is an error, because the assertion that x is a fixnum
;; is violated during the call to zap, even though few 
;; implementations will be able to check:

	(let ((x 12) (y 'foo))
	  (flet ((zap ()
		   (rotatef x y)
		   (rotatef x y)))
	    (locally (declare (fixnum x))
	      (zap)
	      x)))



;; this is an error, even though the violation of the type
;; constraint happens after the form with the declaration
;; is exited.

(let ((f (let ((x 3))  (declare (fixnum x)) #'(lambda (z) (incf x z)))))
   (funcall f 4.3))


Rationale:

  This proposal enables optimizing compilers to make use of the otherwise
  ignored type information.  Many people have often asked  for it, and
  there is no strong reason to forbid it.
  
Current practice:

  Lucid Common Lisp allows "free" type declarations;  under some 
  circumstances the compiler issues a warning message that such usage 
  is an extension to Common Lisp.

Cost to Implementors:

  Implementations that might currently warn about such declarations
  would have to remove the warning; otherwise, it is valid to ignore 
  type declarations.

Cost to Users:

  None, this is a compatible addition.

Cost of non-adoption:

  Common Lisp will be less self-consistent.

Benefits:

  Programmers will be able to use type declaration to express their
  intent, rather than having to manually insert THE wrappers around 
  every reference.


Esthetics:

  It is a simpler interpretation for type declaration specifiers, with
  fewer special cases; hence reduces the number of exceptions in the
  language.

Discussion:

  Another cleanup issue, DECLARATION-SCOPE, addresses the scope of 
  declarations. This proposal carefully uses the phrase "within the 
  scope of the declaration" to avoid confounding the two issues. 

  This issue has been discussed at the Fort Collins X3J13 meeting in
  November 1987, and at length on the various electronic mailing lists.

  At least one current implementation is able to generate more efficient
  code when declarations are associated with a particular binding, since
  it then has the option to choose type-specific specialized storage for 
  the runtime value of the variable.  So, for example, 

      (let ((x v)) (declare (type float x)) (+ x x))

  is sometimes more efficient than

      (let ((x v)) (locally (declare (type float x)) (+ x x)))

  However, the local type declarations allowed by this proposal do
  provide some useful information, even if it is not the *most* useful.
  It is possible for a sufficiently "smart" compiler to infer the 
  equivalent of a "binding declaration" when it can ascertain that the 
  type of the binding value -- 'v' above -- is commensurate with the 
  type locally declared over the scope of usage of the variable.

  It may be useful for a compiler to issue a warning whenever it finds
  nested type declarations referring to the same variable and the
  intersection of the declared types is null.

  Documentation might want to discuss the style implications of
  nested declarations intersecting. The interesting cases are:
   - An inner declaration could be a subtype of an outer one.
     This is the most useful case and probably the only one to
     be encouraged in code written by humans. e.g.,
       (locally (declare (type number x))
         (locally (declare (type integer x))
	   ...use X as integer...))
   - An outer declaration could be a subtype of an inner one.
     This is useless but harmless. It might happen as the result
     of certain macro situations. e.g.,
       (locally (declare (type integer x))
	 (locally (declare (type number x))
	   ...use X as integer...))
   - Two types may only partially overlap. This would presumably
     happen only as the result of a macro expansion.
       (locally (declare (type fixnum x))
         (locally (declare (type (or bit package) x))
           ...use X as BIT...))