In our familiar OO language, data and methods can be divided into different access levels through Access Control modifiers such as private, protected, and public. This article starts with a special encapsulation example to discuss topics related to encapsulation, type system, and contractual programming. Let's start with the example:
Public class Person {
Private int _ money;
Public void Change (amount ){
This. _ money + = amount;
}
Public void Exchange (Person p, int amount ){
P. _ money-= amount;
This. _ money + = amount;
}
}
Based on the assumption that "My money is not allowed to be moved directly without my permission", the Person class uses the Variable _ money as a private member and provides the public Change method. However, the controversial point is that in Exchange, we can directly access and modify p. _ money. Note that the above Code is completely legal in the C # compiler, and similar code is the same in C ++ and Java. When I first came into contact with this example, I initially wondered whether the compiler was correct or wrong? Later I thought of a reason that "OO encapsulation is based on classes rather than objects" to convince myself.
Now I have an updated understanding of this issue and hope to discuss it with you. In the above example, we ideally expect that the Person object itself can directly access its own _ money variable, and other Person objects cannot be directly accessed. However, the encapsulation Implementation of OO must rely on the compiler for static access permission check. Since it is static, it can only be applied to the type and cannot be applied to the object instance. Therefore, in the preceding example, the C # compiler cannot confirm whether p and this reference the same object or different objects. In this sense, the encapsulation of OO to the class level is not so much an option as design considerations.
On a larger level, this example is not only related to OO encapsulation, but essentially reflects the functions and limitations of a programming language system. The Type System of the program language is a static tracking and check mechanism that ensures the correctness of the program type, but does not guarantee the semantic correctness (ideally, in the above example, if p and this are the same object, the semantics is correct. Otherwise, the semantics is incorrect ). In other words, the type correctness can be expressed and checked in a formal manner by the type system. How can we ensure semantic correctness? Is there a formal approach? The answer may be like the following:
Public class Person {
Private int _ money;
Public void Change (amount ){
This. _ money + = amount;
}
Public void Exchange (Person p, int amount ){
Assert (this! = P );
P. Change (-amount );
This. _ money + = amount;
}
}
Adding Assert assertions is to ensure the correctness of semantics in the form. My understanding is: we need a formal method to ensure the correctness of semantics. Is this the original intention of the so-called contractual programming? Hope you can give me some advice!