Abstract nonsense

I happened to see somewhere declarations like this:

procedure P (x : in out T'Class) is abstract;

where T is a tagged type. Ouch, isn’t it?
Fortunately, GNAT shows the following message:

warning: abstract subprogram is not dispatching or overriding [-gnatwr]

but only when the switch is enabled.
I am wondering why it is legal Ada in the first place.

You can even write this:

procedure Q is abstract;

It compiles successfully (both GNAT and ObjectAda do it at least) !
Isn’t it a gap in the Ada rules?

Full reproducer here:

package Abstract_Nonsense is

  type T is abstract tagged null record;
  
  procedure P (x : in out T'Class) is abstract;

  procedure Q is abstract;
  
end;

--  gnatmake -gnatwr abstract_nonsense.ads:
--
--  abstract_nonsense.ads:5:39: warning: abstract subprogram is not dispatching or overriding [-gnatwr]
--  abstract_nonsense.ads:7:18: warning: abstract subprogram is not dispatching or overriding [-gnatwr]

No, it is designed to be this way and has an important function. Declaring a subprogram abstract hides it. E.g.

type T is new Integer;
function "/" (Left, Rgiht : T) return T is abstract; -- No more "/"

Note a subtle difference. If a primitive subprogram is declared abstract when the tagged type declaration is not frozen that declares an abstract primitive subprogram that must be overridden (implemented) in a concrete derived type.

type T is abstract tagged null record;
procedure P (X : in out T'Class) is abstract; -- Hidden
procedure Q is abstract; -- Hidden
procedure S (X : in out T) is abstract; -- Primitive

Here neither P nor Q are primitive, so declaring abstract hides them. Now consider S:

   type U is new T with null record
   overriding procedure S (X : in out U); -- Required!

Further

   X : U; -- The type U is frozen at this point
   procedure S (X : in out U) is abstract; -- Hides the override!
begin
   S (X); -- Error, S is declared abstract and hides the primitive S
   X.S;   -- OK, primitive subprograms are always reachable
3 Likes

Ah, I found the paragraphs:

Ramification: {AI95-00310-01} {AI12-0413-1} If an abstract subprogram is not a dispatching operation of some tagged type, then it cannot be called at all. In Ada 2005, such subprograms are not even considered by name resolution (see 6.4).
{AI95-00310-01} In Ada 2005, abstract primitive subprograms of an untagged type may be used to “undefine” an operation.
{AI95-00251-01} {AI95-00334-01} If the type is abstract or untagged, the implicitly declared subprogram is abstract.
Ramification: Note that it is possible to override a concrete subprogram with an abstract one.

Slight precision, for the laymen among us: we override a concrete subprogram with an abstract one, but only with non-tagged types, or abstract tagged ones. Ok, I learnt something useful !

1 Like