;;; -*- Mode:gate; Fonts:(HL12 HL12I HL12B CPTFONTB HL12BI HL12B HL12I ) -*- =Node: 4Defflavor Options* =Text: 3DEFFLAVOR OPTIONS* There are quite a few options to 2defflavor*. They are all described here, although some are for very specialized purposes and not of interest to most users. Each option can be written in two forms; either the keyword by itself, or a list of the keyword and arguments to that keyword. Several of these options declare things about instance variables. These options can be given with arguments which are instance variables, or without any arguments in which case they refer to all of the instance variables listed at the top of the 2defflavor*. This is 1not* necessarily all the instance variables of the component flavors, just the ones mentioned in this flavor's 2defflavor*. When arguments are given, they must be instance variables that were listed at the top of the 2defflavor*; otherwise they are assumed to be misspelled and an error is signaled. It is legal to declare things about instance variables inherited from a component flavor, but to do so you must list these instance variables explicitly in the instance variable list at the top of the 2defflavor*. 2:gettable-instance-variables* Enables automatic generation of methods for getting the values of instance variables. The operation name is the name of the variable, in the keyword package (i.e. it has a colon in front of it). Note that there is nothing special about these methods; you could easily define them yourself. This option generates them automatically to save you the trouble of writing out a lot of very simple method definitions. (The same is true of methods defined by the 2:settable-instance-variables* option.) If you define a method for the same operation name as one of the automatically generated methods, the explicit definition overrides the automatic one. 2:settable-instance-variables* Enables automatic generation of methods for setting the values of instance variables. The operation name is `2:set-*' followed by the name of the variable. All settable instance variables are also automatically made gettable and inittable. (See the note in the description of the 2:gettable-instance-variables* option, above.) In addition, 2:case* methods are generated for the 2:set* operation with suboperations taken from the names of the variables, so that 2:set* can be used to set them. 2:inittable-instance-variables* The instance variables listed as arguments, or all instance variables listed in this 2defflavor* if the keyword is given alone, are made 1inittable*. This means that they can be initialized through use of a keyword (a colon followed by the name of the variable) as an init-option argument to 2make-instance*. 2:special-instance-variables* The instance variables listed as arguments, or all instance variables listed in this 2defflavor* if the keyword is given alone, will be bound dynamically when handling messages. (By default, instance variables are bound lexically with the scope being the method.) You must do this to any instance variables that you wish to be accessible through 2symeval*, 2set*, 2boundp* and 2makunbound*, since they see only dynamic bindings. This should also be done for any instance variables that are declared globally special. If you omit this, the flavor system does it for you automatically when you instantiate the flavor, and gives you a warning to remind you to fix the 2defflavor*. 2:init-keywords* The arguments are declared to be valid keywords to use in 2instantiate-flavor* when creating an instance of this flavor (or any flavor containing it). The system uses this for error-checking: before the system sends the 2:init* message, it makes sure that all the keywords in the init-plist are either inittable instance variables or elements of this list. If any is not recognized, an error is signaled. When you write a 2:init* method that accepts some keywords, they should be listed in the 2:init-keywords* option of the flavor. If 2:allow-other-keys* is used as an init keyword with a non-2nil* value, this error check is suppressed. Then unrecognized keywords are simply ignored. 2:default-init-plist* The arguments are alternating keywords and value forms, like a property list. When the flavor is instantiated, these properties and values are put into the init-plist unless already present. This allows one component flavor to default an option to another component flavor. The value forms are only evaluated when and if they are used. For example, 3(:default-init-plist :frob-array* 3 (make-array 100))* would provide a default ``frob array'' for any instance for which the user did not provide one explicitly. 3(:default-init-plist :allow-other-keys t)* prevents errors for unhandled init keywords in all instantiation of this flavor and other flavors that depend on it. 2:required-init-keywords* The arguments are init keywords which are to be required each time this flavor (or any flavor containing it) is instantiated. An error is signaled if any required init keyword is missing. 2:required-instance-variables* Declares that any flavor incorporating this one that is instantiated into an object must contain the specified instance variables. An error occurs if there is an attempt to instantiate a flavor that incorporates this one if it does not have these in its set of instance variables. Note that this option is not one of those that checks the spelling of its arguments in the way described at the start of this section (if it did, it would be useless). Required instance variables may be freely accessed by methods just like normal instance variables. The difference between listing instance variables here and listing them at the front of the 2defflavor* is that the latter declares that this flavor ``owns'' those variables and accepts responsibility for initializing them, while the former declares that this flavor depends on those variables but that some other flavor must be provided to manage them and whatever features they imply. 2:required-methods* The arguments are names of operations that any flavor incorporating this one must handle. An error occurs if there is an attempt to instantiate such a flavor and it is lacking a method for one of these operations. Typically this option appears in the 2defflavor* for a base flavor (see 4(FLAVOR-4)Flavor Families*). Usually this is used when a base flavor does a 2(send self ...)* to send itself a message that is not handled by the base flavor itself; the idea is that the base flavor will not be instantiated alone, but only with other components (mixins) that do handle the message. This keyword allows the error of having no handler for the message to be detected when the flavor instantiated or when 2compile-flavor-methods* is done, rather than when the missing operation is used. 2:required-flavors* The arguments are names of flavors that any flavor incorporating this one must include as components, directly or indirectly. The difference between declaring flavors as required and listing them directly as components at the top of the 2defflavor* is that declaring flavors to be required does not make any commitments about where those flavors will appear in the ordered list of components; that is left up to whoever does specify them as components. The purpose of declaring a flavor to be required is to allow instance variables declared by that flavor to be accessed. It also provides error checking: an attempt to instantiate a flavor that does not include the required flavors as components signals an error. Compare this with 2:required-methods* and 2:required-instance-variables*. For an example of the use of required flavors, consider the 2ship* example given earlier, and suppose we want to define a 2relativity-mixin* which increases the mass dependent on the speed. We might write, 3(defflavor relativity-mixin () (moving-object))* 3(defmethod (relativity-mixin :mass) ()* 3 (// mass (sqrt (- 1 (^ (// (send self :speed)* 3 *speed-of-light*)* 3 2)))))* but this would lose because any flavor that had 2relativity-mixin* as a component would get 2moving-object* right after it in its component list. As a base flavor, 2moving-object* should be last in the list of components so that other components mixed in can replace its methods and so that daemon methods combine in the right order. 2relativity-mixin* has no business changing the order in which flavors are combined, which should be under the control of its caller. For example, 3(defflavor starship ()* 3 (relativity-mixin long-distance-mixin ship))* puts 2moving-object* last (inheriting it from 2ship*). So instead of the definition above we write, 3(defflavor relativity-mixin () ()* 3 (:required-flavors moving-object))* which allows 2relativity-mixin*'s methods to access 2moving-object* instance variables such as 2mass* (the rest mass), but does not specify any place for 2moving-object* in the list of components. It is very common to specify the 1base flavor* of a mixin with the 2:required-flavors* option in this way. 2:included-flavors* The arguments are names of flavors to be included in this flavor. The difference between declaring flavors here and declaring them at the top of the 2defflavor* is that when component flavors are combined, if an included flavor is not specified as a normal component, it is inserted into the list of components immediately after the last component to include it. Thus included flavors act like defaults. The important thing is that if an included flavor 1is* specified as a component, its position in the list of components is completely controlled by that specification, independently of where the flavor that includes it appears in the list. 2:included-flavors* and 2:required-flavors* are used in similar ways; it would have been reasonable to use 2:included-flavors* in the 2relativity-mixin* example above. The difference is that when a flavor is required but not given as a normal component, an error is signaled, but when a flavor is included but not given as a normal component, it is automatically inserted into the list of components at a reasonable place. 2:no-vanilla-flavor* Normally when a flavor is instantiated, the special flavor 2si:vanilla-flavor* is included automatically at the end of its list of components. The vanilla flavor provides some default methods for the standard operations which all objects are supposed to understand. These include 2:print-self*, 2:describe*, 2:which-operations*, and several other operations. See 4(FLAVOR-4)Vanilla Flavor*. If any component of a flavor specifies the 2:no-vanilla-flavor* option, then 2si:vanilla-flavor* is not included in that flavor. This option should not be used casually. 2:default-handler* The argument is the name of a function that is to be called to handle any operation for which there is no method. Its arguments are the arguments of the 2send* which invoked the operation, including the operation name as the first argument. Whatever values the default handler returns are the values of the operation. Default handlers can be inherited from component flavors. If a flavor has no default handler, any operation for which there is no method signals a 2sys:unclaimed-message* error. 2:ordered-instance-variables* This option is mostly for esoteric internal system uses. The arguments are names of instance variables which must appear first (and in this order) in all instances of this flavor, or any flavor depending on this flavor. This is used for instance variables that are specially known about by microcode, and also in connection with the 2:outside-accessible-instance-variables* option. If the keyword is given alone, the arguments default to the list of instance variables given at the top of this 2defflavor*. Removing any of the 2:ordered-instance-variables*, or changing their positions in the list, requires that you recompile all methods that use any of the affected instance variables. 2:outside-accessible-instance-variables* The arguments are instance variables which are to be accessible from outside of this flavor's methods. A macro (actually a subst) is defined which takes an object of this flavor as an argument and returns the value of the instance variable; 2setf* may be used to set the value of the instance variable. The name of the macro is the name of the flavor concatenated with a hyphen and the name of the instance variable. These macros are similar to the accessor macros created by 2defstruct* (see 4(DEFSTRUCT-0)Defstruct*.) This feature works in two different ways, depending on whether the instance variable has been declared to have a fixed slot in all instances, via the 2:ordered-instance-variables* option. If the variable is not ordered, the position of its value cell in the instance must be computed at run time. This takes noticeable time, although less than actually sending a message would take. An error is signaled if the argument to the accessor macro is not an instance or is an instance that does not have an instance variable with the appropriate name. However, there is no error check that the flavor of the instance is the flavor the accessor macro was defined for, or a flavor built upon that flavor. This error check would be too expensive. If the variable is ordered, the compiler compiles a call to the accessor macro into a subprimitive which simply accesses that variable's assigned slot by number. This subprimitive is only three or four times slower than 2car*. The only error-checking performed is to make sure that the argument is really an instance and is really big enough to contain that slot. There is no check that the accessed slot really belongs to an instance variable of the appropriate name. 2:accessor-prefix* Normally the accessor macro created by the 2:outside-accessible-instance-variables* option to access the flavor 1f*'s instance variable 1v* is named 1f-v*. Specifying 2(:accessor-prefix get$)* causes it to be named 2get$1v** instead. 2:alias-flavor* Marks this flavor as being an alias for another flavor. This flavor should have only one component, which is the flavor it is an alias for, and no instance variables or other options. No methods should be defined for it. The effect of the 2:alias-flavor* option is that an attempt to instantiate this flavor actually produces an instance of the other flavor. Without this option, it would make an instance of this flavor, which might behave identically to an instance of the other flavor. 2:alias-flavor* eliminates the need for separate mapping tables, method tables, etc. for this flavor, which becomes truly just another name for its component flavor. The alias flavor and its base flavor are also equivalent when used as an argument of 2subtypep* or as the second argument of 2typep*; however, if the alias status of a flavor is changed, you must recompile any code which uses it as the second argument to 2typep* in order for such code to function. 2:alias-flavor* is mainly useful for changing a flavor's name gracefully. 2:abstract-flavor* This option marks the flavor as one that is not supposed to be instantiated (that is, is supposed to be used only as a component of other flavors). An attempt to instantiate the flavor signals an error. It is sometimes useful to do 2compile-flavor-methods* on a flavor that is not going to be instantiated, if the combined methods for this flavor will be inherited and shared by many others. 2:abstract-flavor* tells 2compile-flavor-methods* not to complain about missing required flavors, methods or instance variables. Presumably the flavors that depend on this one and actually are instantiated will supply what is lacking. 2:method-combination* Specifies the method combination style to be used for certain operations. Each argument to this option is a list 2(1style order operation1 operation2*...)*. 1operation1*, 1operation2*, etc. are names of operations whose methods are to be combined in the declared fashion. 1style* is a keyword that specifies a style of combination; see 4(FLAVOR-4)Method Combination*. 1order* is a keyword whose interpretation is up to 1style*; typically it is either 2:base-flavor-first* or 2:base-flavor-last*. Any component of a flavor may specify the type of method combination to be used for a particular operation. If no component specifies a style of method combination, then the default style is used, namely 2:daemon*. If more than one component of a flavor specifies the combination style for a given operation, then they must agree on the specification, or else an error is signaled. 2:instance-area-function* The argument is the name of a function to be used when this flavor is instantiated, to determine which area to create the new instance in. Use a function name rather than an explicit lambda expression. 3(:instance-area-function 1function-name*)* When the instance area function is called, it is given the init plist as an argument, and should return an area number or 2nil* to use the default. Init keyword values can be accessed using 2get* on the init plist. Instance area functions can be inherited from component flavors. If a flavor does not have or inherit an instance area function, its instances are created in 2default-cons-area*. 2:instantiation-flavor-function* You can define a flavor 2foo* so that, when you try to instantiate it, it calls a function to decide what flavor it should really instantiate (not necessarily 2foo*). This is done by giving 2foo* an instantiation flavor function: 3(:instantiation-flavor-function 1function-name*)* When 2(make-instance 'foo 1keyword-args*...)* is done, the instantiation flavor function is called with two arguments: the flavor name specified (2foo* in this case) and the init plist (the list of keyword args). It should return the name of the flavor that should actually be instantiated. Note that the instantiation flavor function applies only to the flavor it is specified for. It is not inherited by dependent flavors. 2:run-time-alternatives* 2:mixture* A run-time-alternative flavor defines a collection of similar flavors, all built on the same base flavor but having various mixins as well. Instantiation chooses a flavor of the collection at run time based on the init keywords specified, using an automatically generated instantiation flavor function. A simple example would be 3(defflavor foo () (basic-foo)* 3 (:run-time-alternatives* 3 (:big big-foo-mixin))* 3 (:init-keywords :big))* Then 2(make-instance 'foo :big t)* makes an instance of a flavor whose components are 2big-foo-mixin* as well as 2foo*. But 2(make-instance 'foo)* or 2(make-instance 'foo :big nil)* makes an instance of 2foo* itself. The clause 2(:big big-foo-mixin)* in the 2:run-time-alternatives* says to incorporate 2big-foo-mixin* if 2:big*'s value is 2t*, but not if it is 2nil*. There may be several clauses in the 2:run-time-alternatives*. Each one is processed independently. Thus, two keywords 2:big* and 2:wide* could independently control two mixins, giving four possibilities. 3(defflavor foo () (basic-foo)* 3 (:run-time-alternatives* 3 (:big big-foo-mixin)* 3 (:wide wide-foo-mixin))* 3 (:init-keywords :big))* It is possible to test for values other than 2t* and 2nil*. The clause 3(:size (:big big-foo-mixin)* 3 (:small small-foo-mixin)* 3 (nil nil))* allows the value for the keyword 2:size* to be 2:big*, 2:small* or 2nil* (or omitted). If it is 2nil* or omitted, no mixin is used (that's what the second 2nil* means). If it is 2:big* or 2:small*, an appropriate mixin is used. This kind of clause is distinguished from the simpler kind by having a list as its second element. The values to check for can be anything, but 2eq* is used to compare them. The value of one keyword can control the interpretation of others by nesting clauses within clauses. If an alternative has more than two elements, the additional elements are subclauses which are considered only if that alternative is selected. For example, the clause 3(:etherial (t etherial-mixin)* 3 (nil nil* 3 (:size (:big big-foo-mixin)* 3 (:small small-foo-mixin)* 3 (nil nil))))* says to consider the 2:size* keyword only if 2:etherial* is 2nil*. 2:mixture* is synonymous with 2:run-time-alternatives*. It exists for compatibility with Symbolics systems. 2:documentation* Specifies the documentation string for the flavor definition, which is made accessible through 2(documentation 1flavorname* 'flavor)*. This documentation can be viewed with the 2describe-flavor* function (see 4(FLAVOR-2)Flavor Functions*) or the editor's 2Meta-X Describe Flavor* command (see 4(FLAVOR-5)Useful Editor Commands*). Previously this option expected two arguments, a keyword and a string. The keyword was intended to classify the flavor as a base flavor, mixin or combination. But no way was found for this classification to serve a useful purpose. Keyword are still accepted but no longer recommended for use.