4. Subsumption and Dynamic Dispatch (Translator Press: Oh, 驴 技穷, I can't find the right translation)
From the above examples, it seems that the subclass is only used to borrow some definitions from the parent class to avoid repetition. However, when we consider Subsumption, things are somewhat different. What is SUBSUMPTION? Please see the following example:
Var mycell: instancetypeof (cell): = new cell;
Var myrecell: instancetypeof (recell): = new reccell
Procedure f (x: instancetypeof (cell)) is ... end;
Look at the following code:
Mycell: = MyRecell;
f (MyRecell);
In these two lines of code, the headband assigns an InstanceTypeOf (Recell) variable to a variable of instancetypeof (Cell). The second line uses the instanceTypeOf (Recell) variable as a parameter to a function of the parameter type InstanceTypeOf (Cell).
This use is illegal in language similar to PASCAL. In the object-oriented language, it is based on the following rules, it is completely correct usa. This rule is often called subtype polimorphism, namely, the translator is pressed: in fact subtyping should be the most different from OO language.
If c 'is a subclass of C, and O' is an example of C ', then O' is an example of C.
More stringent:
If c 'is a subclass of C, and O': InstanceTypeOf (c '), then o': instancetypeof (c).
Carefully analyze the above rules, we can introduce a sub-type relationship that meets the anti-translational sub-type between the type of InstanceTypeOf, and we use the <: symbol. (The translator is pressed by: It is said that any A, A relationship A is established, for example, the relationship between mathematics is reversed. And the transfer is said that if the A relation is B, B relationship C, Launched a relationship C. Great than, less than or other relationships are delivered)
Then the rule above can be dismantled into two rules:
1. For any A: A, if a: b, then A: B.
2. InstanceTypeOf (c ') <: instancetypeof (c) is only when C' is a subclass of C
The first rule is called Subsumption. It is a unique criterion for judging subtypes (attention, is Subtype, not subclass).
The second rule can be called subclassing-is-subtyping (subclass is a subtype, take a mouth?)
In general, inheritance is related to subclassing, so this rule can also be called: inheritance-is-subtyping (inheritance is subtype)
All object-oriented languages support subsumption (which can be said, there is no Subsumption, it is not object-oriented).
Most of the class-oriented language-oriented language does not distinguish between Subclassings and Subtyping. However, some of the latest object-oriented languages take a method of separating subtyping and subsclassing. That is, A is the subclass of B, but the object of Class A cannot be used as an object of a class B. (Translator Press: It is a bit like private inheritance in C , but the content is better than it. About Subclassings and Subtyping, we will tell.
Below, let's take back this procedure f. Under Subsumption, what is the dynamic semantics of this code?
Procedure f (x: instancetypeof (cell)) IS
x.set (3);
END;
f (MyRecell);
When MyRecell is used as an object of instancetypeof (Cell), X.SET (3) is called which version of the SET method? Is the set defined in the cell or that defined in the RECELL?
At this time, we have two options.
1. Static Dispatch (decide according to the type of compile)
2. Dynamic Dispatch (Decided according to the actual type of objects)
(Translator pressed, friends who are familiar with C must smile, this is simple.)
Static Dispatch has nothing to say.
Dynamic Dispatch has an interesting attribute. That is, Subsumption must not affect the status of the object. If you change this object's status, such as the object slice in C , then dynamic parsing method may fail.
Ok, this attribute is very beneficial to semantically or in efficiency.
(Translator pressed,
Object slicing in C will initialize the VPTR of the new object into its own type of VTable pointer, so there is no dynamic resolution. But in fact, the object slice does not be called Subsumption.
In the specific language implementation, such as C , although Subsumption does not change the status of the object, but the value of the pointer may change. This is also a hateful thing, but the C vTable program can only be like this. There is a variant VTABLE method to avoid changes in pointers and more efficient. We will explain this method in another article. )
5. Salang lost horse (about type information)
Although Subsumption does not change the status of the object, in some languages (such as Java), it doesn't even have any runtime overhead. However, it allows us to throw some static type information.
For example, we have a type of instanceTypeOf (Object), and any properties and methods are not defined in the Object class. We also have a class MyObject, which inherits from Object. Then when we handle myObject's object as an instanceTypeof (Object) type, we get a no-empty object that is not used.
Of course, if we consider a less extreme situation, for example, a method f is defined in the object class, and myObject is overloaded to method f, then, by Dynamic Dispatch, we can still operate attribute in MyObject. And methods. This is also a typical method for object-oriented design and programming.
From a Purist's perspective (the translator presses, very unfortunate, I am a purity), Dynamic Dispatch is the only thing you should use to have forgotten by Subsumption. It is elegant, safe, all glory is attributed to Dynamic Dispatch! ! ! (Translator pressed, this sentence is what I said) However, let PuriSt disappoint, most languages provide some attributes and methods for checking object types at runtime, and to operate for forgetting the properties and methods for Subsumption. This method is generally called Run Time Type Identification. Such as Dynamic_cast, or the instanceof in Java in C .
Requirements doctors say that RTTI is useful. (Translator pressed, typical existence is reasonable robber logic, mad at me!). But because some theoretical and methodological reasons, it is considered to destroy the object-oriented purity.
First, it destroys abstraction, so that some methods and properties that should not be used are not used correctly.
Second, because of the uncertainty of runtime, it effectively becomes more fragile.
Third, maybe it is the most important point, it makes your program lack scalability. When you join a new type, you may need to read your Dynamic_cast or instanceof code carefully, and change them if necessary to ensure that this new type of joining will not cause problems. In this process, the compiler will not give you any help.
Many people mention RTTI, always focus on its runtime overhead. However, this time the expenditure of this runtime is not enough than the shortcomings of the methodology.
In the framework of the Purist (the translator presses, sucks your mouth, visiting the distance, deposited), the addition of new subclasses does not need to change the existing code.
This is a very good advantage, especially when you don't have all source code.
In general, although RTTI (also called Type Case) seems to be inevitable, it must be used very cautious because of some shortcomings in its methodology. Many things in the type of language-oriented language today are all kinds of efforts to avoid RTTI.
For example, some complex types of types can be used to use the SELF type on the parameters and return values to avoid RTTI. This will be introduced later.
6. Coordination, anti-co-change and pressure roots constant (Covarance, Contravariance and Invariance)
In the following sections, let's introduce a type technology to avoid RTTI. Prior to this, let's introduce the concept of "Co-Crane", "Anti-Coordination" and "Roots."
Coordination
First, let's look at a PAIR type: a * b
This type supports a geta () operation to return A elements in this pair.
Given a A '<: A, then we can say A' * B <: a * b.
why? We can prove with the properties of Subsumption:
Suppose we have a A '* B type object a' * b, here, A ': A', B: B, A '* B <: a' * b
Then, because, A '<: a, from Subsumption, we can know A': a, geta (): a, so A '* b <: a * b
In this way, we define this type of A * b to be coordinated for A.
Similarly, we can also prove that A * B is also coordinated for B.
Squiry, Covariance is defined: given L (T), here, the type L is combined by the type T. Then
If T1 <: t2 is able to introduce L (T1) <: L (T2), then we say that L is co-change to T.
Anti-coordination
Please see a function: A f (b b); (definition with functional language may be more concise, ie f: b-> a)
So, what kind of subtype relationship is given between B-> A and B '-> A?
It can be proved that B-> a <: b '-> a.
Based on the space, we no longer be derived.
Therefore, the parameter type of the function is anti-cooperative.
The definition of the regular point of Contravariance is like this:
Given L (T), here, type L is combined by type T. Then
If T1 <: t2 can be launched L (T2) <: L (T1), then let's say that L is anti-co-change to T.
Similarly, it can be proved that the return type of the function is coordinated.
Indifferent roots
Then we consider the function g: A-> a
Here, A does both the position of the parameter, and there is a position returned, which can be proved that it is neither a coordination, nor is not anti-coordination.
For this case that is neither a coordination, it is not anti-union, we call INVARIANCE (the translator is pressing: "The turbulence is constant" is my editor, such a translation of the old earth, you don't want to be true)
It is worth noting that for the PAIR type in the first example, if we support Seta (a), then Pair turns into invariance.
7. Method Specialization
In the discussion of Subclass in front of us, we took the simplest rule of Override, that is, Overriding method must have the same Signature as Overriden's method.
However, this is not necessary from the perspective of type security. Apply the knowledge of the cohabese and anti-co-change in our previous discussion, we can completely change the return type of the method, let the method's parameter types.
Thus, as long as a <: a ', b' <: b, the following code is legal:
Class C Is
Method M (x: a): b is ... End;
Method M1 (X1: A1): B1 is ... END;
END;
SUBCLASS C 'OF C IS
OVERRIDE M (X: a '): b' is ... End;
END;
We don't allow coordination of properties. Because only immutable properties are coordinated. Allow modifications to attributes make the properties in invariant.
Special Variable Self This has an interesting attribute that is a parameter, but it is coordinated. This special feature is that since the SELF variable can only be incorporated by the compiler, the unsafeness of the Candarity parameters is avoided.
Another interesting place is that the above cohabement occurs when Override, that is, when the subclass has to rewrite the method of the parent class. However, when inheriting, the variation rules of the parameters and return types are another matter.
For example, the following example:
Class C Is
Method M (x: a): b is ... End;
Method M1 (X1: A1): B1 is ... END;
END;
SUBCLASS C 'OF C IS
Inherit M (x: a '): b';
// Here, the code M of the method M is inherited, and the subclass is only the interface SIGNATUREEND of the method M;
Then, here, the parameter is coordinated, and the return type is anti-cooperative.
Here, from the other side, we have seen subtyping (through Override), and Subclassing (through inheritance) essentially.
8. Specialization of Self Type Specialization
Methods Specialize Allows you to flexibly change the type when inheriting or rewriting the parent class in the subclass.
In addition, we may need another flexibility. Consider the following code:
Class C Is
Method getself (): InstanceTypeOf (c) IS
Return Self;
END;
END;
SUBCLASS C 'OF C IS
VAR Y: Integer: = 0;
END;
InstanceTypeOf (c ') x: = (new c'). Getself ();
Here, the last sentence is illegal, because the return type of GetSelf () is InstanceTypeOf (C), and the Type of X is InstanceTypeOf (C ').
Of course, subclass C 'can overrunate GetSelf () methods, return type instancetypeof (c'):
SUBCLASS C 'OF C IS
VAR Y: Integer: = 0;
Override getself (): instancetypeof (c ') IS
Return Self;
END;
END;
Thus, because the return type of the method is coordinated, and the special variable Self (the translator is pressed, the THIS in C / Java) is coordinated inheritance or overload, so the above subclass definition is feasible.
However, this requires that each subclass will overload this method. Moreover, this overload is also impossible if some of the ways returning a self-designed ways to hide some logic. such as:
Class C Is
Method ChangeandReturn (): InstanceTypeOf (C) IS
... // Do some update operations. And hide the logic of subclass.
Return Self;
END;
END;
SUBCLASS C 'OF C IS
VAR Y: Integer: = 0;
OVERRIDE CHANGEANDRETURN (): InstanceTypeOf (c ') IS
Return super.changeAndreturn ();
END;
END;
The definition of this subclass C 'here is not established, because super.changeandreturn () returns InstanceTypeOf (C).
So, is there a way to make the child c 'inherited naturally return to InstanceTypeOf (c')? In this way, because we have not been forced to lose any type of information, RTTI can be avoided.
This consideration will naturally lead to a new type: SELF type. Similar to the Self variable, the SELF type represents the runtime real type of this object. Only the SELF variable is a self type. This type is safe because of the special class of class of Self variables. With the SELF type, the above examples can be rewritten:
Class C Is
Method getself (): self is
Return Self;
END;
END;
SUBCLASS C 'OF C IS
VAR Y: Integer: = 0;
END;
InstanceTypeOf (c ') x: = (new c'). Getself (); this time, the last sentence is legal because the return type of getself () is InstanceTypeOf (c ').
In addition to the return type of the method, we can also define the property as a Self type. In order to ensure the security of the type, such an attribute can only be initialized or updated with the value of Self or other SELF type. That is, if a SELF type property is defined in Class C, you cannot initialize or update it with a variable of instancetypeof (c).
The extension of a typical class-oriented language as described above is feasible, and there is no side effects (except for the type inspection system slightly more complicated). It greatly enhances the expression of strong types of object-oriented language. And effectively prevent unnecessary loss of type information.
Naturally, the reader may think of the parameters of the SELF type for the method. Eiffel is doing this. But unfortunately, the parameters are Contravariant for overloading, just like the foregoing. When overloaded, the type is generally available, but it is not safe.
However, in the class-oriented domain-oriented domain, the parameters use the SELF type or extensive research. We will introduce related technologies later.
Next chapter:
Object type, generic technology, separation subclassing and subtyping, object protocol (Object Protocol).