繁体   English   中英

包专有的Ada方面

[英]Ada aspects which are private to a package

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

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()过程,但这太可怕了。 什么是正确的方法?

我认为,当验证检查是私有的时,这总是一个问题,而解决方案是声明一个函数来执行检查:

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;

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

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

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

一些不请自来的建议:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM