Я хочу реализовать что-то похожее на интерфейс с использованием Ada 95 (поэтому типичные интерфейсы OO недоступны). Я сделал это с помощью обобщений и набора «указатель на метод» в записи. Код ниже.
РЕДАКТИРОВАТЬ: Я знаю, что это можно сделать путем передачи подпрограмм в качестве формальных параметров в универсальный пакет, но я хотел бы избежать передачи слишком много параметров в него.
Я думаю, что должен быть гораздо лучший способ реализовать то, что я хочу, поэтому я хотел бы, если я прав, и, если это так, я хотел бы увидеть пример кода.
«Интерфейс» объявлен в универсальном пакете с именем Drivers
. Там есть запись, которая должна содержать переменную универсального типа, которая представляет драйвер, и запись, которая содержит его операции:
drivers.ads
generic
type T is private;
type Error is private;
NOT_IMPLEMENTED_CODE : Error;
package Drivers is
type Driver is private;
-- Need to declare these types because I compile with Ada 95.
type ToStringPtr is access function(self : in T) return String;
type ReadLinePtr is access procedure(self : in T; buffer : out String; err : out Error);
type DriverOps is
record
to_string_op : ToStringPtr := null;
read_line_op : ReadLinePtr := null;
end record;
function create_driver(underlying : T; ops : DriverOps) return Driver;
function to_string(self : in Driver) return String;
procedure read_line(self : in Driver; buffer : out String; err : out Error);
private
type Driver is
record
underlying : T;
ops : DriverOps;
end record;
end Drivers;
drivers.adb
package body Drivers is
function create_driver(underlying : T; ops : DriverOps) return Driver is
begin
return (underlying, ops);
end create_driver;
function to_string(self : in Driver) return String is
begin
if self.ops.to_string_op /= null then
return self.ops.to_string_op(self.underlying);
else
return "";
end if;
end to_string;
procedure read_line(self : in Driver; buffer : out String; err : out Error) is
begin
if self.ops.read_line_op /= null then
self.ops.read_line_op(self.underlying, buffer, err);
else
err := NOT_IMPLEMENTED_CODE;
end if;
end read_line;
end Drivers;
main.adb
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Strings.Fixed;
with Drivers;
procedure main is
type Error is (SUCCESS, NOT_IMPLEMENTED, UNKNOWN);
type MyInt is new Integer;
function to_string(self : in MyInt) return String is
begin
return Integer'Image( Integer(self) ); --'
end to_string;
procedure read_line(self : in MyInt; buffer : out String; err : out Error) is
begin
Ada.Strings.Fixed.Move(
Target => buffer,
Source => "Lets suppose we have read this from a device" & ASCII.LF,
Pad => ASCII.NUL);
err := SUCCESS;
end read_line;
package IntDrivers is new Drivers(MyInt, Error, NOT_IMPLEMENTED);
use IntDrivers;
underlying : MyInt := 25;
int_driver_ops : DriverOps := (
to_string_op => to_string'access, --'
read_line_op => read_line'access --'
);
my_driver : Driver := create_driver(underlying, int_driver_ops);
buffer : String(1..256) := (others => Character'Val(0)); --'
err : Error := SUCCESS;
begin
Put_Line(to_string(my_driver));
read_line(my_driver, buffer, err);
Put(buffer);
Put_Line(Error'Image(err)); --'
end main;