From: Damien Kick
Subject: Macros, declare, and locally
Date: 
Message-ID: <3bv5eumt.fsf@email.mot.com>
A while back, I'd asked about CL idioms for conditionally declaring
optimizations <http://tinyurl.com/6z8ud>.  Well, the subject has come
up for me again but I've discovered a few more things since I first
asked the question.  I've recently stumbled across the DECLARE-MACROS
issue <http://tinyurl.com/6mw2d>, hiding right out in the open <grin>,
which contains snippets of helpful work arounds for not being able to
write macros which conditionally expand into DECLARE expressions.  I
was very excited to find the snippet which used "#."

    (EVAL-WHEN (EVAL COMPILE LOAD)
      (DEFVAR *STANDARD-SPEED-AND-SAFETY* '((SPEED 0) (SAFETY 3))))
    (DEFUN FOO ()
      (DECLARE (OPTIMIZE #.*STANDARD-SPEED-AND-SAFETY*))
      ...)

because it seemed the simplest to me until somebody mentioned that
read-time evaluation is seen as a potential security risk.  Apparently
GBBopen uses macros which expand into a LOCALLY expression, a
technique which avoids this problem.  Indeed, I don't find any
restriction on macro forms not being able to expand into LOCALLY
expressions like I do for DECLARE expressions in the CLHS.  Are the
following really equivalent?

    (defun foo ()
      (declare (optimize (speed 0) (safety 3)))
      ...)
    (defun bar ()
      (locally (declare (optimize (speed 0) (safety 3))))
      ...)

What I don't understand, assuming my understanding of the situation
with macro forms expanding into LOCALLY or DECLARE forms is correct
and that FOO and BAR are equivalent, is why one would bother to
introduce this restriction for DECLARE only.  Within the rational
given in DECLARE-MACROS is that the restriction would no longer
require, one finds the following:

    * In order to find the end of the declarations, MACROEXPAND must
      be called until a non-macro form is seen or until a macro does
      not expand into a macro.  In some interpreters which do macro
      expansion on the fly, this may cause inefficiency because macro
      expansion of the first form in a body must be done twice. In
      implementations where this is optimized, the implementor may
      resent the fact that an optimization is needed in the first
      place.

But if one can write a macro which expands into a LOCALLY form, does
this not mean that one must continue to call MACROEXPAND to find the
end of the declarations?

From: Christophe Rhodes
Subject: Re: Macros, declare, and locally
Date: 
Message-ID: <sq8y4xiztp.fsf@cam.ac.uk>
Damien Kick <······@email.mot.com> writes:

> Are the following really equivalent?
>
>     (defun foo ()
>       (declare (optimize (speed 0) (safety 3)))
>       ...)
>     (defun bar ()
>       (locally (declare (optimize (speed 0) (safety 3))))
>       ...)

I believe not, no.  BAR is permitted, assuming a non-SAFETY-3
prevailing compilation environment, not to perform argument count
checking, whereas FOO must perform such checking.  That is, (FOO 1)
must signal an error, while (BAR 1) need not.

Christophe
From: dkixk
Subject: Re: Macros, declare, and locally
Date: 
Message-ID: <1110324665.334403.225360@z14g2000cwz.googlegroups.com>
Christophe Rhodes wrote:
> Damien Kick <······@email.mot.com> writes:
>
> > Are the following really equivalent?
> >
> >     (defun foo ()
> >       (declare (optimize (speed 0) (safety 3)))
> >       ...)
> >     (defun bar ()
> >       (locally (declare (optimize (speed 0) (safety 3))))
> >       ...)
>
> I believe not, no.  [...]

Ah, right.  Sorry.

(locally (declare ...) (defun bar ...))

This bar would be equivalent to foo, correct?
From: Joerg Hoehle
Subject: Re: Macros, declare, and locally
Date: 
Message-ID: <uu0njk360.fsf@users.sourceforge.net>
"dkixk" <······@gmail.com> writes:
> (locally (declare ...) (defun bar ...))
> This bar would be equivalent to foo, correct?
A priori, yes, or so it seems.
Whether all implementations treat it equivalently is another topic.
Also, the nesting causes automatic indentation in Emacs to indent
defun, which may not be wished for.

If your intent is something like
> *STANDARD-SPEED-AND-SAFETY* '((SPEED 0) (SAFETY 3))
then why don't you look into compilation units?

IMHO, compilation units can be used to supply a default across
multiple files, which I only supersede in very rare cases using
(declare (optimize safety)) os some such thing.

Also, putting general declarations outside each function source allows
you to make use of extensions like CMUCL's ext:optimize-interface
declaration.

Regards,
	Jorg Hohle
Telekom/T-Systems Technology Center
From: Damien Kick
Subject: Re: Macros, declare, and locally
Date: 
Message-ID: <br9rb3sf.fsf@email.mot.com>
Joerg Hoehle <······@users.sourceforge.net> writes:

> "dkixk" <······@gmail.com> writes:
> > (locally (declare ...) (defun bar ...))
> > This bar would be equivalent to foo, correct?
> A priori, yes, or so it seems.
> Whether all implementations treat it equivalently is another topic.

Sounds like an interesting topic... would anyone be able to elaborate,
please?

> If your intent is something like
> > *STANDARD-SPEED-AND-SAFETY* '((SPEED 0) (SAFETY 3))
> then why don't you look into compilation units?

My former 2nd order ignorance about compilation units <smile>...

> IMHO, compilation units can be used to supply a default across
> multiple files, which I only supersede in very rare cases using
> (declare (optimize safety)) os some such thing.

The CLHS mentions only one standard option for WITH-COMPILATION-UNITS
which effects whether or not warnings are deferred.  CMUCL happens to
provide an extension that effects optimization levels exactly like I
want to be able to do.  However, I can't seem to find any similar
extension mentioned in the Allegro documentation.  Am I just missing
it?  This doesn't seem to be a common extension; is it?

> ALSO, putting general declarations outside each function source
> allows you to make use of extensions like CMUCL's
> ext:optimize-interface declaration.

<nod> Thanks for the tip.
From: Brian Downing
Subject: Re: Macros, declare, and locally
Date: 
Message-ID: <M_aYd.115998$4q6.72301@attbi_s01>
In article <························@z14g2000cwz.googlegroups.com>,
dkixk <······@gmail.com> wrote:
> Ah, right.  Sorry.
> 
> (locally (declare ...) (defun bar ...))
> 
> This bar would be equivalent to foo, correct?

Not for the general case of (declare ...).

;; assuming x is not globally special...

(defun foo (&optional (#1=x #2=x))
  (declare (special x))
  ;; #1=x is special, #2=x is lexical
  ...)

(locally (declare (special x))
  (defun bar (&optional (#1=x #2=x))
    ;; #1=x is lexical, #2=x is special
    ...))

-bcd
-- 
*** Brian Downing <bdowning at lavos dot net> 
From: Kalle Olavi Niemitalo
Subject: Re: Macros, declare, and locally
Date: 
Message-ID: <87is41buks.fsf@Astalo.kon.iki.fi>
Damien Kick <······@email.mot.com> writes:

> But if one can write a macro which expands into a LOCALLY form, does
> this not mean that one must continue to call MACROEXPAND to find the
> end of the declarations?

No, it doesn't.  A LOCALLY form terminates the list of local
declarations, just like any other form would:

  (defun x ()
    (declare (special *y*))
    (locally (declare (optimize safety)))
    "foo"
    (declare (ignore z)))

Here, "foo" is not a documentation string; and (declare (ignore z))
is a form to be evaluated, with undefined consequences.

If you splice in the body of the LOCALLY form:

  (defun x ()
    (declare (special *y*))
    (declare (optimize safety))
    "foo"
    (declare (ignore z)))

then "foo" becomes a documentation string, and the function
returns nil.

Now suppose you had a macro there instead:

  (defun x ()
    (declare (special *y*))
    (clever-macro)
    "foo"
    (declare (ignore z)))

Because (clever-macro) cannot expand to a declaration, the
compiler can figure out that the declarations end there, without
expanding the macro.
From: Kent M Pitman
Subject: Re: Macros, declare, and locally
Date: 
Message-ID: <uvf7zqg3s.fsf@nhplace.com>
Kalle Olavi Niemitalo <···@iki.fi> writes:

> Damien Kick <······@email.mot.com> writes:
> 
> > But if one can write a macro which expands into a LOCALLY form, does
> > this not mean that one must continue to call MACROEXPAND to find the
> > end of the declarations?
> 
> No, it doesn't.  A LOCALLY form terminates the list of local
> declarations, just like any other form would

True, but not the key issue.

 (defun foo (x)
   (declare (special x))
   x) ; <-- this x is special

 (defun foo (x)
   (locally (declare (special x)))
   x) <-- this x is NOT special

The scope of a locally is only its body.  That is,

 (LOCALLY (DECLARE (SPECIAL X))
    ... this part is where X is special ...)

so

 (defun foo (x)
   (locally (declare (special x)) 
     ;; There's nothing in this LOCALLY body
   ) ;; <-- this closes the body of LOCALLY
   ;; This isn't in the LOCALLY body, which is now closed.
   x)

So you're right that LOCALLY stops the list of declarations at the
top of FOO, but the reason is that it's an exectuable form.  Indeed,
in many implementations:

 (LOCALLY decls . forms)

expands into

 (LET () decls . forms)
From: Kalle Olavi Niemitalo
Subject: Re: Macros, declare, and locally
Date: 
Message-ID: <87vf7ylogx.fsf@Astalo.kon.iki.fi>
Kent M Pitman <······@nhplace.com> writes:

> Indeed, in many implementations:
>
>  (LOCALLY decls . forms)
>
> expands into
>
>  (LET () decls . forms)

That can't be right.  When LOCALLY is a top-level form, its body
forms are also considered to be at top level.  Not so with LET.