Ada方面是一个私有的包

时间:2014-04-21 18:05:22

标签: packages ada preconditions

假设我拥有世界上最愚蠢的环形缓冲区。

size: constant := 16;
subtype T is integer;

package RingBuffer is
  procedure Push(value: T);
  function Pop return T;
end;

package body RingBuffer is
  buffer: array(0..size) of T;    
  readptr: integer := 0;
  writeptr: integer := 1;

  procedure Push(value: T) begin
    buffer(writeptr) := value;
    writeptr := (writeptr + 1) mod size;
  end;

  function Pop return T
  begin
    readptr := (readptr + 1) mod size;
    return buffer(readptr);
  end;
end;

因为我的代码很糟糕,我想添加前提条件和后置条件,以免我误用这个。所以我按如下方式更改了Push的实现:

procedure Push(value: T) with
  pre => readptr /= writeptr
is begin
  buffer(writeptr) := value;
  writeptr := (writeptr + 1) mod size;
end;

但是,我收到编译错误,因为我需要将方面定义放在过程的声明中,而不是在实现中。

问题是,这是一个包。我的声明是公开的。前置条件所依赖的值属于包体,声明不可见。为了将方面定义放在声明中,我将不得不重构我的代码以将实现细节公开到包的公共部分(在这种情况下,readptrwriteptr)。我不想这样做。

我可以想到一些解决这个问题的方法,例如让Push()实现PushImpl()调用私有{{1}}过程只定义在实际具有前提条件的主体中......但这太可怕了。什么是正确的方法?

2 个答案:

答案 0 :(得分:5)

我认为当验证检查是私有的时,这总是会出现问题,并且解决方案是声明一个函数来进行检查:

package RingBuffer is
   function Is_Full return Boolean;
   procedure Push(value: T) with Pre => not Is_Full;
   function Pop return T;

Is_Full无论如何都可能有用;在其他情况下可能不是这样。)

如果将实现保留在包体中,则还需要将Is_Full放在那里,但您可以将它们移动到规范并使用表达式函数:

package RingBuffer is
   function Is_Full return Boolean;
   procedure Push(value: T) with Pre => not Is_Full;
   function Pop return T;
private
   buffer: array(0..size) of T;
   readptr: integer := 0;
   writeptr: integer := 1;
   function Is_Full return Boolean is (Readptr = Writeptr);
end RingBuffer;

答案 1 :(得分:2)

合同方面旨在用于(子)类型和子程序的公共视图。

如果要将检查保留在私有视图中,则将其编写为子程序中的第一个语句很简单:

begin
   if Is_Full then
      raise Constraint_Error with "Ring buffer is full.";
   end if;
   ...

一些未经请求的建议:

  • 使合同公开,因此包的用户可以看到它应该如何使用。
  • 从缓冲区弹出项目时插入类似的Is_Empty检查。
  • 使您的索引类型模块化:type Indexes is mod 16;