Peter Siebel - Practical Common Lisp

Здесь есть возможность читать онлайн «Peter Siebel - Practical Common Lisp» весь текст электронной книги совершенно бесплатно (целиком полную версию без сокращений). В некоторых случаях можно слушать аудио, скачать через торрент в формате fb2 и присутствует краткое содержание. Год выпуска: 2005, ISBN: 2005, Издательство: Apress, Жанр: Программирование, на английском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале библиотеки ЛибКат.

Practical Common Lisp: краткое содержание, описание и аннотация

Предлагаем к чтению аннотацию, описание, краткое содержание или предисловие (зависит от того, что написал сам автор книги «Practical Common Lisp»). Если вы не нашли необходимую информацию о книге — напишите в комментариях, мы постараемся отыскать её.

Practical Common Lisp — читать онлайн бесплатно полную книгу (весь текст) целиком

Ниже представлен текст книги, разбитый по страницам. Система сохранения места последней прочитанной страницы, позволяет с удобством читать онлайн бесплатно книгу «Practical Common Lisp», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

The current define-binary-classmacro has no way to handle this kind of reading—you could use define-binary-classto define a class to represent each kind of frame, but you'd have no way to know what type of frame to read without reading at least the identifier. And if other code reads the identifier in order to determine what type to pass to read-value, then that will break read-valuesince it's expecting to read all the data that makes up the instance of the class it instantiates.

You can solve this problem by adding inheritance to define-binary-classand then writing another macro, define-tagged-binary-class, for defining "abstract" classes that aren't instantiated directly but that can be specialized on by read-valuemethods that know how to read enough data to determine what kind of class to create.

The first step to adding inheritance to define-binary-classis to add a parameter to the macro to accept a list of superclasses.

(defmacro define-binary-class (name (&rest superclasses) slots) ...

Then, in the DEFCLASS template, interpolate that value instead of the empty list.

(defclass ,name ,superclasses

...)

However, there's a bit more to it than that. You also need to change the read-valueand write-valuemethods so the methods generated when defining a superclass can be used by the methods generated as part of a subclass to read and write inherited slots.

The current way read-valueworks is particularly problematic since it instantiates the object before filling it in—obviously, you can't have the method responsible for reading the superclass's fields instantiate one object while the subclass's method instantiates and fills in a different object.

You can fix that problem by splitting read-valueinto two parts—one responsible for instantiating the correct kind of object and another responsible for filling slots in an existing object. On the writing side it's a bit simpler, but you can use the same technique.

So you'll define two new generic functions, read-objectand write-object, that will both take an existing object and a stream. Methods on these generic functions will be responsible for reading or writing the slots specific to the class of the object on which they're specialized.

(defgeneric read-object (object stream)

(:method-combination progn :most-specific-last)

(:documentation "Fill in the slots of object from stream."))

(defgeneric write-object (object stream)

(:method-combination progn :most-specific-last)

(:documentation "Write out the slots of object to the stream."))

Defining these generic functions to use the PROGN method combination with the option :most-specific-lastallows you to define methods that specialize objecton each binary class and have them deal only with the slots actually defined in that class; the PROGN method combination will combine all the applicable methods so the method specialized on the least specific class in the hierarchy runs first, reading or writing the slots defined in that class, then the method specialized on next least specific subclass, and so on. And since all the heavy lifting for a specific class is now going to be done by read-objectand write-object, you don't even need to define specialized read-valueand write-valuemethods; you can define default methods that assume the type argument is the name of a binary class.

(defmethod read-value ((type symbol) stream &key)

(let ((object (make-instance type)))

(read-object object stream)

object))

(defmethod write-value ((type symbol) stream value &key)

(assert (typep value type))

(write-object value stream))

Note how you can use MAKE-INSTANCE as a generic object factory—while you normally call MAKE-INSTANCE with a quoted symbol as the first argument because you normally know exactly what class you want to instantiate, you can use any expression that evaluates to a class name such as, in this case, the typeparameter in the read-valuemethod.

The actual changes to define-binary-classto define methods on read-objectand write-objectrather than read-valueand write-valueare fairly minor.

(defmacro define-binary-class (name superclasses slots)

(with-gensyms (objectvar streamvar)

`(progn

(defclass ,name ,superclasses

,(mapcar #'slot->defclass-slot slots))

(defmethod read-object progn ((,objectvar ,name) ,streamvar)

(with-slots ,(mapcar #'first slots) ,objectvar

,@(mapcar #'(lambda (x) (slot->read-value x streamvar)) slots)))

(defmethod write-object progn ((,objectvar ,name) ,streamvar)

(with-slots ,(mapcar #'first slots) ,objectvar

,@(mapcar #'(lambda (x) (slot->write-value x streamvar)) slots))))))

Keeping Track of Inherited Slots

This definition will work for many purposes. However, it doesn't handle one fairly common situation, namely, when you have a subclass that needs to refer to inherited slots in its own slot specifications. For instance, with the current definition of define-binary-class, you can define a single class like this:

(define-binary-class generic-frame ()

((id (iso-8859-1-string :length 3))

(size u3)

(data (raw-bytes :bytes size))))

The reference to sizein the specification of dataworks the way you'd expect because the expressions that read and write the dataslot are wrapped in a WITH-SLOTS that lists all the object's slots. However, if you try to split that class into two classes like this:

(define-binary-class frame ()

((id (iso-8859-1-string :length 3))

(size u3)))

(define-binary-class generic-frame (frame)

((data (raw-bytes :bytes size))))

you'll get a compile-time warning when you compile the generic-framedefinition and a runtime error when you try to use it because there will be no lexically apparent variable sizein the read-objectand write-objectmethods specialized on generic-frame.

What you need to do is keep track of the slots defined by each binary class and then include inherited slots in the WITH-SLOTS forms in the read-objectand write-objectmethods.

The easiest way to keep track of information like this is to hang it off the symbol that names the class. As I discussed in Chapter 21, every symbol object has an associated property list, which can be accessed via the functions SYMBOL-PLIST and GET . You can associate arbitrary key/value pairs with a symbol by adding them to its property list with SETF of GET . For instance, if the binary class foodefines three slots— x, y, and z—you can keep track of that fact by adding a slotskey to the symbol foo's property list with the value (x y z)with this expression:

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Похожие книги на «Practical Common Lisp»

Представляем Вашему вниманию похожие книги на «Practical Common Lisp» списком для выбора. Мы отобрали схожую по названию и смыслу литературу в надежде предоставить читателям больше вариантов отыскать новые, интересные, ещё непрочитанные произведения.


Отзывы о книге «Practical Common Lisp»

Обсуждение, отзывы о книге «Practical Common Lisp» и просто собственные мнения читателей. Оставьте ваши комментарии, напишите, что Вы думаете о произведении, его смысле или главных героях. Укажите что конкретно понравилось, а что нет, и почему Вы так считаете.

x