Классы. Статические и динамические сущности
Классы
Каждый класс должен иметь декларацию класса и имплементацию.
Декларация класса содержит набор объявлений констант, доменов, предикатов, видимых извне.
Имплементация класса содержит
- собственно реализацию предикатов (клаузы), объявленных в декларации,
- декларации констант,
- декларации и реализации предикатов, используемых в клаузах,
- декларации фактов.
- Факты и предикаты, объявленные в имплементации класса, извне не видны.
Cтатический класс - класс не способный порождать объекты (экземпляры или точные копии). Все предикаты и разделы фактов статического класса существуют в единственном экземпляре во всем проекте.
Динамический класс - класс, способный порождать объекты (экземпляры или точные копии), Динамические классы могут содержать как статические, так и динамические предикаты, а также статические и динамические факты. Каждый экземпляр динамического класса содержит свою копию динамического предиката и свою копию динамического раздела фактов. Создание объекта (экземпляра или копии класса) осуществляется вызовом предиката-конструктора. Как правило, это предикат-функция new(), но может быть и любой другой, объявленный как конструктор в разделе constructors декларации класса.
Статический класс - это класс, не имеющий интерфейса. Или, что то же самое, - если класс не имеет инерфейса, то он - статический,
Если класс имеет интерфейс - то он - динамический.
Статические классы
Например, класс staticClass является статическим классом.
class staticClass end class staticClass implement staticClass end implement staticClass
но этот класс ничего не способен делать. Чтобы что-то делать, добавим в этот класс декларации предикатов и клаузы.
class staticClass predicates visibleStaticPred:(). end class staticClass implement staticClass clauses visibleStaticPred():- ... invisibleStaticPred(), ... class predicates invisibleStaticPred:(). clauses invisibleStaticPred():- ... end implement staticClass
Обращения к предикатам этого класса записываются как
... staticClass::staticVisiblePred(), ...
(существенно использования именно :: для обращения к статической сущности)
Здесь предикат invisibleStaticPred является предикатом, объявленным внутри имплементации, и только внутри этой имплементации может быть вызван. То есть предикаты, объявленные в декларации класса, являются заведомо всегда статическими предикатами, а раздел объявлений предикатов внутри имплементации статического класса всегда должен имет вид class predicates Если попробовать создать экземпляр класса staticClass с помощью вызова конструктора new()
... staticClass::new(), ...
то это не пропустит компилятор. Таким образом, статические классы - это просто модули проекта. Проект, построенный только на модулях (статических классах) - не имеет никакого отношения к объекто-ориентированной концепции программирования.
Динамические классы
Например, класс dynamicClass является динамическим классом, что определяется конструкцией dynamicClass:justInterface.
class dynamicClass:justInterface end class dynamicClass implement dynamicClass end implement dynamicClass interface justInterface end interface justInterface
Опять-таки, синтаксически все правильно, но практически бесполезно. Теперь добавим какие-нибудь полезности и вынесем вперед декларацию интерфейса.
interface justInterface predicates visibleDynamicPred:(). end interface justInterface class dynamicClass:justInterface predicates visibleStaticPred:(). end class dynamicClass implement dynamicClass clauses visibleStaticPred():- ... invisibleStaticPred(), ... clauses visibleDynamicPred():- ... invisibleStaticPred(), ... class predicates invisibleStaticPred:(). clauses invisibleStaticPred():- ... predicates invisibleDynamicPred:(). clauses invisibleDynamicPred():- ... end implement dynamicClass
Здесь мы имеем четыре предиката, которые имеют различные динамические особенности. visibleDynamicPred - динамический предикат, принадлежащий интерфесу justInterface, видимый извне. visibleStaticPred - статический предикат, видимый извне. invisibleStaticPred - статический предикат, определенный в имплементации класса dynamicClass, невидимый извне. invisibleDynamicPred - динамический предикат, определенный в имплементации класса dynamicClass, невидимый извне. К такому классу можно обратиться как к статическому
... dynamicClass::visibleStaticPred(), ...
но нельзя так:
... dynamicClass::visibleDynamicPred(), ...
Чтобы вызвать предикат visibleDynamicPred(), необходимо с помощью конструктора создать экземпляр класса и обратиться к этому экземпляру:
... ЭкземплярDynamicClass=dynamicClass::new(), ЭкземплярDynamicClass:visibleDynamicPred(), ...
Примечания:
- Конструктор new() является предопределенным конструктором, объявление которого не требуется, если в имплементации нет для него клауза;
- В обращении к экземпляру класса (объекту) используется разделитель ':' (а не '::', как этого требует обращение к статической сущности).
Факты
Факты декларируются и могут быть использованы в клаузах предикатов только в имплементации класса. Нельзя объявить факты в одном классе и пытаться использовать обращение к ним в другом классе. В статических классах факты должны быть объявлены только как статические.
implement example ... class facts myFact_F:(string,string). ... end implement example
В имплементациях динамических классов факты могут быть объявлены либо как статические, либо как динамические:
class example1:example1interface predicates запомнитьГород:(string Город). запомнитьИмяАдрес:(string Имя, string Адрес). получитьГород:()->string Город. получитьИмяАдрес:(string Имя, string Адрес). end class example1 implement example1 ... class facts город_V:string Город. ... facts имяАдрес_F:(string Адрес, string Имя). clauses запомнитьГород(Город):- город_V:=Город. ... clauses запомнитьИмяАдрес(Имя,Адрес):- assert(имяАдрес_F:(Адрес,Имя)). clauses получитьГород(город_V). ... clauses получитьИмяАдрес(Имя,Адрес):- имяАдрес_F(Адрес,Имя), !, ... end implement example1
В приведенном примере класса example1 факт город_V является статическим, а факты имяАдрес_F(...) являются динамическими, что определяется разницей в имени раздела class facts и просто facts. Поскольку статическая сущность любого класса всего одна, а динамическая - по одной на каждый экземпляр - то и в нашем примере запрос получитьГород(), переданный любому экземпляру, вернет один и тот же результат, а запрос получитьИмяАдрес(...) вернет для каждого экземпляра свое значение.
Особенности использования фактов-переменных
В примере выше использовался факт-переменная город_V, особенностью которого является то, что такой факт всегда один и он сам несет значение терма, объявленного в декларации.
class facts город_V:string Город.
Здесь факт город_V имеет строковое значение. Возможны значения любых объявленных доменов, например
domains мойДомен=персона(string Имя,unsigned Возраст). class facts персона_V:мойДомен.
В отличие от обычных фактов, факт-переменная всегда существует и должен иметь начальное значение. Начальное значение факту-переменной можно задать при объявлении
domains мойДомен=персона(string Имя,unsigned Возраст). class facts персона_V:мойДомен:=персона("Старик",80). город_V:string:="НеИзвестен".
В динамических классах начальное значение вместо декларации можно задать в клаузе конструктора
implement dynamicClass domains мойДомен=персона(string Имя,unsigned Возраст). class facts персона_V:мойДомен. clauses new():- персона_V:=персона("Старик",80), ... end implement dynamicClass
Бывает, что конкретное начальное значение установить невозможно по смыслу реализации. Тогда начальное значение может быть установлено как "неустановленное".
class facts город_V:string:=erroneous.
где erroneous - ключевое слово языка. Факт со значением erroneous не может быть использован, можно только проверить является ли значение факта неустановленным с помощью детерминированного предиката isErroneous(...)
implement dynamicClass domains мойДомен=персона(string Имя,unsigned Возраст). class facts город_V:string:=erroneous. персона_V:мойДомен. clauses new():- персона_V:=персона("Старик",80), ... clauses ... isErroneous(город_V), ... end implement dynamicClass
С учетом сказанного наш пример
class facts город_V:string Город.
на этапе компиляции выдаст ошибку, поскольку статический факт не инициализирован при объявлении.
Константы и домены
Константы и домены могут объявляться везде - в декларациях классов, интерфейсов и в имплементациях. По своей сущности они, естественно, имеют статический характер. Объявления, сделанные в имплементации, видимы только внутри этой же имплементации. Объявления констант и доменов, сделанные в декларации класса или интерфейса, являются глабальными. Конкретное использование осуществляется путем добавления префикса декларации соответствующего класса или интерфейса в формате
<имя декларации класса или интерфейса>::<имя домена или константы>.
Взаимоотношени статических и динамических сущностей
Клаузы предикатов, объявленных статическими, не могут обращаться к динамическим сущностям (предикатам и фактам). То есть нельзя так:
implement dynamicClass clauses staticPred():- ... dynamicPred(), ... end implement dynamicClass
Клаузы предикатов, объявленных динамическими, такого ограничения не имеют. Как статические так и динамические факты могут хранить указатели на динамические предикаты и экземпляры классов.