From: Liu Fung Sin
Subject: I proclaim that I really dont know where to put my declaim
Date: 
Message-ID: <1185605562.542708.294460@e9g2000prf.googlegroups.com>
I've read some of the previous discussions regarding proclaim and
declaim. I understand that (declaim ...) is a macro that will get
expanded to (proclaim ...) with the right magic applied and that is
what one usually want to use.

However, I still don't know how to apply this in practice.

Let's consider I have the following files in a project:

;; ==============================================
;; test.asd
;; ==============================================
(in-package #:cl-user)

(declaim (optimize (debug 3) (safety 3) (speed 0) (space 0)))
;;
;; If I put declaim here, will it affect the libraries that this
;; module depends on ?
;;
;; Specifically, will it affect lib1 and lib2 ?
;;
;; If not, how do I apply this optimization setting to lib1 and
;; lib2 without changing its source code?
;;
;; Secondly, will it apply to the test package if I declaim here
;; (i.e. file1, file2, file3)?
;;
(defpackage #:test-system
  (:use #:cl #:asdf))

(in-package #:test-system)

(defsystem test
  :depends-on
  (#:lib1 #:lib2)
  :serial t
  :components
  ((:file "packages")
   (:file "file1")
   (:file "file2")
   (:file "file3")))


;; ==============================================
;; package.lisp
;; ==============================================

(in-package #:cl-user)

(defpackage #:test
  (:use #:cl))

(declaim (optimize (debug 3) (safety 3) (speed 0) (space 0)))
;;
;; If I declaim in package.lisp instead, will this apply to the all
;; functions that I'm going to define in package :test (again, file1,
;; file2, file3)
;;


;; ==============================================
;; file1.lisp
;; ==============================================

(in-package #:test)

(defun fun1 ()
  (...))

;; ==============================================
;; file2.lisp
;; ==============================================

(in-package #:test)

(declaim (optimize (debug 3) (safety 3) (speed 0) (space 0)))
;;
;; If I declaim in file2.lisp, apparently this will apply to all forms
;; defined in file2.lisp. But will it apply to file3 and any files
;; that are loaded after file2.lisp?
;;
(defun fun2 ()
  (...))

;; ==============================================
;; file1.lisp
;; ==============================================

(in-package #:test)

(defun fun3 ()
  (...))


I hope some experienced lispers can shed some lights here, a lot of
newbies will really appreciate it (including me).

I think the general question is whether there's a easy way to
(declaim ...) for the whole package, instead of adding it to the top
of each file in the package.

TIA
fungsin

From: Kent M Pitman
Subject: Re: I proclaim that I really dont know where to put my declaim
Date: 
Message-ID: <uir85rn5d.fsf@nhplace.com>
Liu Fung Sin <···········@gmail.com> writes:

> I've read some of the previous discussions regarding proclaim and
> declaim ... I still don't know how to apply this in practice.

[In a setup file:]

> (declaim (optimize (debug 3) (safety 3) (speed 0) (space 0)))
> ;;
> ;; If I put declaim here, will it affect the libraries that this
> ;; module depends on ?
> ;;
> ;; Specifically, will it affect lib1 and lib2 ?
> ;;
> ;; If not, how do I apply this optimization setting to lib1 and
> ;; lib2 without changing its source code?

You call PROCLAIM prior to initiating a compile action. [More on that
in the end.]

[In file2.lisp:] 
> (declaim (optimize (debug 3) (safety 3) (speed 0) (space 0)))
> ;;
> ;; If I declaim in package.lisp instead, will this apply to the all
> ;; functions that I'm going to define in package :test (again, file1,
> ;; file2, file3)

From http://www.lispworks.com/documentation/HyperSpec/Body/m_declai.htm#declaim

  If a use of this macro appears as a top level form in a file being
  processed by the file compiler, the proclamations are also made at
  compile-time. As with other defining macros, it is unspecified
  whether or not the compile-time side-effects of a declaim persist
  after the file has been compiled.

Is there something unclear about "it is unspecified" here?

That is, the spec is not failing to say what is true, it's just that
what is true is that you don't know.

For example, saying that "it is unknown whether there is a God" is not
an ambiguous statement; it is an objectively true statement.  Whether 
there is a God is open to interpretation/faith/debate, so might be said
to be ambiguous.  But the statement that no one knows how to resolve such
a debate involves no ambiguity.

So, too, here.  The spec does not define this.  That isn't ambiguous.
It merely says, as a point of fact, that you have no way of knowing
the answer portably.

In still other words, if you want it to apply to file3, and you want
to use declaim, then you should put it in file3.  If you want
something else in file3, then you must make that need explicit in
file3.

Additional notes:

  A package is not a file, so if the package is still getting
  definitions in another file, this text is quite explicit that you
  can't rely on it.

  Moreover, a declaim is not "scoped" to a package. A package is a
  thing about how the reader and related operations (e.g., INTERN)
  work.  Declarations made in a certain package will certainly affect
  other packages that occur in the same file (if you switch prevailing
  packages during a file).  A package contains nothing more than
  symbols--it does not contain environment info.

- - - - -

The issue is that compilation is done before evaluation.  So if you put
(proclaim ...) in a file, it won't get executed until load time and so
will not affect compilation ... of that file.  But if you call proclaim
prior to calling compile-file in the Lisp doing the compilation, it will
make a global change to that Lisp that should affect future compilations.
So if you have a file load-up.lisp that proclaims data and then makes
explicit calls to compile-file, you should be fine.

The purpose of declaim is to allow you, within a file, to compile the
file in a way that affects the compilation "in time".  It does this by
making a compile-time side-effect.  The scope of that effect is only
guaranteed to be to the file because there's no guarantee that a compiler
will keep the same compile-time environment across file compilations.  
I'd bet most implementations will keep the same environment across a 
compilation unit, so you may mostly win.  But from a strict definitional
point of view, you can't rely on that.  So either ask your vendors if you
can rely on it in the implementations you care about, or else make your
declarations explicit at the top of each file.

But note also that as soon as any file loads that had a declaim in it,
that file will make a global change in effect to the global state of
the Lisp which is seen at least when the next time a compilation unit
starts (unless superseded by another file that was loaded with
different settings).  What's unclear is whether implementations use
some other environment than the global/runtime environment for
compilation.  I think the intent was that they at least could (and
someone who's looked this up recently can say whether they are
required to--I remember there was much debate and don't remember how
it came out).

In practice, I think a lot of implementations found it hard to
separate the compilation environment from the global environment, so I
bet in most environments a proclaim being loaded during a compilation
environment affects that compilation environment immediately and
doesn't wait for you to finish the environment before making it
visible.  I think it's normally too hard to make it do otherwise
unless you're doing the hack that KCL used to do of spawning an
inferior process to do a file compile in an utterly separate address
space.  But it's the presence of options like that which make the
whole thing a mess.

The rule that results reminds me a little of the rule I learned for driving
in rotaries in the Boston area [that's a "roundabout" for you guys in the UK].
Around here, each rotary seems to follow its own rules of who can enter when,
notwithstanding the fact that the law requires a rule that many don't use.
The rule I learned was "Don't hit anything." ... In other words, practice
"defensive driving" by not assuming others will do their part.  You can insist
on driving by the rules, but you'll probably get hit.  And so the question 
soon becomes "are you up to the hassle of that, or is it easier to just
go with the flow (so to speak)?"

Defensive programming in the case of declaim is to just sprinkle them in more
places than you may wish you had to, or else put a PROCLAIM before the whole
biz starts. I'd say to do the latter, since this allows you to make the change
without affecting your individual code.  Either that or make a macro that is
sensitive to a compilation or runtime setting. e.g.,

 (defmacro quickly (&body forms) ;unconditional
   `(locally (declare (optimize (speed 3)))
      ,@forms))

 (defmacro usually-quickly (&body forms)
   (if *usually* ;compile-time test
       `(quickly ,@forms)
       `(progn ,@forms)))

 (defmacro quickly-if (test &body forms)
   `(if ,test ;runtime test
        (quickly ,@forms)
        (progn ,@forms)))

In general, I doubt you'll find much in the way of declaration processing
other than (SAFETY 3) that reliably works the same in all implementations,
so making macros with tighter granularity allows you to make them conditional
on implementation variation in a way that is semi-portable [in the sense that
the macro's uses are able to be portable even if the definition is not]...

 (defmacro quickly (&body forms)
   `(locally (declare #+some-lisp '(optimize (speed 3) (debug 1))
                      #-some-lisp '(optimize (speed 3)))
      ,@forms))

- - - - -

Disclaimer: I didn't do a big survey of what implementations are
 doing.  Nor have I looked seriously at this issue in a while.  So
 don't take what I'm saying as gospel--just as one person's experience
 over a long period of time. I rarely set these things globally--I
 usually only set them locally within a particular function I have 
 a special need to optimize, in the vague kind of style I used in the
 QUICKLY macro above... though the specific conditions I made up there
 are just samples.
From: Liu Fung Sin
Subject: Re: I proclaim that I really dont know where to put my declaim
Date: 
Message-ID: <1185612544.463040.79660@d30g2000prg.googlegroups.com>
On Jul 28, 12:41 am, Kent M Pitman <······@nhplace.com> wrote:
> In practice, I think a lot of implementations found it hard to
> separate the compilation environment from the global environment, so I
> bet in most environments a proclaim being loaded during a compilation
> environment affects that compilation environment immediately and
> doesn't wait for you to finish the environment before making it
>
> So either ask your vendors if you
> can rely on it in the implementations you care about, or else make your
> declarations explicit at the top of each file.

Wow, thanks for the detailed explanation. I guess I didn't exaggerate
enough in my post, but I am really interested in the common
practice of applying the (optimize ...) setting using the major
implementations (sbcl, lispworks). As you say, the hyperspec leave
this open to the implementers).

I know there're a few sbcl hackers lurking here (also there're others
who have extensive experience with lispworks/cmucl/clisp etc) . I
think understanding the implementation specific behavior will be
helpful because one usually only target a single lisp for production
deployment.

>  I rarely set these things globally--I
>  usually only set them locally within a particular function I have
>  a special need to optimize

I also find that the default setting are usually fast enough without
having to specify (optimize ...)

However, for most lisps you cannot use slime to step sexp forms or
examine the frame variable in the debugger without the highest debug
setting.

Again, thanks for taking the time to reply!
From: Juho Snellman
Subject: Re: I proclaim that I really dont know where to put my declaim
Date: 
Message-ID: <slrnfam36u.tb8.jsnell@sbz-30.cs.Helsinki.FI>
Liu Fung Sin <···········@gmail.com> wrote:
> Wow, thanks for the detailed explanation. I guess I didn't exaggerate
> enough in my post, but I am really interested in the common
> practice of applying the (optimize ...) setting using the major
> implementations (sbcl, lispworks). As you say, the hyperspec leave
> this open to the implementers).
>
> I know there're a few sbcl hackers lurking here (also there're others
> who have extensive experience with lispworks/cmucl/clisp etc) . I
> think understanding the implementation specific behavior will be
> helpful because one usually only target a single lisp for production
> deployment.

SBCL actually uses a scheme that Kent didn't mention. Essentially 
this is what happens:

  * non-OPTIMIZE proclamations become visible in the global
    environment. There is no separate compilation environment. Let's
    say that file "x.lisp" contains only the form (DECLAIM (SPECIAL
    *A*)). In a fresh lisp (COMPILE-FILE "x.lisp") (DESCRIBE '*A*)
    will show you that *A* is now a special variable. Likewise in a
    fresh lisp (LOAD "x.fasl") (DESCRIBE '*A*) will show *A* as
    special.    
  * OPTIMIZE proclamations are handled approximately file-locally.
    LOAD and COMPILE-FILE will store the current optimization policy
    before doing anything else, and restore the original value back
    when the file has been handled. So if you have a file that
    contains the following:
    
      (declaim (optimize speed))
    
      (eval-when (:compile-toplevel)
        (sb-ext:describe-compiler-policy))
      
      (eval-when (:load-toplevel)
        (sb-ext:describe-compiler-policy))
    
    It will print (amongs other things) SPEED = 3 when you compile the
    file, and again when you load the fasl. Since the original policy
    will be restored back, calling SB-EXT:DESCRIBE-COMPILER-POLICY
    from the repl after either the LOAD or the COMPILE-FILE will show
    SPEED = 1. On the other hand, if you type (DECLAIM (OPTIMIZE
    DEBUG)) on the repl, and repeat the steps above, you'll see that
    the DEBUG optimization quality will be 3 during compilation,
    during loading, and at the repl afterwards.

You might wonder why things are done this way. Well, the root cause is
that this is how CMUCL did it. But this behaviour has the benefit that
loading a library will not mess up you optimization policy. This is
important since compiling things with the wrong policy can be bad;
(SAFETY 0) has the obvious drawbacks, (DEBUG 3) can slow down your
code, etc. If a random library can change default compiler policy,
you'll need to add a protective declamation at the start of every file
in your system.

Of course, this behaviour also has some drawbacks: mainly, it doesn't
conform to the spec.

-- 
Juho Snellman
From: Don Geddis
Subject: Re: I proclaim that I really dont know where to put my declaim
Date: 
Message-ID: <874pjo8pue.fsf@geddis.org>
Kent M Pitman <······@nhplace.com> wrote on 28 Jul 2007 03:4:
> The rule that results reminds me a little of the rule I learned for driving
> in rotaries in the Boston area [that's a "roundabout" for you guys in the
> UK].  Around here, each rotary seems to follow its own rules of who can
> enter when, notwithstanding the fact that the law requires a rule that many
> don't use.  The rule I learned was "Don't hit anything." ... In other
> words, practice "defensive driving" by not assuming others will do their
> part.  You can insist on driving by the rules, but you'll probably get hit.
> And so the question soon becomes "are you up to the hassle of that, or is
> it easier to just go with the flow (so to speak)?"

I had a similar experience.  A long straight steep downhill street near me
has lots of T-intersections coming in from the side.  Of the three directions
with traffic, only two have stop signs.  The incoming T street has a stop,
and the nearest through direction has a stop, but the opposite through
direction does not.

So now you get situations where a car comes on the side T street, and comes
to a full stop, and indicates that it wants to make a left turn.  Then
another car comes on the adjacent through direction, and also comes to a stop.
Meanwhile, a third car is approaching from the opposite through direction,
with no stop.

People (in California, anyway) are mostly used to either "all-way stop signs",
or perhaps "inferior street (with stop signs) crossing superior street (with
no stop signs)".

In the case of this street, their automatic driving habits betray them.

There is a solution in the rules, but as you suggest, the best real-world
approach is to ignore the rules and drive defensively.  It is unlikely that
the other cars will always obey the rules, even if you know them and you do.

        -- Don
_______________________________________________________________________________
Don Geddis                  http://don.geddis.org/               ···@geddis.org
Blame:  The secret to success is knowing who to blame for your failures.
	-- Despair.com
From: Raffael Cavallaro
Subject: Re: I proclaim that I really dont know where to put my declaim
Date: 
Message-ID: <2007072813385911272-raffaelcavallaro@pasdespamsilvousplaitmaccom>
On 2007-07-28 12:17:45 -0400, Don Geddis <···@geddis.org> said:

> People (in California, anyway) are mostly used to either "all-way stop signs",
> or perhaps "inferior street (with stop signs) crossing superior street (with
> no stop signs)".
> 
> In the case of this street, their automatic driving habits betray them.
> 
> There is a solution in the rules, but as you suggest, the best real-world
> approach is to ignore the rules and drive defensively.  It is unlikely that
> the other cars will always obey the rules, even if you know them and you do.

Agreed. I've often found when driving in San Francisco that the 
implicit rule is "gravity wins." That is, even at a 4-way stop, the 
vehicle going downhill effectively has the right of way since all the 
other vehicles yield to it.