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», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

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

Интервал:

Закладка:

Сделать

(defmethod initialize-instance :after ((account bank-account)

&key opening-bonus-percentage)

(when opening-bonus-percentage

(incf (slot-value account 'balance)

(* (slot-value account 'balance) (/ opening-bonus-percentage 100)))))

By defining this INITIALIZE-INSTANCE method, you make :opening-bonus-percentagea legal argument to MAKE-INSTANCE when creating a bank-accountobject.

CL-USER> (defparameter *acct* (make-instance

'bank-account

:customer-name "Sally Sue"

:balance 1000

:opening-bonus-percentage 5))

*ACCT*

CL-USER> (slot-value *acct* 'balance)

1050

Accessor Functions

Between MAKE-INSTANCE and SLOT-VALUE , you have all the tools you need for creating and manipulating instances of your classes. Everything else you might want to do can be implemented in terms of those two functions. However, as anyone familiar with the principles of good object-oriented programming practices knows, directly accessing the slots (or fields or member variables) of an object can lead to fragile code. The problem is that directly accessing slots ties your code too tightly to the concrete structure of your class. For example, suppose you decide to change the definition of bank-accountso that, instead of storing the current balance as a number, you store a list of time-stamped withdrawals and deposits. Code that directly accesses the balanceslot will likely break if you change the class definition to remove the slot or to store the new list in the old slot. On the other hand, if you define a function, balance, that accesses the slot, you can redefine it later to preserve its behavior even if the internal representation changes. And code that uses such a function will continue to work without modification.

Another advantage to using accessor functions rather than direct access to slots via SLOT-VALUE is that they let you limit the ways outside code can modify a slot. [188] Of course, providing an accessor function doesn't really limit anything since other code can still use SLOT-VALUE to get at slots directly. Common Lisp doesn't provide strict encapsulation of slots the way some languages such as C++ and Java do; however, if the author of a class provides accessor functions and you ignore them, using SLOT-VALUE instead, you had better know what you're doing. It's also possible to use the package system, which I'll discuss in Chapter 21, to make it even more obvious that certain slots aren't to be accessed directly, by not exporting the names of the slots. It may be fine for users of the bank-accountclass to get the current balance, but you may want all modifications to the balance to go through other functions you'll provide, such as depositand withdraw. If clients know they're supposed to manipulate objects only through the published functional API, you can provide a balancefunction but not make it SETF able if you want the balance to be read-only.

Finally, using accessor functions makes your code tidier since it helps you avoid lots of uses of the rather verbose SLOT-VALUE function.

It's trivial to define a function that reads the value of the balanceslot.

(defun balance (account)

(slot-value account 'balance))

However, if you know you're going to define subclasses of bank-account, it might be a good idea to define balanceas a generic function. That way, you can provide different methods on balancefor those subclasses or extend its definition with auxiliary methods. So you might write this instead:

(defgeneric balance (account))

(defmethod balance ((account bank-account))

(slot-value account 'balance))

As I just discussed, you don't want callers to be able to directly set the balance, but for other slots, such as customer-name, you may also want to provide a function to set them. The cleanest way to define such a function is as a SETF function.

A SETF function is a way to extend SETF , defining a new kind of place that it knows how to set. The name of a SETF function is a two-item list whose first element is the symbol setfand whose second element is a symbol, typically the name of a function used to access the place the SETF function will set. A SETF function can take any number of arguments, but the first argument is always the value to be assigned to the place. [189] One consequence of defining a SETF function—say, (setf foo) —is that if you also define the corresponding accessor function, foo in this case, you can use all the modify macros built upon SETF , such as INCF , DECF , PUSH , and POP , on the new kind of place. You could, for instance, define a SETF function to set the customer-nameslot in a bank-accountlike this:

(defun (setf customer-name) (name account)

(setf (slot-value account 'customer-name) name))

After evaluating that definition, an expression like the following one:

(setf (customer-name my-account) "Sally Sue")

will be compiled as a call to the SETF function you just defined with "Sally Sue" as the first argument and the value of my-accountas the second argument.

Of course, as with reader functions, you'll probably want your SETF function to be generic, so you'd actually define it like this:

(defgeneric (setf customer-name) (value account))

(defmethod (setf customer-name) (value (account bank-account))

(setf (slot-value account 'customer-name) value))

And of course you'll also want to define a reader function for customer-name.

(defgeneric customer-name (account))

(defmethod customer-name ((account bank-account))

(slot-value account 'customer-name))

This allows you to write the following:

(setf (customer-name *account*) "Sally Sue") ==> "Sally Sue"

(customer-name *account*) ==> "Sally Sue"

There's nothing hard about writing these accessor functions, but it wouldn't be in keeping with The Lisp Way to have to write them all by hand. Thus, DEFCLASS supports three slot options that allow you to automatically create reader and writer functions for a specific slot.

The :readeroption specifies a name to be used as the name of a generic function that accepts an object as its single argument. When the DEFCLASS is evaluated, the generic function is created, if it doesn't already exist. Then a method specializing its single argument on the new class and returning the value of the slot is added to the generic function. The name can be anything, but it's typical to name it the same as the slot itself. Thus, instead of explicitly writing the balancegeneric function and method as shown previously, you could change the slot specifier for the balanceslot in the definition of bank-accountto this:

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

Интервал:

Закладка:

Сделать

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

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


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

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

x