在Ada中链接的方法

时间:2014-08-30 23:34:33

标签: oop ada

所以很多语言都有这样的模式:

object = Create_Object().Set(1).Set(2).Set(3);

(我相信这起源于Smalltalk。)这是有效的,因为Set()方法返回对其接收者的引用。

我可以在Ada做这样的事吗?

我尝试过的工作包括:

-- doesn't work because the returned object is a read-only copy of the receiver
function Set(self: in out Object) return Object;

-- doesn't work because I can't return an access to a local variable
function Set(self: in out Object) return access Object;

-- looks like it works until I realise that it's not a method, and isn't doing
-- dynamic dispatch [*]
function Set(self: access Object) return access Object;

可以这样做吗?

3 个答案:

答案 0 :(得分:1)

我认为使用此配置文件的功能将为您完成这项工作:

function Set (Target   : in Instance;
              New_Item : in Integer) return Instance;

围绕该函数声明编写完整的包,我可以写:

Object := Set (1).Set (2).Set (3);
Object.Show;

并获得输出:

{1, 2, 3}

我已将完整的资源推送到http://repositories.jacob-sparre.dk/miscellaneous-ada-2005-examples/

答案 1 :(得分:1)

你的第三个提议是正确的方法,当你输入" access"时,你实际上定义了一个原始操作。对于参数。下面是一个示例,它使用两个标记类型来显示调度发生的位置,并使用方法调用的链接。为方便起见,我提供了一个程序,否则您将不得不使用临时变量。我已经使用了Create_Object,但显式调用了" new",但这当然是同样的事情。另外,我已经展示了一个例子,当Ada静态地知道所涉及的类型时,它不会进行动态调度。这实际上是一个很好的功能(性能方面),即使它确实需要关注(甚至专家也时不时地被咬:=)

with Utils; use Utils;    
procedure Chain is
   O : access Object := new Object;
   C : access Child := new Child;
begin
   O.Add (1).Add (2);
   C.Add (3).Add (4);
end Chain;

package Utils is    
   type Object is tagged null record;
   function Add (Self : access Object; Val : Integer) return access Object;
   procedure Add (Self : access Object; Val : Integer);  --  for convenience

   type Child is new Object with null record;
   overriding function Add (Self : access Child; Val : Integer) return access Child;
   overriding procedure Add (Self : access Child; Val : Integer);  --  for convenience
end Utils;

with Ada.Text_IO; use Ada.Text_IO;    
package body Utils is    
   function Add (Self : access Object; Val : Integer) return access Object is
   begin
      Put_Line ("func Object.Add" & Val'Img);
      Self.Add (Val);   --  static call, not dynamic dispatch
      return Self;
   end Add;

   procedure Add (Self : access Object; Val : Integer) is
   begin
      Put_Line ("proc Object.add" & Val'Img);
   end Add;

   overriding function Add (Self : access Child; Val : Integer) return access Child is
   begin
      Put_Line ("Child.Add" & Val'Img);
      Self.Add (Val);   --  static call, not dynamic dispatch
      return Self;
   end Add;

   overriding procedure Add (Self : access Child; Val : Integer) is
   begin
      Put_Line ("proc Child.Add" & Val'Img);
   end Add;   
end Utils;

该程序的输出是:

func Object.Add 1
proc Object.add 1
proc Object.add 2
Child.Add 3
proc Child.Add 3
proc Child.Add 4

编辑:正如评论中所讨论的,建议始终使用覆盖以确保该过程确实覆盖,而不是使用不同的配置文件。访问参数确实创建了一个原始操作。

答案 2 :(得分:0)

从第18段开始,函数[formal]参数只能使用'in'模式(只读)。因此输入对象不会被修改。

  

18 {参数模式}形式参数的参数模式用实际参数传递信息传递的方向:in,in out或out。 Mode in是默认值,是access_definition定义的参数模式。函数的形式参数(如果有的话)应具有模式。[Ada 2005]

所以我不认为该语言支持它,如其他语言所示。

但是,如果您不介意复制,我们可以将结果保存回对象中,但这与您引用的其他语言不同。

obj := obj.set("this").set(123).set(some_other_type);

您在'obj'的副本上设置“this”并返回该副本。从该副本中,我们创建一个新副本并在该副本中设置123,然后返回该副本。最后,复制了最后一个结果,并将'some_other_type'设置为它。返回最后一个副本,我们可以将其保存在obj中。请注意,如果set()函数足够小并且内联,那么优化的实现可以避免大多数(如果不是全部)副本,但我不能使用它。

回想起来,使用程序:

obj.set("this");
obj.set(123);
obj.set(some_other_type);

根本不会复制。