From: David Bakhash
Subject: declaration propogation...
Date: 
Message-ID: <cxjaf1ncja6.fsf@engc.bu.edu>
hey,

I hate re-writing declarations.  But sometimes I do it because I am
not sure about how they propogate down.  for example:

(defun f (x)
  (let ((a (make-array ...))) ; we're defining `a' here...
    (declare (type (simple-array fixnum (2 3)) a)) ; declaration
    (do-something)
    .
    .
    .
    (labels ((f-int () ; this function uses `a' defined above
	        (declare (type (simple-array fixnum (2 3)) a) ; is this redundant?
			 (special a)                          ; is `a' considered special?
			                                      ; (with respect to `f-int'?)
			 (dynamic-extent a)                   ; when is this appropriate?
			 )
		(loop for i below x
		  do
		  (setf (row-major-aref a i) (something)))
		))
      (f-int)
      (row-major-aref a 1))))  ; return value (which is an element in array `a'

Questions:

1) Is my declaration of the array `a' redundant when I do it the 2nd
   time?  i.e. can the forms inside the labels form see the
   declaration from the let above it?

2) in the labels form, is the variable `a' considered to be `special'
   since it's defined outside of `f-int'?

3) What about the `dynamic-extent' declaration?  When is that
   appropriate?  Is it appropriate here?  if not, then why not?

dave

From: Lyman S. Taylor
Subject: Re: declaration propogation...
Date: 
Message-ID: <732hko$oie@pravda.cc.gatech.edu>
In article <···············@engc.bu.edu>, David Bakhash  <·····@bu.edu> wrote:
>hey,

>Questions:
>
>1) Is my declaration of the array `a' redundant when I do it the 2nd
>   time?  i.e. can the forms inside the labels form see the
>   declaration from the let above it?

   As written I don't think  it is redundant. However, it is different
   from the declaratoin above it. that is the only reason.  More on that
   later. 

   To the question not asked.  Is it necesary?  No. 

    (let  (  (a ... )   )

         ... body of let ....  )


     the variable A is visible through all the forms and expressions 
     within the body of let until some nested definition says differently.
     [ Your declaration happens to "say so". ]    If you don't introduce
     a new definition of A in some nested form,  A (and its declaration)
     should percolate  through all the whole body. 
     
     Let creates a new lexical scope.  


>2) in the labels form, is the variable `a' considered to be `special'
>   since it's defined outside of `f-int'?

    No. 

    Special variables are  dynmacially scoped.  Let doesn't create
    dynamically scoped variables by default.   You have to explicitly 
    state they are special. 

    "special" variable are  globals or other nonlocally defined 
     psudeo-global variables.  Pusdeo-global meaning that they typically
     take on they value outside the local context.  Conceptually, the value it 
     "looked up" dynamically on the call stack. 

     The let encloses the label call so that isn't outside the context.
     As opposed to the following example: 

      (defun  demo1 ( x )    
          (outer-demo x ))

      (defun demo2  (x )
          (declare (special  x))
          (list (inner-demo) (outer-demo (1+ x ))))

      (defun  outer-demo ( x ) 
        (declare (special x ) )
        (inner-demo )  )

      (defun  inner-demo ()
         (declare (special x ))
          (+ x x ))
     
      (demo1  3 )   ==>  6 
      (demo2  3 )   ==> ( 6 8 )

      Here the variable x inside of the body of INNER-DEMO takes on the 
      value last assigned to x in the previous calls.       


>
>3) What about the `dynamic-extent' declaration?  When is that
>   appropriate?  Is it appropriate here?  if not, then why not?

      [ I hope I explain this one right.... I'm more sure of the above.] 

      I think you can leave this out.  Most nontrival implementation should
      be able to figure this out. 

      It is appropriate when the implementation couldn't figure this
      out by itself.    A sufficiently smart implementation shouldn't
      need it.  :-)     If made it probably should be with A's original
      declaration. 


       (let   ( ( a  1 ) )
           (+ a  a ) )

     A is bound to at the beginning where the LET is executed/evaluated
     and is unbound when that LET exits.   When that LET finishes 
     there is no need for A anymore. 

     This is in contrast to the following example: 

     (setf my-closure    (let   ( ( a 1 ) ) #'(lambda () (+ a a ))) )


     If I subsequently invoke this closure 

       (funcall my-closure )    ==>  2 

     then a's value will be called upon after the LET has exited.. 

     If you leave out the declaration then a non sufficently smart 
     implemenation will go through the effort to make sure A stays around
     until nothing needs it anymore.   Which in the first case happens to
     coincide with the exit of the LET. Perhaps a more efficient
     allocation for the memory that holds the reference "address" that
     "A" stands for can be made. 


   
           
         


-- 
Lyman S. Taylor            "emacs - ... Do NOT use vi to edit your programs.  
(·····@cc.gatech.edu)              Watching you stuggle through the 
				   edit/compile/debug cycle [with ] vi 
				    will make me despair of  your sanity..."
				P. N. Hilfinger  CS 164 Fall '92 Syllabus
From: Steve Gonedes
Subject: Re: declaration propogation...
Date: 
Message-ID: <m2u2zu9412.fsf@KludgeUnix.com>
David Bakhash <·····@bu.edu> writes:

< I hate re-writing declarations.  But sometimes I do it because I am
< not sure about how they propogate down.  for example:

They make it hard to read the program sometimes. What I usually do for
arrays is write a macro and function pair, like so.

(defsetf dict-parent (i dict) (val)
  `(setf (aref ,dict ,i 1) (ldb (byte 16 0) ,val)))

(defun dict-parent (i dict)
  (declare (optimize speed (safety 1) (space 0)) (fixnum i)
           (type (simple-array (unsigned-short) (35023 3)) dict))
  (the unsigned-short (aref dict i 1)))

Maybe your lisp has some way to help with declarations? In acl you can
use :explain ...

(defun find-child-node (dict parent child)
  (declare (optimize speed (safety 0))
      (fixnum parent child) (:explain :calls))
  ...)

The macro-accessor's usually work fairly well for me. I also wrote a
macro called def-optimize which you can do something like,

(def-optimize this ((i fixnum) (vec simple-vector)) (:speed (:safety 0))
  "The optional doc string screwed me up at first"
  (svref vec i))

which expands into

(DEFUN THIS (I VEC)
  "The optional doc string screwed me up at first"
  (DECLARE (OPTIMIZE (SAFETY 0) (SPEED 3) (DEBUG 2)) (FIXNUM I)
           (SIMPLE-VECTOR VEC))
  (SVREF VEC I))

. The declaration order reminds me of pascal; it seems easier to read
with the declaration following the variable I think because it's
easier to find the left paren then the right paren. Unfortunatly you
can't do (fixnum a b c ...) this way though. The docstring was a pain
because I wanted to be able to do

(def-optimize this (var) "Does thing with var" (thing-with var)).

Anyway, I thought the macro was hard to read and somewhat pointless so
I don't use it, but maybe something along these lines would work for
you?