YLISP 3.7 WIN32





                              Y L i s p  3.7

            Средства объектно-ориентированного программирования
                     Common LISP Object System (CLOS)


     Система YLisp 3.7  включает частичную реализацию CLOS - объектно-ориен-
     тированного (ОО) расширения языка Коммон Лисп. Это  расширение основано
     на концепции класса, множественном наследовании, комбинации  методов  и
     метаобъектах. Классы образуют  естественное  расширение  системы  типов
     Коммон Лисп. Вместо традиционного механизма передачи  сообщений, приня-
     того  в  языке  Смолтолк  (Smalltalk),  используются  родовые   функции
     (generic functions). Методы, ассоциированные с родовыми  функциями, вы-
     бираются по классам аргументов и  осуществляют  специфические  действия
     этих функций.

     YLisp полностью реализует механизм наследования, основанный на построе-
     нии списка предшествования классов (class precedence  list).  Последний
     является тотальным упорядочением множества, включающего данный  класс и
     все его надклассы. Список  предшествования  вычисляется  топологической
     сортировкой упомянутого множества, исходя из  локальных  порядков пред-
     шествования (local precedence order), заданных в определениях классов.

     Иерархия метаобъектов, специфицированная в [CLOS],  включает  следующие
     метаклассы.

     Built-in-class  Экземпляры  данного  метакласса  представляют  основные
                     встроенные типы YLisp.

     Structure-class Экземпляры данного метакласса  суть  структурные  типы,
                     вводимые с помощью defstruct без указания опции :type.

     Standard-class  Экземплярами данного метакласса являются  классы, опре-
                     деляемые пользователем с помощью  defclass,  являющиеся
                     подклассами класса standart-object.

     Безусловно, главный недостаток ОО-системы YLisp - это отсутствие  в ней
     концепции родовых функций и методов. Он сказывается, в  основном, из-за
     необходимости мультиметодов. Простейшие же методы, навроде  системы пе-
     редачи сообщений Смолтолка или функций-членов языка Си++,  легко  могут
     быть смоделированы с помощью разделяемых слотов классов.


     Определение класса
     ~~~~~~~~~~~~~~~~~~
     Синтаксис макроса defclass полностью совпадает со  стандартным  [CLOS].
     Однако, имеются следующие семантические отличия и  особенности реализа-
     ции.

          Функции и методы доступа к слотам
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          Ибо функции доступа, чтения и записи значения  слота, специфициро-
          ванные посредством опций :accessor, :reader и :writer соответствен-
          но, не являются родовыми, нужно избегать употребления одних  и тех
          же имен для этих функций в определениях различных классов.

          В принципе, допустимо использование единой функции доступа  к раз-
          деляемым (shared) слотам,  которые хранятся в  различных  классах,
          но только при условии совпадения имен этих слотов.

          Для доступа к локальным (local) слотам экземпляра класса, рекомен-
          дуется применять только функции, непосредственно указанные в опре-
          делении данного класса. Применение функции  доступа  к  экземпляру
          класса C1 для получения значения слота, который описан в надклассе
          C2, допустимо, лишь когда C2 наследуется по единственной или самой
          правой `генеалогической' ветви, например, так

               (defclass C1 (C3 C2) ...)

          В этом случае строение экземпляра класса C1 таково,  что наследуе-
          мые из C2 локальные слоты размещаются раньше (левее),  чем  слоты,
          наследуемые из C3 и его надклассов, которые не являются надкласса-
          ми C2. Значит, смещения таких слотов в экземплярах и C1, и C2 сов-
          падают.

          Задание типа значения слота
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~
          Проверка, соответствует ли значение слота типу, специфицированному
          в опции :type, осуществляется при инициализации  и реинициализации
          зкземпляров        посредством        initialize-instance        и
          reinitialize-instance. Когда же слоту присваивается значение путем

               (setf (slot-value ...) value)
          или
               (setf (writer-or-accessor-name ...) value),

          соответствие типов не контролируется, а  результаты в случае рас-
          согласования неопределены, что подтверждается стандартом [CLOS].

          Динамическое переопределение
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          YLisp  поддерживает  динамическое  переопределение  классов, кото-
          рое выражается в следующих моментах.

          - Определение класса может быть введено в систему ранее, чем форма
            defclass, определяющая один из его надклассов; важно лишь, чтобы
            чтобы все надклассы стали определенными, прежде чем будет порож-
            ден экземпляр данного класса.

          - При переопределении  класса,  т.е.  повторном  оценивании  соот-
            ветствующей формы defclass, происходит переопределение  всех его
            подклассов.

          Однако по двум пунктам данная возможность `не дотягивает' до стан-
          дарта [CLOS].

          1) Явно переопределенный объект-класс не  совпадает  по реализации
             (по eq) со старым, если число разделяемых слотов  в  его  новом
             определении отлично от числа разделяемых слотов в  старом. Само
             собой, это замечание не относится к автоматически переопределя-
             емым подклассам.

          2) Экземпляры, уже порожденные к моменту явного или неявного пере-
             определения класса, становятся устаревшими и  остаются таковыми
             до конца своего существования. Новое определение  класса  будет
             влиять лишь на строение его экземпляров, порожденных в будущем.
             Модификация устаревших экземпляров в случае неизменности объек-
             та-класса (например, посредством  initialize-instance)  или  их
             уничтожение (открепление с целью разрешить  утилизацию занимае-
             мой ими  памяти  сборщиком  мусора)  полностью  возлагается  на
             пользователя.


     Порождение и инициализация экземпляров
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     Создание   экземпляра    класса    осуществляется    вызовом    функции
     make-instance, которая собственно выделяет память (allocate-instance) и
     инициализирует    (initialize-instance)    новый    объект.     Функция
     initialize-instance, наряду с reinitialize-instance,  реализована через
     shared-initialize.

     ОО-система YLisp полностью поддерживает механизм инициализирующих аргу-
     ментов (initialization argument list), список которых аналогичен списку
     ключевых аргументов и может быть указан при обращении  к вышеупомянутым
     функциям.


     Печатный вид экземпляров
     ~~~~~~~~~~~~~~~~~~~~~~~~
     Печать стандартного  объекта, экземпляра  standard-object,  выполняется
     функцией print-object, действие которой можно рассматривать как первич-
     ный метод (primary method) для ее `родовой версии'.  Она  выдает  нечто
     следующего вида:

          #{class-name slot-name1 value1 ... slot-nameN valueN}.

     Приведенная форма содержит значения всех  связанных  слотов  экземпляра
     класса class-name. Выдача содержимого разделяемых слотов контролируется
     значением динамической переменной *print-shared*.

     Длина и глубина печатного представления регулируется  динамическими пе-
     ременными *print-length* и *print-level*, аналогично тому, как это про-
     исходит при печати списков и общих векторов.

     Поскольку функция print-object не является родовой, постольку не следует
     ее переопределять. Настроить программу печати на конкретный  класс мож-
     но, определив в этом классе разделяемый слот с  именем :print-function.
     Значением этого слота должен стать функциональный объект с  двумя аргу-
     ментами:

       1) печатаемый экземпляр,

       2) выходной поток.

     Желательно,  чтобы  подобные  функции  учитывали  значения   переменных
     *print-pretty* и *print-escape*. Значение *print-length*  может игнори-
     роваться, а глубину печати принтер отслеживает сам.