4

Somewhat embarassed to ask this, but I know it's for the best. I've been programming in Ada for many years now, and understand nearly every part of the language fluently. However, I've never seemed able to wrap my head around T'Class. To borrow from others, can someone "explain it like I'm five?".

Edit: I bought it just to have, but contained within is a great description of, and example use of, T'Class; I refer to “Software Construction and Data Structures with Ada 95” by Michael B. Feldman.

Patrick Kelly
  • 633
  • 5
  • 22

2 Answers2

5

If you start with

package P1 is
   type T is tagged private;
   procedure Method (Self : T);
end P1;
package P2 is
   procedure Proc (Self : T);  -- not a primitive
   procedure Proc2 (Self : T'Class);
end P2;

In the case of Proc, you are telling the compiler that the parameter should always be considered precisely as of type T (remember that a tagged type is always passed by reference, so the actual type could be derived from T of course, you would not lose the extra data). In particular, that means that within the body of Proc, all calls to Method will be exactly calls to P1.Method, never a call to an overriding Method.

In the case of Proc2, you are telling the compiler that you do not know the exact type statically, so it will need to insert extra code to resolve things at run time. A call to Method, within the body of Proc2, could be call to P1.Method, or to another overriding Method.

Basically: with 'Class, things are resolved at runtime.

manuBriot
  • 2,755
  • 13
  • 21
  • Where I seem to get confused though, is if I derive T, by creating a child T2, can't I use both Proc and Proc2 with instances of T2 as the argument? If I understood you correctly, if T2 overrides method, then T2.Proc will actually call T.Method, while T2.Proc2 will call T2.Method. – Patrick Kelly Feb 12 '15 at 19:10
  • 1
    Yes, you can use both Proc and Proc2 (although in the case of Proc you will have to cast: Proc(T (Var)). The differences occurs when the proc executes a call to Method, since a different subprogram would be called in the two cases (assuming T2 overrides Method). Your understanding of the dispatching is correct (except that you can't call T2.Proc to T2.Proc2, just Proc2(T2), this is not a primitive operation. – manuBriot Feb 13 '15 at 09:02
  • No it doesn't I believe. First of all, T2 here is the name of a type, and we can't use "T2.Proc" on a type. Let's assume that the original author meant "Var.Proc2", where Var is of type T2. Then "Var.Proc2" is only allowed if Proc2 is defined in the same package as T2 is defined, otherwise the dot notation doesn't apply. In my example, Proc2 is defined in a different package, so you can't use Var.Proc2 – manuBriot Feb 15 '15 at 08:47
  • I know about T2 being the name of a type: I was just following your comment! Please look at [this example](https://www.dropbox.com/s/sgiqjrd88yme91k/pc.ada?dl=0) (gnatchop, then gnatmake): Main happily calls Childsprint.Prints, even though Parents isn’t visible. – Simon Wright Feb 15 '15 at 17:01
  • Yes, of course it does. `Prints` is defined in the `Parents` package, same as the `Parent` type. As such, you can indeed use `.Prints` for any type derived of `Parent`. But in our example in this thread `Proc2` is defined in another package than the type `T`, and as such you cannot use `.Proc2`. – manuBriot Feb 16 '15 at 07:24
2

Well, if you were five, I would say that T'Class represents the whole family of T. By family, we mean children and grand-children and grand-grand-children.

As you're not five, it means that this special type represents every tagged type which is in the inheritance tree of T. This way, if you use this type as a parameter, you can use every parameter which has T as ancestor directly or not. For more information, you can read the wikibooks on this.

Frédéric Praca
  • 1,620
  • 15
  • 29