dacker
dacker

Reputation: 457

Overloading operator "=" for anonymous access types?

I am working my way through Barnes' excellent Ada book. This is a code sample for deep comparison of linked lists from section 11.7:

type Cell is
  record
    Next: access Cell;
    Value: Integer;
  end record;

function "=" (L, R: access Cell) return Boolean is
begin
  if L = null or R = null then    -- universal =
    return L = R;                 -- universal = (Line A)
  elsif L.Value = R.Value then
    return L.Next = R.Next;       -- recurses OK (Line B)
  else
    return False;
  end if;
end "=";

I can't seem to wrap my head around why in Line A operator "=" of the universal_access type is called (because of the preference rule), on Line B, however, the user-defined operator "=" is called (which makes recursion possible in the first place), this time with no preference for operator "=" of universal_access.

Both L and R, as well as L.Next and R.Next are of the same anonymous type "access Cell". Why the difference in "dispatching"? Does it have to do with L and R being access parameters? If so, what is the rule there?

I did my best to find anything in the AARM, especially section 4.5.2, but could not make any sense of it.

Cheers.

Upvotes: 5

Views: 210

Answers (2)

dacker
dacker

Reputation: 457

I will summarize my findings (with the help of Simon Wright and G_Zeus) as of now. Please correct me if I'm wrong:

According to the standard, L = null, R = null, L = R as well as L.Next = R.Next should each unambiguously call the user-defined operator =. universal_access operator = must not kick in at all here.

Reason:

The operands L, R, L.Next and R.Next violate the precondition in ARM 4.5.2(9.1-9.4) for interpreting = in these expressions as to mean operator = of the universal_access type:

The precondition says that neither of the operands are of an access-to-object type (access Cell) whose designated type is Cell (check), Cell has a user-defined primitive equality operator (check) such that

  • its result type is Boolean (check);
  • it is declared immediately within the same declaration list as Cell (check); and
  • at least one of its operands is an access parameter with designated type Cell (both operands are, check).

The preference rule for operator = of the universal_access type in ARM 8.6(29.1) does not apply here, since it requires "two acceptable interpretations". But because of 4.5.2, operator = of the universal_access type is not an acceptable interpretation.

So there is no choice: in all cases (even L = null) it has to be the user-defined operator =.

@Simon Wright: So "unbounded recursion" is actually the correct compiler behavior.

@G_Zeus: Issuing an ambiguity error for l = r is incorrect compiler behavior, the compiler should have picked Access_Equal."=".

The example should correctly read:

...

  if Standard."="(L, null) or Standard."="(R, null) then    -- universal =
    return Standard."="(L, R);                              -- universal =
  elsif L.Value = R.Value then
    return L.Next = R.Next;                                 -- recurses OK

...

Cheers.

Upvotes: 5

G_Zeus
G_Zeus

Reputation: 71

I do not have enough reputation to comment on OP, so I will write an answer instead.

Interestingly enough, I cannot compile such an example (I used Integer access instead, but I doubt it has any relevance) in Gnat 6.1.1. Gnat keeps telling me the use of inline "=" is ambiguous between the overloading "=" and the universal "=" in Standard. So I tried:

package body Access_Equal is
   function "=" (L,R : access Integer) return Boolean is
   begin
      return Standard."="(L, R) or L.all = R.all;
   end "=";
end Access_Equal;

And it seems to do the trick. I cannot use inline "=" in my code however, I have to use fully qualified names:

with Ada.Text_IO; use Ada.Text_IO;
with Access_Equal; use Access_Equal;
procedure Access_Equal_Test is
   l : access Integer := new Integer'(1);
   r : access Integer := new Integer'(1);
begin
   Put_Line(Boolean'Image(Standard."="(l, r))); -- FALSE
   Put_Line(Boolean'Image(Access_Equal."="(l, r))); -- TRUE
   Put_Line(Boolean'Image(l = r)); -- does not work
end Access_Equal_Test;

Note: using the Standard package might be a portability hazard, as it does not seem to be required to define universal "=". More information here.

Upvotes: 1

Related Questions