VpPuZzle. Observe. Part 1: различия между версиями

Материал из wikiru.visual-prolog.com

 
(не показано 17 промежуточных версий этого же участника)
Строка 1: Строка 1:
{{copyright}}
{{copyright}}
{{VpPuZzle_Обзор. Навигатор}}
{{VpPuZzle. Observe. Naivgator}}


DLL-based component technology (The Visual Prolog Puzzle or VPPZL or just PZL) is the set of agreements to build VIP-based applications on the basis of the standard VIP packages placed into DLLs. The VIP package fitted to PZL-technology agreements is named pzl-component. The VIP project (executable or DLL), which contains pzl-components, organized in a special way, is named pzl-container.
DLL-based component technology (The Visual Prolog Puzzle or VPPZL or just PZL) is the set of agreements to build VIP-based applications on the basis of the standard VIP packages placed into DLLs. The VIP package fitted to PZL-technology agreements is named pzl-component. The VIP project (executable or DLL), which contains pzl-components, organized in a special way, is named pzl-container.
The short description of the pzl-technology and it's masic consepts may be found below.
The short description of the pzl-technology and it's basic consepts may be found below.
==Motivation==
==Motivation==
Talking about components we consider component as the peace of software, which can be reused in applications without the change of the source code.
Talking about components we consider component as the peace of software, which can be reused in applications without the change of the source code.
Строка 107: Строка 107:


So in the reality the chain of substitutions and conversions is made, when we use the call:
So in the reality the chain of substitutions and conversions is made, when we use the call:
<vip>
<vip>
...  
...  
MyClassInstance=myClass::new(),  
MyClassInstance=myClass::new(),  
...  
...  
</vip>
</vip>
Let’s assume the DLL is already loaded.
Let’s assume the DLL is already loaded.
#myClass is the static class with the predicate (not constructor) new() at the calling side.  
#myClass is the static class with the predicate (not constructor) <vp>new()</vp> at the calling side.  
#The predicate call new() transported to DLL and real constructor is invoked <vip>MyClassInstance=myClass ::new()</vip>
#The predicate call new() transported to DLL and real constructor is invoked <vp>MyClassInstance=myClass ::new()</vp>
#MyClassInstance converted by <vip>MyClassObject=convert(object,MyClassInstance)</vip>  
#MyClassInstance converted by <vp>MyClassObject=convert(object,MyClassInstance)</vp>  
#MyClassObject delivered to calling side
#MyClassObject delivered to calling side
#MyClassObject converted to MyClass domain by <vip>MyClassInstance=convert(myClass,MyClassObject)</vip>  
#MyClassObject converted to MyClass domain by <vp>MyClassInstance=convert(myClass,MyClassObject)</vp>  


Thus from the pragmatic point of view the call  
Thus from the pragmatic point of view the call  
  <vip> MyClassInstance =myClass::new()</vip>
  <vip> MyClassInstance =myClass::new()</vip>
will take place, and then it is used as usual
will take place, and then it is used as usual
<vip> MyClassInstance:CallNeededPredicate(…)</vip>
<vip> MyClassInstance:CallNeededPredicate(…)</vip>
So the source code of the calling class is not changed.
So the source code of the calling class is not changed.


==Механизмы Pzl-cистемы==  
==The mechanizms of the Pzl-system==  
'''Pzl-Система''' представляется классом '''pzl''' и включает библиотеки, именуемые '''PzlSystem'''.


Pzl-Система:
The '''Pzl-system''' is represented by the class  '''pzl''' and appropriate library.
*автоматически загружает DLL, содержащую класс, к которому производится обращение
*транспортирует вызовы конструктора и возвращает указатель на экземпляр объекта
*обеспечивает возможность взаимодействия классов, помещенных в различные DLL, а не только классов основного приложения и DLL
*автоматически выгружает DLL, когда прекращено использование всех классов данной DLL
*обеспечивает минимальные изменения в текстах программ
*не требует существенного изменения структуры основного приложения


Pzl-Технология:
The '''pzl-system''':
*включает все неоходимые библиотеки и тексты классов, поддерживающих функционирование pzl-системы
*makes automatic loading of DLLs with the needed class
*позволяет легко встроить PZL-Механизмы в действующие проекты
*transports the constructor calls and object pointers back
*автоматически генерирует все необходимые коды
*gives the opportunity to interact classes placed to different DLLs (not only to the application and DLL)
*содержит все необходимые инструменты для практического использования pzl-системы
*unloads automatically the DLLs, when all classes are finalized by garbage collector
*leads to minimal changes in the source codes of classes
*doesn’t change dramatically the structure of the main application


PZL-Технология требует понимания концепций:  
The '''pzl-technology''':
*VIP-пакет (VipPack) как PZL-компонента (PzlComponent)
*includes all nessesery libraries and classes, which support the running of the pzl-system
*Представитель Компоненты (Component Delegate (proxy))
*gives the possibility to update the existing application projects so it can use the PZL technology
*VIP проекты как Pzl-Контейнеры (PzlContainer)
*gives the possibility to generate the code of DLLs automatically
*Главное приложение как PZL-Порт (pzlPort)
*contains all needed tools to use the pzl-system practically
===Pzl-компонента (PzlComponent)===
Pzl-компонента является обычным классом, помещенным в пакет системы Visual Prolog.


Главными особенностями являются:  
The technology means several entities to be described:
*этот класс наследует от класса pzlComponent  
*VIP Pack as the pzl-component
*базовый интерфейс этого класса поддерживает интерфейс pzlComponent  
*Component Delegate (proxy)
*базовый интерфейс этого класса содержит специальную константу-дескриптор componentDescriptor_C  
*VIP Project as the pzlContainers
*имя интерфейса и имя класса должны отличаться
*Main Application as the pzlPort
*конструктор класса является единственным и представляется как new:(object AnyUserDefinedObject). Аргумент конструктора не имеет специльного назначения в рамках Pzl-системы.
===Pzl-component===
'''PzlComponent''' is the usual Visual Prolog class. The only difference is that:
*this class inherits from the class pzlComponent
*the base interface of this class supports interface pzlComponent
*the base interface of this class contains the special constant componentDescriptor_C
*the interface name and the class name must be different
*The constructor of the class declared as new:(object AnyUserDefinedObject)<br\>The argument has no special meaning in the context of the Pzl System.


Константа-дескриптор componentDescriptor_C принадлежит специальному домену pzlComponentInfo_D. Один из аргументов структурированного домена  pzlComponentInfo_D определяет уникальный идентификатор компоненты. Идентификатор может иметь форму string или это может быть  универсальный идентификатор, как это обычно принято в MSCOM технологии.  
The constant componentDescriptor_C belongs to the special domain pzlComponentInfo_D. One of the arguments of the structured domain pzlComponentInfo_D defines the unique component identifier. The iniquity has the sense only in the given application. The identifier may belong to the domain string or it can be a Universal ID, the same as it used in the MSCOM technology.
Component has also the alias, which can be used to create the instance in some cases. The Component Alias is the part of the component descriptor also.
The source code of the class A after the conversion to the pzlComponent is shown below.


Компонента имеет дополнительно имя, которое может быть использовано для создания экземпляра компоненты. Это имя также является частью структуры константы-дескриптора componentDescriptor_C.
Код класса A после его преобразования в Pzl-компоненту приведен в ниже.
<vip>
<vip>
inrerface iA  
inrerface iA  
Строка 199: Строка 194:
end implement a  
end implement a  
</vip>  
</vip>  
Класс B, преобразованный в Pzl-компоненту выглядит абсолютно также, кроме того, что используется другое имя класса.


Как видно, изменения претерпели только декларации класса и интерфейса, но не код имплементации.  
Class B converted to the pzlComponent looks absolutely the same except the name of the class.
You can see that there are changes only in declarations and not in the meaningful code of the implementation.
You can see that the pzl-component doesn't know nor about the place where it is placed, nor about the place where the component, which it comminicates with,  placed.


Следует обратить внимание на то, что pzl-компонента ничего не знает ни о месте, где она сама расположена, ни о месте компоненты, с которой данная компонента взаимодействует.
===The registration of the component===
Pzl-system must know where the pzl-component is placed at the computer. To provide this the registration mechanism is used. The information regarding the component registration may be stored in the user-defined file or it may be stored in the Windows Registry. The same component may be registerede in more then one place.  


===Регистрация компонент===
The pzl-technology tools give the possibility to register or to deregister any component from the any place of registration one by one or using the group mode.
Для того, чтобы знать, где на данном компьютере размещается та или иная pzl-компонента, используется механизм регистрации компонент. Информация о регистрации компонент может быть сохранена либо в файле, который находится в распоряжении и под управлением пользователя, либо эта информация может быть сохранена в реестре Windows. Одна и та же компонента может быть зарегистрирована в нескольких местах.  


Средстав pzl-технологии могут зарегистрировать или снять с регистрации pzl-компоненты в любом из заданных мест раздельно или совместно в составе группы.
===Three ways to create an instance of the component===
The initial and the most important process of the communication of two classes is that one class must get the pointer to the instance of the other created class.  


===Три способа создания экземпляров===
There are three ways to invoke the creation of the instance of the PzlComponent:
Важнейшей частью процесса взаимодействия двух классов является то, что вызывающий класс должен иметь в своем распоряжении указатель на экземпляр вызвываемого класса - обьект класса.  
*By calling the class constructor new()
*By calling the predicate newByName() of the pzl class.
*By calling the predicate newByID() of the pzl class.


Существуют три способа вызова создания экземпляра pzl-компоненты:
The first way was already described and looks like
*путем вызова конструктора new(...)
*путем вызова предиката newByName(...)
*путем вызова предиката newByID(...)
Первый способ уже обсуждался выше и выглядит следующим образом:
<vip>
<vip>
...  
...  
Строка 224: Строка 219:
...  
...  
</vip>
</vip>
Это соответствует обычным правилам VIP.  
It corresponds to the usual VIP rules.


Второй способ использует pzl-систему явно и выглядит так:
The second way uses PzlSystem explicitly and looks like
<vip>
<vip>
...
...
Строка 233: Строка 228:
MyClassInstance:сallNeededPredicate(…),  
MyClassInstance:сallNeededPredicate(…),  
</vip>
</vip>
Здесь iMyClass является интерфейсом класса myClass, а “MyClass” является строковым именем класса (alias) myClass.  
Here iMyClass is the base interface of the class myClass and “MyClass” is the string name (alias) of the class myClass.


Третий способ также явно использует pzl-систему и выглядит так:
The third way also uses PzlSystem explicitly and looks like
<vip>  
<vip>  
...
...
Строка 242: Строка 237:
MyClassInstance:сallNeededPredicate(…),  
MyClassInstance:сallNeededPredicate(…),  
</vip>  
</vip>  
Здесь iMyClass является интерфейсом класса myClass, а str(“MyClass”) является строковым представлением идентификатора класса.  
Here iMyClass is the interface of the class myClass, and str(“MyClass”) is the string form of the class identifier.  


Заметим, что строковое представление идентификатора str(...) является удобным, но не обеспечивает надежной уникальности. Для обеспечения уникальности следует пользоваться численным идентификатором, который должен выглядеть следующим образом (числа, разумеется в каждом случае, свои):  
The string form of the class identifier str(...) is the convenient form, but it doesn't provide the uniqueness. To provide the uniqueness it is recommended to use the numeric identifier, which must look like (numbers depend on the user's wishes):  


uid(0xB5B1AE3D,0xBD01,0x4A29,0x9A,0x14,0x48,0x56,0x34,0x97,0xC7,0xC9).  
uid(0xB5B1AE3D,0xBD01,0x4A29,0x9A,0x14,0x48,0x56,0x34,0x97,0xC7,0xC9).  


Выбор способа использования зависит от обстоятельств, в частности от ответственности кода. Например, в ходе освоения техники программирования с использованием pzl-системы, можно пользоваться строковым идентификатором str(...), а в случае реального коммерческого программирования предпочтительнее использовать цифровой идентификатор uid(...)
The user is free to choose the way to represent the identifier. For instance while learning the programming with the pzl-system use it is convenient to use the string representation of the identifier str(...). In the case of the real commercial programming it is preferable to use the numeric identifier uid(...).


===Класс-делегат (proxy)===  
===Class delegate (proxy)===  
При использования обычного для VIP стиля программирования
 
To use the usual VIP style
<vip>
<vip>
...
...
MyClassInstance =myClass::new(SomeObject),  
MyClassInstance =myClass::new(SomeObject),
MyClassInstance:callNeededPredicate(…)  
MyClassInstance:CallNeededPredicate(…)
...
...
</vip>
</vip>
в случае, если вызывающий и вызываемый классы помещены в разные сущности (EXE и DLL или в разные DLL) , процесс создания экземпляра класса использует класс-делегат (proxy). При этом вызывающий класс вызывает предикат new() класса-делегата, а класс-делегат взаимодействует с PZL-системой, которая возвращает классу-делегату указатель на экземпляр вызываемого класса. Класс-делегат преобразует указатель, имеющий тип object в тип вызываемого класса и, таким образом, создание указателя экземпляра завершается.  
in the case, when called and calling classes placed in different entities (in the executable and DLL or in two different DLLs), the process of creation of the instance of the class uses the delegate (proxy) class.  
 
Thus the calling class calls the predicate <vp>new()</vp> of the proxy class and then proxy class communicates with the Pzl-system and Pzl-system returns the pointer to the instance of the called class to proxy class. Proxy class then converts the object domain to the domain of the called class and the creation of the pointer to the instance is complete.


Текст класса-делегата очень прост и единообразен, что создает возможность его автоматической генерации для каждой pzl-компоненты. Пример текста класса-делегата для класса "AboutDialog" приведен ниже
The text of the proxy class is extremely simple and it is possible to generate the text of the proxy class automatically for each PzlComponent. As an example the text of the class implementation of the class-proxy is shown
<vip>
<vip>
implement aboutDialog
implement aboutDialog
Строка 275: Строка 273:
   new(ObjIn)=convert(iAboutDialog,ObjOut):-
   new(ObjIn)=convert(iAboutDialog,ObjOut):-
   ObjOut=pzl::new(iAboutDialog::componentID_C, ObjIn).
   ObjOut=pzl::new(iAboutDialog::componentID_C, ObjIn).
 
</vip>
end implement aboutDialog
The package file AboutDialog.pack has the text
</vip>  
Пакет AboutDialog.pack имеет текст
<vip>
<vip>
#include@"AboutDialog\AboutDialog.ph"
#include@"AboutDialog\AboutDialog.ph"
#include@"AboutDialog\AboutDialogProxy.pro"
#include@"AboutDialog\AboutDialogProxy.pro"
</vip>
</vip>
Средства pzl-технологии генерируют классы-делегаты автоматически.
Pzl-technology tools can generate the content of files needed to have a class-proxy automatically.


===Комбинированное использование оригинального класса и класса-делегата===  
===The combination of the Original and Proxy classes===  
В случаях, когд вызываемый и вызывающий классы помещены в одну сущность  (в EXE или в одну и ту же DLL), взаимодействие классов в форме
In the case, when called and calling classes placed in one entity (in the executable or in one DLL), then the communication of the classes in the form
<vip>
<vip>
...
...
Строка 293: Строка 289:
...
...
</vip>
</vip>
происходит непосредственно и pzl-система не принимает участие во взаимодействии. Здесь действуют обычные правила VIP. Пакет в этом случае выглядит следующим образом
 
happens explicitly, and PZL system doesn’t participate in the interaction. The usual VIP rules work here. The package for this case looks like
<vip>
<vip>
#include@"AboutDialog\AboutDialog.ph"
#include@"AboutDialog\AboutDialog.ph"
Строка 304: Строка 301:
#include @"AboutDialog\AboutDialog.pro"  
#include @"AboutDialog\AboutDialog.pro"  
</vip>  
</vip>  
С технологической точки зрения удобно иметь все упоминания о файлах, относящихся к pzl-компоненте - пакеты, представляющие оригинальный класс и класс-делегат, в одном пакете.  
It was found convenient to have all files, related to the pzlComponent - the Original and Proxy classes and packages, mentioned in one package.


Возможность комбинированного использования соответствующих деклараций и имплементаций дает использование условной компиляции. В зависимости от значения параметра условной компиляции используется либо оригинальный класс, либо класс-делегат.  
The conditional compilation gives the possibility to use the appropriate declarations and implementations. Depending on the meaning of the conditional compilation parameter, the original or proxy code is used.


Пример текста такого комбинированного пакета приведен ниже.  
The text of the combined package file is shown below.  
<vip>
<vip>
#include @"AboutDialog\AboutDialog.ph"
#include @"AboutDialog\AboutDialog.ph"
#include @"pfc\string\string.ph"


#if iPzlConfig::useAboutDialogOriginal_C=true #then
#if iPzlConfig::useAboutDialogOriginal_C=true #then
% privately used packages
% privately used packages
#include @"pfc\string\string.ph"


% private classes
% private classes
Строка 327: Строка 324:
#endif  
#endif  
</vip>  
</vip>  
Тот же принцип используется для комбинированного использования оригинального класса и класса-делегата в файле заголовка AboutDialog.ph.


Таким образом, если используется оригинальный класс, то константа useAboutDialogOriginal_C должна иметь значение true, а, если используется класс-делегат, то константа  useAboutDialogOriginal_C должна иметь значение false.  
The same principle is used to combine the contents of the header file AboutDialog.ph for the use of the Original and the Proxy related files
 
So if we need to use the original classes, then the constant useAboutDialogOriginal_C must have the value true, and if we need to use the proxy-related files, then the constant useAboutDialogOriginal_C must have the value false.
 
The constant, which defines the way of communication, is defined in the file PzlConfig.i of the package PzlConfig.pack , which is the collection of the pzlComponents of the given entity (executable of DLL).
 
===PzlContainer===
The PzlContainer is the usual Visual Prolog project (one container - one project). It can be the project, which generates the executable application or it can be the project, which generates the DLL.
Unlike the pzl-component, the PzlContainer “knows” which pzl-components it contains. All pzl-components, which are placed to the given pzl-container, must be included to the special package PzlConfig. The implementation of the class pzlConfig deals with the pzl-components also.
The picture below shows the structure of the PzlConfig package as it can be seen on the Project window of the IDE.  


Значение константы, которая определяет способ взаимодействия, определяется в файле PzlConfig.i, в котором собрана информация обо всех pzl-компонентах данной сущности  (EXE или DLL).
[[Image:PzlConfigStructure.png]]


===Pzl-контейнер===
The file of the interface type PzlConfig.i, implementation type PzlConfig.pro and package type PzlConfig.pack are the only entities, related to the pzl-components, included to the given project.
Pzl-контейнер является проектом системы программирования Visual Prolog (один контейнер - один проект). Он может быть проектом, создающим исполняемое приложение (EXE) или проектом, создающим DLL.  


Pzl-компонента "не знает", в каком контейнере она помещается. В отличие от pzl-компоненты pzl-контейнер "знает"  какие pzl-компоненты он содержит. Все pzl-компоненты, которые помещены в данный pzl-контейнер, должны быть включены в предопределенный пакет PzlConfig.pack. Имплементация класса pzlConfig содержит обращения к классам pzl-компонент.  
Files PzlConfig.cl and PzlConfig.ph has no deal with pzlComponents and thus are included to the set of files of the PzlSystem. Because of the information regarding the pzlComponents included to the given pzlContainer is concentrated only in files of the pzlConfig package. This feature gives the possibility to move pzlComponents from one pzlContainer to another pzlContainer with no changes in other parts of the projects.


Ниже приведена структура  PzlConfig, как это представляется в проектном окне IDE как главного приложения Exe, так и контейнера
Pzl-technology tools may update the content of the pzlConfig files automatically, when pzlComponent is added (removed) to (from) the given pzlContainer.


[[Изображение:PzlConfigStructure.png]]
Being the usual project, PzlContainer may contain not only pzlComponents, but it may contain usual Visual Prolog packs also according to the user needs.
Отсутствующие здесь файлы PzlConfig.cl и PzlConfig.ph не содержат информации по конкретным pzl-компонентам и включены в набор файлов, помещенных в директорию PzlSystem. Приведенные же три файла PzlConfig.i, PzlConfig.pro и PzlConfig.pack обеспечивают работу pzl-компонент, включенных в данный проект. Это обстоятельство позволяет перемещать pzl-компоненты из одного контейнера в другой без модификации остальных частей проектов-контейнеров. Средства pzl-технологии обеспечивают автоматически согласованную модификацию файлов пакета pzlConfig при добавлении или удалении соответсвующих pzl-компонент из проекта-контейнера.  


Являясь обычным Vip проектом, pzl-контейнер может содержать не только pzl-компоненты, но и любые другие пакеты, соответствющие потребностям.  
{{VpPuZzle. Observe. Naivgator}}


{{VpPuZzle_Обзор. Навигатор}}
The feature of the PZL-technology, when two pzlComponents placed in one entity communicate explicitly with no use of PzlSystem and communicate via PzlSystem, when they are placed in different entities, gives the possibility to split the application on parts whenever user finds it convenient to him. No change in code is needed. Pzl-technology tools can help in this.
Свойство pzl-технологии, заключающееся в том, что две pzl-компоненты, помещенные в один проект (генерирующий EXE или DLL), взаимодействуют непосредственно без участия pzl-системы, и взаимодействуют через pzl-систему, если они помещаются в разные проекты, позволяет легко делить приложения на части тогда, когда программист находит это удобным. Дополнительных изменений в проектах не требуется. Средства pzl-технологии позволяют производить такое перемещение без вникания в технические детали организации pzl-механизмов.


=Ссылки=
=References=
[[Категория:VpPuZzle]]
[[Category:VpPuZzleEn]]

Текущая версия на 09:57, 31 января 2008

Автор: Виктор Юхтенко

VpPuZzle. Observe


DLL-based component technology (The Visual Prolog Puzzle or VPPZL or just PZL) is the set of agreements to build VIP-based applications on the basis of the standard VIP packages placed into DLLs. The VIP package fitted to PZL-technology agreements is named pzl-component. The VIP project (executable or DLL), which contains pzl-components, organized in a special way, is named pzl-container. The short description of the pzl-technology and it's basic consepts may be found below.

Motivation

Talking about components we consider component as the peace of software, which can be reused in applications without the change of the source code.

The component-based programming is one of the ways to make software development efficient. The usual ways to represent components in the component-based technologies today are:

  • Source code
  • Statically linked libraries
  • Dynamically linked libraries (DLLs)

As to Visual Prolog the VIP package is the example of the component, which is represented via the source code.

The use of statically linked libraries as components in VIP is possible but is not clearly supported.

Compare to source code the use of statically linked libraries gives the only opportunity to hide the internal algorithms of the component. But components based on both source code and static libraries have the negative features:

  • The size of the application is the sum of the size of used components
  • Developers do not have the opportunity to extend the application’s functionality without the rebuilding the whole application.

The best way of the component representation is the DLL. With the use of DLLs almost all goals of the efficient development are reached. Applications become expandable and easily modifiable. Microsoft Component Model technology (MSCOM) is the one of the possible sets of agreements regarding the use of DLLs. The Microsoft agreements, which make DLLs as the COM components are widely used. Visual Prolog currently supports the use of the MS COM components. But to make the use of MSCOM in the VIP-style takes time and still has some problems. Placing the code to DLLs we (being programmers) meet problems which we must have in mind. We must: · take care for the loading and unloading the DLLs · organize the general error handling · think about the common output stream

The goal was to support the use of DLLs with no knowledge about DLLs, using the current VIP IDE.

The usual way to use the DLL

Let’s assume we have two interacting dynamic classes shown in the table

Class A Class B
inrerface a 
predicates 
  pA:(). 
end interface a 
 
class a:a 
end class a 
 
implement a 
clauses 
  ...
  Ob=b::new(), 
  Ob:pB(). 
clauses 
  pA():- 
  ... 
end implement a
 
inrerface b 
predicates 
  pB:(). 
end interface b 
 
class b:b 
end class b 
 
implement b 
clauses 
  ... 
  Oa=a::new(), 
  Oa:pA(). 
clauses 
  pB():- 
  ... 
end implement b


Let’s assume now that on some reasons we wish to place the implementation of the class B into DLL. The standard MS Windows methods are supported in VIP6 well enough by the IDE and the PFC class pfc\application\useDLL.

It is the easy procedure: using the IDE it is needed to create project with the target type DLL. Then the package, which includes the class B, must be included to the appropriate DLL project. The exported predicate must be created and then it must be linked to the predicates of the class B.

The part of the application, which uses class placed to the DLL, must be also modified. Say for the calling the predicate pB the code in the class A will look like

...
ObjDll = useDll::load(DLLFileName), 
pB_Ref=ObjDll:getPredicateHandle(pB_Exp), 
pB_Ref(), 
...

It is not important how much the code above has practical sense. The main point is that the code of the class A, which calls the predicate pB, must be changed dramatically and it becomes hardly dependant on the procedure of the interaction with the class placed to DLL.

Moreover, the creation of the instance of the class A and the call of the predicate pA from the class B side will need to create some special code.

VPPuZzle: Basic Idea

The PZL technology makes it possible to split the application on parts, which are placed to DLL so the codes of the classes are not dramatically changed. The called and calling classes are indifferent in that case to the place where they are placed. It means, that all the communication way work well for calling and called classes:

  • Main applicaion - DLL
  • DLL - Main applicaion
  • DLL - DLL

The two features of VIP system are used to make this possible:

  • The main application and DLLs created by VIP have the same memory space;
  • All instances of classes belong to the domain Object.

The PZL technology is built around the basic idea: When some peace of code needs to call the predicate of some class placed to DLL, then the call new() is transported to DLL, the new instance of the needed class is created and then the pointer to the created object is transported back to the caller. Between main application and DLL this pointer is transported belonging to the Object domain.

But on the back way to the caller it is converted to the domain of the called class.

So in the reality the chain of substitutions and conversions is made, when we use the call:

... 
MyClassInstance=myClass::new(), 
...

Let’s assume the DLL is already loaded.

  1. myClass is the static class with the predicate (not constructor) new() at the calling side.
  2. The predicate call new() transported to DLL and real constructor is invoked MyClassInstance=myClass ::new()
  3. MyClassInstance converted by MyClassObject=convert(object,MyClassInstance)
  4. MyClassObject delivered to calling side
  5. MyClassObject converted to MyClass domain by MyClassInstance=convert(myClass,MyClassObject)

Thus from the pragmatic point of view the call

 MyClassInstance =myClass::new()

will take place, and then it is used as usual

 MyClassInstance:CallNeededPredicate()

So the source code of the calling class is not changed.

The mechanizms of the Pzl-system

The Pzl-system is represented by the class pzl and appropriate library.

The pzl-system:

  • makes automatic loading of DLLs with the needed class
  • transports the constructor calls and object pointers back
  • gives the opportunity to interact classes placed to different DLLs (not only to the application and DLL)
  • unloads automatically the DLLs, when all classes are finalized by garbage collector
  • leads to minimal changes in the source codes of classes
  • doesn’t change dramatically the structure of the main application

The pzl-technology:

  • includes all nessesery libraries and classes, which support the running of the pzl-system
  • gives the possibility to update the existing application projects so it can use the PZL technology
  • gives the possibility to generate the code of DLLs automatically
  • contains all needed tools to use the pzl-system practically

The technology means several entities to be described:

  • VIP Pack as the pzl-component
  • Component Delegate (proxy)
  • VIP Project as the pzlContainers
  • Main Application as the pzlPort

Pzl-component

PzlComponent is the usual Visual Prolog class. The only difference is that:

  • this class inherits from the class pzlComponent
  • the base interface of this class supports interface pzlComponent
  • the base interface of this class contains the special constant componentDescriptor_C
  • the interface name and the class name must be different
  • The constructor of the class declared as new:(object AnyUserDefinedObject)<br\>The argument has no special meaning in the context of the Pzl System.

The constant componentDescriptor_C belongs to the special domain pzlComponentInfo_D. One of the arguments of the structured domain pzlComponentInfo_D defines the unique component identifier. The iniquity has the sense only in the given application. The identifier may belong to the domain string or it can be a Universal ID, the same as it used in the MSCOM technology. Component has also the alias, which can be used to create the instance in some cases. The Component Alias is the part of the component descriptor also. The source code of the class A after the conversion to the pzlComponent is shown below.

inrerface iA 
  supports pzlComponent 
constants 
  componentDescriptor_C:…componentInfo
    (
    componentAlias_C, 
    componentID_C, 
    ... 
    ). 
predicates 
  pA:(). 
end interface iA 
 
class a:iA 
constructors 
  new:(Object). 
end class a 
 
implement a 
  inherits pzlComponent 
clauses 
  new(_Object):- 
    ...
 
clauses 
  ... 
  Ob=b::new(This), 
  Ob:pB(). 
clauses 
  pA():- 
  ... 
end implement a

Class B converted to the pzlComponent looks absolutely the same except the name of the class. You can see that there are changes only in declarations and not in the meaningful code of the implementation. You can see that the pzl-component doesn't know nor about the place where it is placed, nor about the place where the component, which it comminicates with, placed.

The registration of the component

Pzl-system must know where the pzl-component is placed at the computer. To provide this the registration mechanism is used. The information regarding the component registration may be stored in the user-defined file or it may be stored in the Windows Registry. The same component may be registerede in more then one place.

The pzl-technology tools give the possibility to register or to deregister any component from the any place of registration one by one or using the group mode.

Three ways to create an instance of the component

The initial and the most important process of the communication of two classes is that one class must get the pointer to the instance of the other created class.

There are three ways to invoke the creation of the instance of the PzlComponent:

  • By calling the class constructor new()
  • By calling the predicate newByName() of the pzl class.
  • By calling the predicate newByID() of the pzl class.

The first way was already described and looks like

... 
MyClassInstance =myClass::new(SomeObject), 
MyClassInstance:callNeededPredicate() 
...

It corresponds to the usual VIP rules.

The second way uses PzlSystem explicitly and looks like

...
MyClassObj=pzl::newByName(MyClass,...), 
MyClassInstance=tryConvert(iMyClass, MyClassObj), 
MyClassInstance:сallNeededPredicate(),

Here iMyClass is the base interface of the class myClass and “MyClass” is the string name (alias) of the class myClass.

The third way also uses PzlSystem explicitly and looks like

 
...
MyClassObj=pzl::newByID(str(MyClass),...), 
MyClassInstance=tryConvert(iMyClass, MyClassObj), 
MyClassInstance:сallNeededPredicate(),

Here iMyClass is the interface of the class myClass, and str(“MyClass”) is the string form of the class identifier.

The string form of the class identifier str(...) is the convenient form, but it doesn't provide the uniqueness. To provide the uniqueness it is recommended to use the numeric identifier, which must look like (numbers depend on the user's wishes):

uid(0xB5B1AE3D,0xBD01,0x4A29,0x9A,0x14,0x48,0x56,0x34,0x97,0xC7,0xC9).

The user is free to choose the way to represent the identifier. For instance while learning the programming with the pzl-system use it is convenient to use the string representation of the identifier str(...). In the case of the real commercial programming it is preferable to use the numeric identifier uid(...).

Class delegate (proxy)

To use the usual VIP style

...
MyClassInstance =myClass::new(SomeObject),
MyClassInstance:CallNeededPredicate()
...

in the case, when called and calling classes placed in different entities (in the executable and DLL or in two different DLLs), the process of creation of the instance of the class uses the delegate (proxy) class.

Thus the calling class calls the predicate new() of the proxy class and then proxy class communicates with the Pzl-system and Pzl-system returns the pointer to the instance of the called class to proxy class. Proxy class then converts the object domain to the domain of the called class and the creation of the pointer to the instance is complete.

The text of the proxy class is extremely simple and it is possible to generate the text of the proxy class automatically for each PzlComponent. As an example the text of the class implementation of the class-proxy is shown

implement aboutDialog
   open core
 
constants
  className = "AboutDialogProxy".
  version = "1.0".
 
clauses
    classInfo(className, version).
 
clauses
  new(ObjIn)=convert(iAboutDialog,ObjOut):-
   ObjOut=pzl::new(iAboutDialog::componentID_C, ObjIn).

The package file AboutDialog.pack has the text

#include@"AboutDialog\AboutDialog.ph"
#include@"AboutDialog\AboutDialogProxy.pro"

Pzl-technology tools can generate the content of files needed to have a class-proxy automatically.

The combination of the Original and Proxy classes

In the case, when called and calling classes placed in one entity (in the executable or in one DLL), then the communication of the classes in the form

...
MyClassInstance =myClass::new(SomeObject), 
MyClassInstance:CallNeededPredicate() 
...

happens explicitly, and PZL system doesn’t participate in the interaction. The usual VIP rules work here. The package for this case looks like

#include@"AboutDialog\AboutDialog.ph"
% privately used packages
#include @"pfc\string\string.ph"
% private interfaces
 #include @"resourceIdentifiers.i"
 
% implementations
#include @"AboutDialog\AboutDialog.pro"

It was found convenient to have all files, related to the pzlComponent - the Original and Proxy classes and packages, mentioned in one package.

The conditional compilation gives the possibility to use the appropriate declarations and implementations. Depending on the meaning of the conditional compilation parameter, the original or proxy code is used.

The text of the combined package file is shown below.

#include @"AboutDialog\AboutDialog.ph"
#include @"pfc\string\string.ph"
 
#if iPzlConfig::useAboutDialogOriginal_C=true #then
% privately used packages
 
% private classes
 
% private interfaces
    #include @"resourceIdentifiers.i"
 
% implementations
    #include @"AboutDialog\AboutDialog.pro"
#else
    #include @"AboutDialog\AboutDialogProxy.pro"
#endif

The same principle is used to combine the contents of the header file AboutDialog.ph for the use of the Original and the Proxy related files

So if we need to use the original classes, then the constant useAboutDialogOriginal_C must have the value true, and if we need to use the proxy-related files, then the constant useAboutDialogOriginal_C must have the value false.

The constant, which defines the way of communication, is defined in the file PzlConfig.i of the package PzlConfig.pack , which is the collection of the pzlComponents of the given entity (executable of DLL).

PzlContainer

The PzlContainer is the usual Visual Prolog project (one container - one project). It can be the project, which generates the executable application or it can be the project, which generates the DLL. Unlike the pzl-component, the PzlContainer “knows” which pzl-components it contains. All pzl-components, which are placed to the given pzl-container, must be included to the special package PzlConfig. The implementation of the class pzlConfig deals with the pzl-components also. The picture below shows the structure of the PzlConfig package as it can be seen on the Project window of the IDE.

PzlConfigStructure.png

The file of the interface type PzlConfig.i, implementation type PzlConfig.pro and package type PzlConfig.pack are the only entities, related to the pzl-components, included to the given project.

Files PzlConfig.cl and PzlConfig.ph has no deal with pzlComponents and thus are included to the set of files of the PzlSystem. Because of the information regarding the pzlComponents included to the given pzlContainer is concentrated only in files of the pzlConfig package. This feature gives the possibility to move pzlComponents from one pzlContainer to another pzlContainer with no changes in other parts of the projects.

Pzl-technology tools may update the content of the pzlConfig files automatically, when pzlComponent is added (removed) to (from) the given pzlContainer.

Being the usual project, PzlContainer may contain not only pzlComponents, but it may contain usual Visual Prolog packs also according to the user needs.

VpPuZzle. Observe


The feature of the PZL-technology, when two pzlComponents placed in one entity communicate explicitly with no use of PzlSystem and communicate via PzlSystem, when they are placed in different entities, gives the possibility to split the application on parts whenever user finds it convenient to him. No change in code is needed. Pzl-technology tools can help in this.

References