Post 条件和限制 in out 参数
Post conditions and limited in out parameters
post条件如何指定limited in out参数在子程序调用时不被修改?考虑以下代码:
with Ada.Text_IO;
procedure Main is
package C is
type Printer is tagged limited private;
procedure Print
(P : in out Printer;
B : Integer);
private
type Printer is tagged limited record
A : Integer := 0;
end record;
end C;
package body C is
procedure Print
(P : in out Printer;
B : Integer) is
begin
if B >= 0 then
P.A := B;
end if;
Ada.Text_IO.Put_Line (P.A'Image);
end Print;
end C;
P : C.Printer;
begin
P.Print (-1);
end Main;
当指定负数作为 Print 子程序的输入时,Printer 实例的内部状态在子程序调用期间保持不变。指定它的最佳方法是什么?尝试以下操作会产生错误消息 "attribute 'Old' cannot apply to limited objects":
procedure Print
(P : in out Printer;
B : Integer) with
Post => (if B < 0 then P'Old = P);
能否在 Ada 2020 标准的增量聚合中找到解决方案?
编辑:考虑到有限类型根据定义没有任何相等运算符,这可能是一个棘手的问题。
来自 RM 6.1.1
For each X'Old in a postcondition expression that is enabled, a
constant is implicitly declared at the beginning of the subprogram or
entry. The constant is of the type of X and is initialized to the
result of evaluating X (as an expression) at the point of the constant
declaration. The value of X'Old in the postcondition expression is the
value of this constant; the type of X'Old is the type of X. These
implicit constant declarations occur in an arbitrary order.
AARM 非常明确:
'Old makes no sense for limited types, because its implementation
involves copying. It might make semantic sense to allow
build-in-place, but it's not worth the trouble.
我认为增量聚合不会解决问题,因为我看不出它如何防止隐式复制。
然而,虽然您不能将 'old
应用于受限对象,但您可以将其应用于其一个或多个非受限组件。
procedure Print
(P : in out Printer;
B : Integer) with Post => (if B < 0 then P.A'Old = P.A);
当然,在您的示例中,组件 A 是私有的,因此这将不起作用,并且通常不适合 public 过程。
要解决这个问题,您可能需要将组件包装在 getter 函数中并编写:
function Printer_Value (P : in Printer) return Integer;
procedure Print
(P : in out Printer;
B : Integer) with Post => (if B < 0 then P.Printer_Value'Old = P.Printer_Value);
private
function Printer_Value (P : in Printer) return Integer is (P.A);
然后调整 Printer_Value 以手动包含应检查不变性的组件。但这也将无法编译,因为 P.Printer_Value'Old
可能未评估(当 B>=0
时)。 AARM 声明通常的解决方案是 P'Old.Printer_Value
但这是不可能的,因为 P 是有限的。所以要让它工作,我们必须无条件地评估它:
procedure Print
(P : in out Printer;
B : Integer) with Post => P.Printer_Value'Old = P.Printer_Value or else B >= 0;
这几乎达到了您想要的效果,但由于维护负担,我怀疑它是否值得。
post条件如何指定limited in out参数在子程序调用时不被修改?考虑以下代码:
with Ada.Text_IO;
procedure Main is
package C is
type Printer is tagged limited private;
procedure Print
(P : in out Printer;
B : Integer);
private
type Printer is tagged limited record
A : Integer := 0;
end record;
end C;
package body C is
procedure Print
(P : in out Printer;
B : Integer) is
begin
if B >= 0 then
P.A := B;
end if;
Ada.Text_IO.Put_Line (P.A'Image);
end Print;
end C;
P : C.Printer;
begin
P.Print (-1);
end Main;
当指定负数作为 Print 子程序的输入时,Printer 实例的内部状态在子程序调用期间保持不变。指定它的最佳方法是什么?尝试以下操作会产生错误消息 "attribute 'Old' cannot apply to limited objects":
procedure Print
(P : in out Printer;
B : Integer) with
Post => (if B < 0 then P'Old = P);
能否在 Ada 2020 标准的增量聚合中找到解决方案?
编辑:考虑到有限类型根据定义没有任何相等运算符,这可能是一个棘手的问题。
来自 RM 6.1.1
For each X'Old in a postcondition expression that is enabled, a constant is implicitly declared at the beginning of the subprogram or entry. The constant is of the type of X and is initialized to the result of evaluating X (as an expression) at the point of the constant declaration. The value of X'Old in the postcondition expression is the value of this constant; the type of X'Old is the type of X. These implicit constant declarations occur in an arbitrary order.
AARM 非常明确:
'Old makes no sense for limited types, because its implementation involves copying. It might make semantic sense to allow build-in-place, but it's not worth the trouble.
我认为增量聚合不会解决问题,因为我看不出它如何防止隐式复制。
然而,虽然您不能将 'old
应用于受限对象,但您可以将其应用于其一个或多个非受限组件。
procedure Print
(P : in out Printer;
B : Integer) with Post => (if B < 0 then P.A'Old = P.A);
当然,在您的示例中,组件 A 是私有的,因此这将不起作用,并且通常不适合 public 过程。
要解决这个问题,您可能需要将组件包装在 getter 函数中并编写:
function Printer_Value (P : in Printer) return Integer;
procedure Print
(P : in out Printer;
B : Integer) with Post => (if B < 0 then P.Printer_Value'Old = P.Printer_Value);
private
function Printer_Value (P : in Printer) return Integer is (P.A);
然后调整 Printer_Value 以手动包含应检查不变性的组件。但这也将无法编译,因为 P.Printer_Value'Old
可能未评估(当 B>=0
时)。 AARM 声明通常的解决方案是 P'Old.Printer_Value
但这是不可能的,因为 P 是有限的。所以要让它工作,我们必须无条件地评估它:
procedure Print
(P : in out Printer;
B : Integer) with Post => P.Printer_Value'Old = P.Printer_Value or else B >= 0;
这几乎达到了您想要的效果,但由于维护负担,我怀疑它是否值得。