Ada延迟常量使用复杂的计算最终确定;把代码放在哪里?
Ada deferred constant finalized using complicated calculation; where to put the code?
我需要相当复杂的计算结果来定义私有类型,如下所示:
generic
top_m : Positive;
package Mystic is
type T is private;
private
type Table is array (Positive range <>) of Positive;
function reallyComplicatedFunction(x : Positive) return Table;
mytable : constant Table := reallyComplicatedFunction(top_m);
-- I will need mytable for calculations later
type T is array (mytable'Range) of Natural;
-- T is very different from Table, except they share their Range
end Mystic;
我需要类型 T 以一种非常复杂的方式依赖于泛型参数 top_m,由 reallyComplicatedFunction(.) 体现。该函数定义在包 Mystic 的主体中,但它不使用包声明的任何其他内容。
令我惊讶的是,这个设置工作得很好。也许我只是幸运,因为据我对 ARM 的解密可以看出,这种函数调用只是 'legal' 但不能保证不会抛出 Program_Error。我将其解释为 "it would be too restrictive to forbid this sort of stuff entirely, but the compiler can't be expected to determine its feasibility in all cases either, so we'll just allow you to experiment with it"。然后很有可能我完全误读了参考手册。无论如何,关于 Ada 的书籍对这类事情给出了相当严厉的警告,通常围绕 pragma Elaborate 等人的讨论,以至于我几乎没有尝试这个解决方案。
我也试过将函数放在 Mystic 的私有子包中,但我无法解决依赖于父项的子项和依赖于子项的父项规范的隐式子项之间的循环问题。不管怎样,这个函数不是Mystic的扩展,而是初始化它的必要代码。
那么我的问题是:这种功能的合适位置在哪里?
ETA:应 Simon Wright 的要求,这是我遇到的 ARM 部分:http://www.ada-auth.org/standards/12rm/html/RM-3-11.html 条目 9、10/1 和 14:
For a construct that attempts to use a body, a check
(Elaboration_Check) is performed, as follows:
- For a call to a (non-protected) subprogram that has an explicit body, a check is made that the body is already elaborated. This check
and the evaluations of any actual parameters of the call are done in
an arbitrary order.
...
The exception Program_Error is raised if any of these checks fails.
据我所知,构造 mytable : constant Table := etc. 试图使用 reallyComplicatedFunction 的主体,因此它必须检查它是否被详细说明。我假设 - 这是我推理中的一个弱点,但这是我所理解的 - 对 reallyComplicatedFunction 主体的详细说明仅发生在包 Mystic 主体的详细说明期间,因此我的功能不会在当时详细说明从包规范的私有部分调用。尽管如此,我在使用包(的实例)时没有收到承诺的 Program_Error。
ETA2:根据 trashgod 的评论,我尝试将包 Mystic 变成一个非通用包;使 top_m 成为可见常量并删除通用部分。编译器现在捕获了我从一开始就担心的循环,程序以 Program_Error: access before elaboration 退出。就好像通用包的主体是在第一次实例化之前详细说明的,或者更确切地说,是在实例化期间详细说明所述包的规范之前。由于我希望 Ada 能够满足这种需求(隐藏在所述包的主体中实例化包所需的复杂计算),如果它按照标准工作,我不会感到惊讶,但我不记得在任何地方都读过类似的东西,想知道确切的规则。一些非常聪明的事情正在发生,因为如果我使函数的主体依赖于类型 T,编译器会在包实例化时警告 'call to Tt may occur before body is seen'(我猜 'Tt' 是类型 T 的某种内部性) ,当程序是 运行 时,它会抛出一个 Program_Error 抱怨在详细说明之前访问,指向类型 T 的对象被另一个函数实例化的第一个地方,我为了测试目的调用了 reallyComplicatedFunction .
假设(因为您没有指定)从 reallyComplicatedFunction
返回的数组具有范围 1..top_m
,您可以定义一个新的子类型并将其用作两个数组的范围:
subtype My_Range is Positive range 1..m_top
type Table is array (My_Range) of Positive;
type T is array (My_Range) of Natural;
并将 my_table
和 reallyComplicatedFunction
都移到包体中。
编辑,反映了解释为什么 reallyComplicatedFunction
不应该是 public.
的注释
如果我没理解错的话,函数并不是真的不依赖Mystic
,而是reallyComplicatedFunction
应该是private的。在那种情况下,我会尝试将它放在其他地方,并保持对 top_m
的依赖。我假设 Table
也可以移动,即使它在形式上创建了 reallyComplicatedFunction
的依赖性,Table
在其参数配置文件中。
为了解决,在层次结构中创建一个新的私有位置,一个私有兄弟获取声明,并且只会在原始 Mystic
的私有部分中使用。因此,private with
在后者的上下文子句中。
package Top is end;
private generic
top_m : Positive;
package Top.Outsourced is
type Table is array (Positive range <>) of Positive;
function reallyComplicatedFunction(x : Positive) return Table;
end Top.Outsourced;
private with Top.Outsourced;
generic
Top_M : Positive;
package Top.Mystic is
type T is private;
private
package Initializer is new Top.Outsourced (top_m);
subtype Table is Initializer.Table;
mytable : constant Table := Initializer.reallyComplicatedFunction (top_m);
-- I will need mytable for calculations later
type T is array (mytable'Range) of Natural;
-- T is very different from Table, except they share their Range
end Top.Mystic;
package body Top.Outsourced is
function reallyComplicatedFunction(x : Positive) return Table is
Limit : Positive;
begin
Limit := Positive'Min (top_m, 1) + x/2;
return Result : Table (1 .. Limit);
end reallyComplicatedFunction;
end Top.Outsourced;
我需要相当复杂的计算结果来定义私有类型,如下所示:
generic
top_m : Positive;
package Mystic is
type T is private;
private
type Table is array (Positive range <>) of Positive;
function reallyComplicatedFunction(x : Positive) return Table;
mytable : constant Table := reallyComplicatedFunction(top_m);
-- I will need mytable for calculations later
type T is array (mytable'Range) of Natural;
-- T is very different from Table, except they share their Range
end Mystic;
我需要类型 T 以一种非常复杂的方式依赖于泛型参数 top_m,由 reallyComplicatedFunction(.) 体现。该函数定义在包 Mystic 的主体中,但它不使用包声明的任何其他内容。
令我惊讶的是,这个设置工作得很好。也许我只是幸运,因为据我对 ARM 的解密可以看出,这种函数调用只是 'legal' 但不能保证不会抛出 Program_Error。我将其解释为 "it would be too restrictive to forbid this sort of stuff entirely, but the compiler can't be expected to determine its feasibility in all cases either, so we'll just allow you to experiment with it"。然后很有可能我完全误读了参考手册。无论如何,关于 Ada 的书籍对这类事情给出了相当严厉的警告,通常围绕 pragma Elaborate 等人的讨论,以至于我几乎没有尝试这个解决方案。
我也试过将函数放在 Mystic 的私有子包中,但我无法解决依赖于父项的子项和依赖于子项的父项规范的隐式子项之间的循环问题。不管怎样,这个函数不是Mystic的扩展,而是初始化它的必要代码。
那么我的问题是:这种功能的合适位置在哪里?
ETA:应 Simon Wright 的要求,这是我遇到的 ARM 部分:http://www.ada-auth.org/standards/12rm/html/RM-3-11.html 条目 9、10/1 和 14:
For a construct that attempts to use a body, a check (Elaboration_Check) is performed, as follows:
- For a call to a (non-protected) subprogram that has an explicit body, a check is made that the body is already elaborated. This check and the evaluations of any actual parameters of the call are done in an arbitrary order.
...
The exception Program_Error is raised if any of these checks fails.
据我所知,构造 mytable : constant Table := etc. 试图使用 reallyComplicatedFunction 的主体,因此它必须检查它是否被详细说明。我假设 - 这是我推理中的一个弱点,但这是我所理解的 - 对 reallyComplicatedFunction 主体的详细说明仅发生在包 Mystic 主体的详细说明期间,因此我的功能不会在当时详细说明从包规范的私有部分调用。尽管如此,我在使用包(的实例)时没有收到承诺的 Program_Error。
ETA2:根据 trashgod 的评论,我尝试将包 Mystic 变成一个非通用包;使 top_m 成为可见常量并删除通用部分。编译器现在捕获了我从一开始就担心的循环,程序以 Program_Error: access before elaboration 退出。就好像通用包的主体是在第一次实例化之前详细说明的,或者更确切地说,是在实例化期间详细说明所述包的规范之前。由于我希望 Ada 能够满足这种需求(隐藏在所述包的主体中实例化包所需的复杂计算),如果它按照标准工作,我不会感到惊讶,但我不记得在任何地方都读过类似的东西,想知道确切的规则。一些非常聪明的事情正在发生,因为如果我使函数的主体依赖于类型 T,编译器会在包实例化时警告 'call to Tt may occur before body is seen'(我猜 'Tt' 是类型 T 的某种内部性) ,当程序是 运行 时,它会抛出一个 Program_Error 抱怨在详细说明之前访问,指向类型 T 的对象被另一个函数实例化的第一个地方,我为了测试目的调用了 reallyComplicatedFunction .
假设(因为您没有指定)从 reallyComplicatedFunction
返回的数组具有范围 1..top_m
,您可以定义一个新的子类型并将其用作两个数组的范围:
subtype My_Range is Positive range 1..m_top
type Table is array (My_Range) of Positive;
type T is array (My_Range) of Natural;
并将 my_table
和 reallyComplicatedFunction
都移到包体中。
编辑,反映了解释为什么 reallyComplicatedFunction
不应该是 public.
如果我没理解错的话,函数并不是真的不依赖Mystic
,而是reallyComplicatedFunction
应该是private的。在那种情况下,我会尝试将它放在其他地方,并保持对 top_m
的依赖。我假设 Table
也可以移动,即使它在形式上创建了 reallyComplicatedFunction
的依赖性,Table
在其参数配置文件中。
为了解决,在层次结构中创建一个新的私有位置,一个私有兄弟获取声明,并且只会在原始 Mystic
的私有部分中使用。因此,private with
在后者的上下文子句中。
package Top is end;
private generic
top_m : Positive;
package Top.Outsourced is
type Table is array (Positive range <>) of Positive;
function reallyComplicatedFunction(x : Positive) return Table;
end Top.Outsourced;
private with Top.Outsourced;
generic
Top_M : Positive;
package Top.Mystic is
type T is private;
private
package Initializer is new Top.Outsourced (top_m);
subtype Table is Initializer.Table;
mytable : constant Table := Initializer.reallyComplicatedFunction (top_m);
-- I will need mytable for calculations later
type T is array (mytable'Range) of Natural;
-- T is very different from Table, except they share their Range
end Top.Mystic;
package body Top.Outsourced is
function reallyComplicatedFunction(x : Positive) return Table is
Limit : Positive;
begin
Limit := Positive'Min (top_m, 1) + x/2;
return Result : Table (1 .. Limit);
end reallyComplicatedFunction;
end Top.Outsourced;