ToCDocOverviewCGDocRelNotesFAQIndexPermutedIndex
Allegro CL version 10.1
Unrevised from 10.0 to 10.1.
10.0 version

Environments support in Allegro Common Lisp

This document contains the following sections:

1.0 Environments introduction
2.0 General information about environments in Allegro CL
   2.1 Kinds of environments
3.0 Environments functionality
4.0 Environments in Allegro CL


1.0 Environments introduction

An environment in Common Lisp is a Lisp object that contains, in some fashion, a set of bindings and also information about operators, variables, symbols, and so on. This information can be useful in various ways, particularly during evaluation, compilation and macro expansion. The macroexpand operator takes an optional environment argument, whose value is either nil or an environment object.

The actual nature of an environment object is implementation dependent. In standard Common Lisp, there is no way for programmers to access or modify environment objects. In the proposed Common Lisp standard specified by Guy Steele et. al. in the second edition of Common Lisp: the Language, an interface to environment objects was proposed (in Section 8.5, pp 207-214), but the ANSI J13 committee decided not to include this in the ANS.

Allegro CL now has implemented much of the CLtL-2 environments proposal, with some differences that we describe. We recommend that users read that section of CLtL-2, although this document is complete in itself.



2.0 General information about environments in Allegro CL

Environments can be thought of as being specified in CLtL-2, Section 8.5, pp 207-214, with a number of differences. In the following points, we describe the differences between our implementation and the CLtL-2 specification.

Environments

Interface Functions


2.1 Kinds of environments

The kind slot of an augmentable-environment object determines what behaviors the accessors have on it. Usually, accessors will return similar information, but for several reasons including performance and the fact that namespaces are not pure mappings, the kind does play a part, along with optional arguments, in returning different levels of information.

An environment object can be "modified" to become a different kind simply by performing a null augmentation on the original environment and by storing into the kind slot:

(setq e2 (sys:augment-environment e1))
(setf (sys::augmentable-environment-kind e2) :evaluation)

which results in an evaluation environment in e2, which has exactly the same information as e1 (which might be any kind of environment, but which in practice is probably a :compiler environment).

The environment kinds are:

Special Handling of function-information returns

If one considers a namespace to be a one-to-one mapping of a name to a binding, then the function namespace is not a pure namespace in Common Lisp; consider that a name can simultaneously name both a special-operator and either a macro or a compiler-macro, or it can name a macro or function and a compiler-macro simultaneously. Of course, any lexical definition created for that name (such as an flet, labels, or macrolet) will shadow all of these potential combinations, but if no such shadowing occurs, there is a necessity for function-information to be able to make the distinctions between the various combinations of definition that are possible.

If the fourth argument (the special-operators argument) to function-information is true, and if the name is a non-shadowed special-operator, then :special-operator is returned, even if it has a macro or a compiler-macro definition as well. If the argument is nil, then for a special-operator which also has a compiler-macro, :compiler-macro is returned only for :compiler and environments (otherwise :special-operator is returned), and for a special-operator which also has a macro definition, :macro is returned only for :interpreter and :evaluation environments (otherwise :special-operator is returned).

We do not define what occurs if a special-operator has both a macro and a compiler-macro definition, because Allegro CL has none of these situations. There should be a normalized behavior for such a situation.

If a name defines a compiler-macro as well as either a macro or a function, then which is returned depends on the environment kind: a :compiler environment will cause the :compiler-macro to be returned, and any other environment will result in the :function or :macro being returned.



3.0 Environments functionality

The following functions and variables are defined in our environments implementation:



4.0 Environments in Allegro CL

The optimize qualities (safety, space, speed, debug) are no longer repesented by variables in the excl package (e.g. excl::.speed.) Also, the compilation-speed quality is added to the set, because it is specified by ANS. These 5 qualities are now accessed by (sys:declaration-information 'optimize <env>) which returns an alist which will always include at least one of each of these qualities. This return value is constant -- never modify its contents. Also, there may be more than one entry for a quality; the first one encountered is the correct value for the specified environment.

The optimize declaration is defined by

(sys:define-declaration optimize (declaration env)
  .optimize.
  :declare
  <body>)

This means, for debugging purposes, that sys::.optimize. is used as the holder of the global optimization quality list.

The declaration-information function will return this list, possibly shadowed by local lexical optimize declarations, depending on the environment object passed to it.

Example 1

cl-user(1): (sys:declaration-information 'optimize nil)
((safety 1) (space 1) (speed 1) (compilation-speed 1) (debug 2))
cl-user(2): 

Example 2

cl-user(1): (setq e1 (sys::make-augmentable-environment-boa :compilation))
#<Augmentable compilation environment @ #x71b0941a>
cl-user(2): (setq e2 (sys:augment-environment e1 :declare '((optimize speed (safety 0)))))
#<Augmentable compilation environment 1 @ #x71b0992a>
cl-user(3): (sys:declaration-information 'optimize e1)
((safety 1) (space 1) (speed 1) (compilation-speed 1) (debug 2))
cl-user(4): (sys:declaration-information 'optimize e2)
((speed 3) (safety 0) (safety 1) (space 1) (speed 1)
 (compilation-speed 1) (debug 2))
cl-user(5): 

Inline, notinline declarations

This is an example of a mutually exclusive declaration; one can declare the same symbol binding both inline and notinline, but not at the same time. Therefore, these two declarations are combined into a single declaration class called inline.

The entire definition for these two declarations is

(sys:define-declaration (inline inline notinline) (declaration env)
  .inline.
  :function)

The first inline in the namespace is the class, and each of the two further names in the namespace are the declaration instances. The kind of declaration is :function, and the body is null and thus takes on the default action.

Thus, function information for a function name that has been declared either inline or notinline will include as its third returned value an entry of the form (inline <value>), where value is one of inline, notinline, or nil (but this might usually be left off).

Example 1

cl-user(1): (setq e1 (sys::make-augmentable-environment-boa :compilation))
#<Augmentable compilation environment @ #x71b0941a>
cl-user(2): (setq e2 (sys:augment-environment e1 :function 'foo
                       :locative (list #'(lambda (x) (1+ x)))
                       :declare '((notinline foo))))
#<Augmentable compilation environment 1 @ #x71b09c62>
cl-user(3): (setq e3 (sys:augment-environment e2 :declare '((inline foo))))
#<Augmentable compilation environment 1 1 @ #x71b09eba>
cl-user(4): (sys:function-information 'foo e1)
nil
cl-user(5): (sys:function-information 'foo e2)
:function
(#<Interpreted Function (unnamed) @ #x71b09c32>)
((inline notinline))
t
cl-user(6): (sys:function-information 'foo e3)
:function
(#<Interpreted Function (unnamed) @ #x71b09c32>)
((inline inline) (inline notinline))
t
cl-user(7): 

Example 2

cl-user(1): (sys:function-information 'bar nil)
nil
cl-user(2): (sys:augment-environment nil :declare '((notinline bar)) :reuse t)
nil
cl-user(3): (sys:function-information 'bar nil)
nil
cl-user(4): (sys:function-information 'bar nil t)
:free
(nil)
((inline notinline))
cl-user(5): (setq e1 (sys::make-augmentable-environment-boa :compilation))
#<Augmentable compilation environment @ #x71b09bd2>
cl-user(6): (setq e2 (sys:augment-environment e1 :declare '((inline bar))))
#<Augmentable compilation environment 1 @ #x71b09fba>
cl-user(7): (sys:function-information 'bar e1)
nil
cl-user(8): (sys:function-information 'bar e1 t)
:free
(nil)
((inline notinline))
cl-user(9): (sys:function-information 'bar e2 t)
:free
(nil)
((inline notinline) (inline inline) (inline notinline))
nil
cl-user(10): 

Ignore, ignorable, excl::ignore-if-unused declarations

Like inline and notinline, these declarations are mutually exclusive. excl::ignore-if-unused is the archaic form for ignorable. The declaration class is called ignore, and will have a value of ignore, ignorable, or excl::ignore-if-unused (though the archaic form only shows up in a compilerless lisp, where it is never used anyway).

The initial definition of these declarations is:

(sys:define-declaration (ignore ignore ignorable excl::ignore-if-unused)
    (declaration env)
  .ignore.
  :variable)

However, when the compiler is loaded, it overwrites this definiton with one which will

It doesn't make sense to ignore a variable which hasn't been bound, but no error is generated when such a situation occurs.

Example 1

cl-user(1): (setq e1 (sys::make-augmentable-environment-boa :compilation))
#<Augmentable compilation environment @ #x71b0941a>
cl-user(2): (setq e2 (sys:augment-environment e1 :variable 'foo
                        :locative (list (comp::make-varrec-boa 'foo))
                        :declare '((ignore foo))))
#<Augmentable compilation environment 1 @ #x71b09ab2>
cl-user(3): (multiple-value-list (sys:variable-information 'foo e2))
(:lexical
 (#<compiler::varrec foo DynamicExtent: maybe Used: ignore
    unknown-type>)
 ((ignore ignore)) t)
cl-user(4): (comp::varrec-used (caadr *))
ignore
cl-user(5): 

Example of maintenance of definitions in compile-file-environment, as opposed to the global-environment:

Note that the two definitions of foo given here are maintained in different locations; one in the global environment, and one in the lexical environment:

cl-user(1): (fboundp 'foo)
nil
cl-user(2): (sys:augment-environment nil :function 'foo
              :locative (list (compile nil (lambda (x y)
                                             (+ x y)))))
nil
cl-user(3): (sys:function-information 'foo)
:function
nil
nil
cl-user(4): (fdefinition 'foo)
#<Function (:anonymous-lambda 9) @ #x71b0ae42>
cl-user(5): (funcall * 10 20)
30
cl-user(6): (setq e1 (sys:make-compile-file-environment))
#<Augmentable compilation environment @ #x71b0e7b2>
cl-user(7): (setq e2 (sys:augment-environment e1 :function 'foo
                     :locative (list (compile nil (lambda (x y)
                                                    (- x y))))))
#<Augmentable compilation environment 1 @ #x71b11d62>
cl-user(8): (sys:function-information 'foo)
:function
nil
nil
cl-user(9): (fdefinition 'foo)
#<Function (:anonymous-lambda 9) @ #x71b0ae42>
cl-user(10): (sys:function-information 'foo e2)
:function
(#<Function (:anonymous-lambda 10) @ #x71b10bda>)
nil
t
cl-user(11): (multiple-value-bind (ignore locative)
                 (sys:function-information 'foo e2)
               (funcall (car locative) 10 20))
-10
cl-user(12): 

Copyright (c) 1998-2022, Franz Inc. Lafayette, CA., USA. All rights reserved.
This page was not revised from the 10.0 page.
Created 2019.8.20.

ToCDocOverviewCGDocRelNotesFAQIndexPermutedIndex
Allegro CL version 10.1
Unrevised from 10.0 to 10.1.
10.0 version