• Aucun résultat trouvé

Slot Properties

Dans le document ANSI Common Lisp (Page 196-200)

Specialized Data Structures

Section 2.10 mentioned that lexical variables are only valid within the context where they are defined. Along with this restriction comes the promise

11.3 Slot Properties

Like structure fields, the values of uninitialized slots are undefined.

11.3 Slot Properties

The third argument to d e f c l a s s must be a list of slot definitions. The simplest slot definition, as in the example above, is a symbol representing its name. In the general case, a slot definition can be a list of a name followed by one or more properties. Properties are specified like keyword arguments,

By defining an : a c c e s s o r for a slot, we implicitly define a function that refers to the slot, making it unnecessary to call s l o t - v a l u e . If we update our definition of the c i r c l e class as follows,

( d e f c l a s s c i r c l e ()

( ( r a d i u s : a c c e s s o r c i r c l e - r a d i u s ) ( c e n t e r : a c c e s s o r c i r c l e - c e n t e r ) ) )

then we will be able to refer to the slots as c i r c l e r a d i u s and c i r c l e -c e n t e r respe-ctively:

> ( s e t f c (make-instance ' c i r c l e ) )

#<Circle #XC5C726>

> (setf (circle-radius c) 1) 1

> (circle-radius c) 1

By specifying a : w r i t e r or a : r e a d e r instead of an : accessor, we could get just the first half of this behavior," or just the second.

To specify a default value for a slot, we have to give an : i n i t f orm argu-ment. If we want to be able to initialize the slot in the call to make-instance, we define a parameter name as an : i n i t a r g .1 With both added, our class definition might become:

( d e f c l a s s c i r c l e ()

( ( r a d i u s : a c c e s s o r c i r c l e - r a d i u s : i n i t a r g : r a d i u s

: i n i t f o r m 1)

( c e n t e r : a c c e s s o r c i r c l e - c e n t e r : i n i t a r g : c e n t e r

: i n i t f o r m (cons 0 0 ) ) ) )

Now when we make an instance of a c i r c l e we can either pass a value for a slot using the keyword parameter defined as the slot's : i n i t a r g , or let the value default to that of the slot's : i n i t f orm.

> ( s e t f c (make-instance ' c i r c l e .-radius 3))

#<Circle #XC2DE0E>

> (circle-radius c) 3

> ( c i r c l e - c e n t e r c) (0 . 0)

Note that : i n i t a r g s take precedence over : i n i t f orms.

We can specify that some slots are to be shared—that is, their value is the same for every instance. We do this by declaring the slot to have

• . a l l o c a t i o n : c l a s s . (The alternative is for a slot to have -.allocation : i n s t a n c e , but since this is the default there is no need to say so explicitly.) When we change the value of such a slot in one instance, that slot will get the same value in every other instance. So we would want to use shared slots to contain properties that all the instances would have in common.

For example, suppose we wanted to simulate the behavior of a flock of tabloids. In our simulation we want to be able to represent the fact that when one tabloid takes up a subject, they all do. We can do this by making all the instances share a slot. If the t a b l o i d class is defined as follows,

Initarg names are usually keywords, but they don't have to be.

11.4 SUPERCLASSES 181 ( d e f c l a s s t a b l o i d ()

( ( t o p - s t o r y .-accessor t a b l o i d - s t o r y : a l l o c a t i o n : c l a s s ) ) )

then if we make two instances of tabloids, whatever becomes front-page news to one instantly becomes front-page news to the other:

> (setf daily-blab (make-instance 'tabloid) unsolicited-mail (make-instance 'tabloid))

#<Tabloid #XC2AB16>

> (setf (tabloid-story daily-blab) 'adultery-of-senator) ADULTERY-OF-SENATOR

> (tabloid-story unsolicited-mail) ADULTERY-OF-SENATOR

The : documentation property, if given, should be a string to serve as the slot's documentation. By specifying a : type, you are promising that the slot will only contain elements of that type. Type declarations are explained in Section 13.3.

11.4 Superclasses

The second argument to def c l a s s is a list of superclasses. A class inherits the union of the slots of its superclasses. So if we define the class s c r e e n - c i r c l e to be a subclass of both c i r c l e and g r a p h i c ,

( d e f c l a s s g r a p h i c ()

( ( c o l o r : a c c e s s o r g r a p h i c - c o l o r : i n i t a r g : c o l o r ) ( v i s i b l e : a c c e s s o r g r a p h i c - v i s i b l e : i n i t a r g : v i s i b l e

: i n i t f o r m t ) ) )

( d e f c l a s s s c r e e n - c i r c l e ( c i r c l e g r a p h i c )

0)

then instances of s c r e e n - c i r c l e will have four slots, two inherited from each superclass. A class does not have to create any new slots of its own;

s c r e e n - c i r c l e exists just to provide something instantiable that inherits from both c i r c l e and graphic.

The accessors and initargs work for instances of s c r e e n - c i r c l e just as they would for instances of c i r c l e or g r a p h i c :

> ( g r a p h i c - c o l o r (make-instance ' s c r e e n - c i r c l e

: c o l o r ' r e d : r a d i u s 3)) RED

We can cause every s c r e e n - c i r c l e to have some default initial c o l o r by specifying an initform for this slot in the def c l a s s :

( d e f c l a s s s c r e e n - c i r c l e ( c i r c l e g r a p h i c ) ( ( c o l o r : i n i t f o r m ' p u r p l e ) ) )

Now instances of s c r e e n - c i r c l e will be purple by default:

> ( g r a p h i c - c o l o r (make-instance ' s c r e e n - c i r c l e ) ) PURPLE

11.5 Precedence

We've seen how classes can have multiple superclasses. When there are methods defined for several of the classes to which an instance belongs, Lisp needs some way to decide which one to use. The point of precedence is to ensure that this happens in an intuitive way.

For every class there is a precedence list: an ordering of itself and its superclasses from most specific to least specific. In the examples so far, precedence has not been an issue, but it can become one in bigger programs.

Here's a more complex class hierarchy:

( d e f c l a s s s c u l p t u r e () ( h e i g h t width d e p t h ) ) ( d e f c l a s s s t a t u e ( s c u l p t u r e ) ( s u b j e c t ) ) ( d e f c l a s s metalwork () ( m e t a l - t y p e ) ) ( d e f c l a s s c a s t i n g (metalwork) ( ) )

( d e f c l a s s c a s t - s t a t u e ( s t a t u e c a s t i n g ) ( ) )

Figure 11.3 contains a network representing c a s t - s t a t u e and its super-classes.

To build such a network for a class, start at the bottom with a node representing that class. Draw links upward to nodes representing each of its immediate superclasses, laid out from left to right as they appeared in the calls to d e f c l a s s . Repeat the process for each of those nodes, and so on, until you reach classes whose only immediate superclass is standard-object—that is, classes for which the second argument to d e f c l a s s was ( ) . Create links from those classes up to a node representing s t a n d a r d - o b j e c t , and one from that node up to another node representing the class t . The result will be a network that comes to a point at both top and bottom, as in Figure 11.3.

11.6 PRECEDENCE 183

JL 0

^standard-objt

i ^sculpture y

^jUT

C statue J)

>

(^cast-statue

Figure 11.3:

icT^

\ V

(jnetalworkj)

jn"

Q casting ^ / i f

Class hierarchy.

The precedence list for a class can be computed by traversing the corre-sponding network as follows:

1. Start at the bottom of the network.

2. Walk upward, always taking the leftmost unexplored branch.

3. If you are about to enter a node and you notice another path entering the same node from the right, then instead of entering the node, retrace your steps until you get to a node with an unexplored path leading upward. Go back to step 2.

4. When you get to the node representing t , you're done. The order in which you first entered each node determines its place in the precedence list.

One of the consequences of this definition (in fact, of rule 3) is that no class appears in the precedence list before one of its subclasses.

The arrows in Figure 11.3 show how it would be traversed. The prece-dence list determined by this graph is: c a s t - s t a t u e , s t a t u e , s c u l p t u r e , c a s t i n g , metalwork, s t a n d a r d - o b j e c t , t . Sometimes the word specific is used as shorthand to refer to the position of a class in a given precedence list. The preceding list runs from most specific to least specific.

The main point of precedence is to decide what method gets used when a generic function is invoked. This process is described in the next section. The other time precedence matters is when a slot with a given name is inherited from several superclasses. The note on page 408 explains the rules that apply when this happens.0

Dans le document ANSI Common Lisp (Page 196-200)