何时使用Pragma Pure / Preelaborate

24
有没有一组通用规则/准则,可以帮助理解何时更喜欢使用pragma Purepragma Preelaborate或其他完全不同的内容?在标准(Ada 2012)中呈现的规则和定义有点晦涩难懂,我很感激能读到一些更加清晰且针对平均情况的东西。
如果我想彻底而不完全理解其中的“原因”,我可以简单地尝试:
  • 使用pragma Pure;标记包规范;
  • 如果它不能编译,请尝试使用pragma Preelaborate;
  • 如果失败,则我做了一些棘手的事情,需要逐个with-by-with基础上考虑对pragma Elaborate单位进行标记,或者重新思考包布局。
虽然这可能有效(是吗?),因为建议尽可能将包标记为Pure(同样适用于Preelaborate),但它似乎有些混乱,我更愿意更好地了解这个过程。
2个回答

28

pragma Pure

您应该在任何没有内部状态的包上使用此指令。它告诉包的用户,调用任何子程序都没有副作用,因为没有内部状态可以更改。因此,在纯包中声明的库级函数在使用相同参数调用时将始终返回相同的结果。

Ada实现允许缓存纯包函数的返回值,并省略调用子程序,如果由于这些要求不会使用它们的返回值。但是,您可以通过在纯包内调用导入的子程序(例如来自C库)来违反限制(这些可能会更改Ada编译器不知道的某些内部状态)。如果您非常邪恶,甚至可以使用pragma Import从软件其他部分导入Ada子程序来绕过pragma Pure的要求。不用说:如果您做任何这样的事情,请不要使用pragma Pure

编辑:为了澄清调用可能被省略的情况,让我引用一下ARM

如果库单元被声明为纯的,则允许实现在库单元的库级子程序上省略调用,如果在调用后不需要结果。同样,它可以省略这样的调用,并仅重复使用由先前对相同子程序的调用产生的结果,前提是没有任何参数具有限制类型,并且所有按引用传递的实际参数的地址和值以及所有按复制传入的实际参数的值与早期调用时相同。即使在调用时,子程序产生其他副作用,也适用此权限。

例如,GNAT 还定义了任何接受类型为 System.Address 或其派生类型的参数的子例程都不被认为是纯函数,即使它们在一个纯包中定义,因为地址指向的位置可能会被更改,但 GNAT 不知道地址指向哪种结构,因此无法检查参数的引用值是否已更改。 pragma Preelaborate 这告诉编译器该包在实例化时不会执行任何代码(即在主过程开始执行之前)。在实例化时,将执行以下结构:
- 库级别变量的初始化(可以是函数调用) - 在库级别声明的任务的初始化(它们可能在主程序之前开始执行) - 在begin ... end块中的语句
如果不需要这些内容,通常应避免使用它们。尽可能使用 pragma Preelaborate,它告诉调用者可以安全地使用该包而无需在实例化时执行任何内容。
如果某些东西不适用于这些编译指示符并且你认为应该适用,请查看其原因。这可能有助于您发现包实现或结构的问题。不要仅仅因为无法编译就去掉 pragma。由于约束影响依赖于您的任何包的可能约束,因此您应始终选择最严格的适用编译指示符。

Pure 的行为,关于子程序不产生副作用的要求,它只适用于 函数 还是也影响 过程?而且所谓的副作用,是指局部于包内吗?例如,一个接受 not null access Root_Stream_Type'Class 的流程过程;显然,该过程会改变流程,那么即使流程是从其他地方传入的,这是否意味着该包不是 Pure 的? - Anthony
1
Root_Stream_Type 受限,因此将其作为参数的子程序调用可能不可省略。我在我的答案中添加了 ARM 的相关部分。但从概念上讲,它确实涉及到与包本地和其依赖包相关的副作用。 - flyx

5
< p > GNAT中的详细顺序处理 是一份有用的指南。理想情况下,标准规则对大多数程序都足够适用。这些编译器指示语告诉编译器替换你的详细顺序。它们应该被应用于解决特定问题,而不是经验性地使用。

补充说明:@ajb强调了指令之间的重要区别。所引用的文章同意问题概述中列出的方法(第一和第二个项目符号):“因此,一个好的规则是尽可能将单位标记为PurePreelaborate,如果不可能,则将其标记为Elaborate_Body。” 它还讨论了无法使用这三个指令的情况(第三个项目符号)。


1
我认为你在想Elaborate、Elaborate_All和Elaborate_Body这些编译指示符,它们的目的是控制实例化顺序。除了Elaborate_Body告诉编译器该包需要一个主体之外,它们什么也不做。Pure和Preelaborate则明确声明一个包不包含某些构造。 - ajb
2
@trashgod 我不得不避免把我的问题表述为“你能详细说明预先准备吗?” - Anthony
是的,我喜欢Ada语言,但学术界的人参与太多了。那么,“initialize”、“setup”或“preamble”怎么样? - ATL_DEV

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接