При разборе пакета SQL наконец внятно понял, зачем нужны абстрактные типы и Meta

Родился один пример, чтобы проверить, как такое безобразие уживается в dll. Подумал, что это может оказаться полезным тем, кто хочет разобраться с использованием абстрактных типов.

Вначале мы абстрактно описываем некоторый процесс, например есть объект содержащий вектор, есть функция вычисления длины. Вот и все. А реализовать это можно разными способами и реализации легко менять в BB. Объект не зря называется Driver, поскольку такой подход удобен в случае, например, общения с базой данных.
## Код:
```
MODULE MyDriver;
   IMPORT Meta;
   TYPE
      Driver* = POINTER TO ABSTRACT RECORD
         x*, y*: REAL;
      END;
      Realisation = PROCEDURE (OUT d: Driver);

   PROCEDURE (d: Driver) Len* (): REAL, NEW, ABSTRACT;
   PROCEDURE (d: Driver) Values* (x, y: REAL), NEW, ABSTRACT;
   
   PROCEDURE Load* (realisation: ARRAY OF CHAR; OUT d: Driver; OUT res: INTEGER);
      VAR item: Meta.Item; mod: Meta.Name; ok, a: BOOLEAN; t: INTEGER;
         v: RECORD (Meta.Value)
            Load: Realisation
         END;
   BEGIN
      mod := realisation$;
      Meta.Lookup(mod, item); d := NIL; res := 0;
      IF item.obj = Meta.modObj THEN
         item.Lookup("Load", item);
         IF item.obj = Meta.procObj THEN
            item.GetVal(v, ok);
            IF ok THEN
               v.Load(d);
               res := 0
            ELSE
               res := 3
            END
         ELSE
            res := 2
         END
      ELSE
         res := 1
      END
   END Load;

END MyDriver.
```


Затем описываем первую реализацию драйвера.
## Код:
```
MODULE MyRealisation;
   IMPORT Math, MyDriver;
   TYPE
      Driver = POINTER TO RECORD (MyDriver.Driver) END;

   PROCEDURE (d: Driver) Len* (): REAL;
   BEGIN
      RETURN Math.Sqrt(Math.IntPower(d.x, 2) + Math.IntPower(d.y, 2))
   END Len;

   PROCEDURE (d: Driver) Values* (x, y: REAL);
   BEGIN
      d.x := x;
      d.y := y;
   END Values;
   
   PROCEDURE Load* (OUT d: MyDriver.Driver);
      VAR i: INTEGER; h: Driver;
   BEGIN
      NEW(h); d := h;
   END Load;

END MyRealisation.
```


И вторую реализацию.
## Код:
```
MODULE MyRealisation2;

   IMPORT Math, MyDriver;

   TYPE
      Driver = POINTER TO RECORD (MyDriver.Driver) END;

   PROCEDURE (d: Driver) Len* (): REAL;
   BEGIN
      RETURN Math.Sqrt(d.x*d.x + d.y*d.y)
   END Len;
   
   PROCEDURE (d: Driver) Values* (x, y :REAL);
   BEGIN
      d.x := x;
      d.y := y;
   END Values;

   PROCEDURE Load*(OUT d: MyDriver.Driver);
      VAR i: INTEGER; h: Driver;
   BEGIN
      NEW(h); d := h;
   END Load;

END MyRealisation2.
```


Ну и наконец — использование.
## Код:
```
MODULE MyUsage;

   IMPORT MyDriver, Out:=StdLog;

   PROCEDURE Test*();
      VAR d1, d2: MyDriver.Driver; res1, res2: INTEGER;
   BEGIN
      MyDriver.Load("MyRealisation", d1, res1);
      MyDriver.Load("MyRealisation2", d2, res2);
      IF (res1 = 0) & (res2 = 0) THEN
         d1.Values(12, 10);
         d2.Values(12, 10);
         Out.Real(d1.Len() + d2.Len())
      ELSE
         Out.String("Error")
      END
   END test;

END MyUsage.
```


Я все это делал, чтобы проверить, как такая функция будет работать в dll и что указывать при компиляции библиотеки, получается надо просто указывать обе реализации. Вроде работает.

Если вместо Out сделать RETURN.
^Q DevLinker.LinkDll
test.dll := Kernel+ Math  Meta MyDriver MyRealisation MyRealisation2 MyUsage # ~