При разборе пакета 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 # ~