When you define the type A_Access
, the compiler automatically defines an equality operator for you:
function "=" (Left, Right : A_Access) return Boolean; --built-in function
When you define your own, though:
function "=" (Left, Right : A_Access) return Boolean is
Right after the is
keyword, your new function becomes visible, and any time you use it on two operands of type A_Access
, it will call your new function--including inside the body of your function. That means that the line
if null = Left or null = Right then
will call your "="
recursively, leading to a stack overflow.
To get around this, you can rename the built-in function before you define your own "="
:
type A_Access is access all A'Class;
-- the following declaration is implicitly added by the compiler
--function "=" (Left, Right : A_Access) return Boolean; --built-in function
function Builtin_Equal (Left, Right : A_Access) return Boolean renames "=";
Since your new "="
isn't visible at that point, renames "="
will rename the built-in function. Now you can use your new name:
function "=" (Left, Right : A_Access) return Boolean is
use Ada.Tags;
begin
if Builtin_Equal (null, Left) or else Builtin_Equal (null, Right) then
return False; -- THIS IS WRONG!
else
return (Left.all'Tag = Right.all'Tag and then Left.a = Right.a);
end if;
end "=";
(I changed or
to or else
because it's my preference, and because it will sometimes save a little bit of time if the code doesn't have to evaluate both operands. It doesn't matter much.)
Also, do you really want your "="
to return False
if both sides are null
? Try this instead:
function "=" (Left, Right : A_Access) return Boolean is
use Ada.Tags;
begin
if Builtin_Equal (null, Left) or else Builtin_Equal (null, Right) then
return Builtin_Equal (Left, Right);
else
return (Left.all'Tag = Right.all'Tag and then Left.a = Right.a);
end if;
end "=";
which returns true
if both are null
, false
if either one is null
but not both, and otherwise it will check your tag and a
component. Another way to do it, which is a little more efficient if Left
and Right
happen to be the exact same pointer:
function "=" (Left, Right : A_Access) return Boolean is
use Ada.Tags;
begin
if Builtin_Equal (Left, Right) then
return true;
elsif Builtin_Equal (null, Left) or else Builtin_Equal (null, Right) then
return false;
else
return (Left.all'Tag = Right.all'Tag and then Left.a = Right.a);
end if;
end "=";