Re: Object identity
- From: "H. S. Lahman" <h.lahman@xxxxxxxxxxx>
- Date: Sun, 25 Jun 2006 00:04:48 GMT
Responding to Barrett-Lennard...
Firstly I will characterise the misconception more carefully: Rather
informally it states that it is implicit to OO that object instances
represent entities from the problem space. Therefore object identity
is fundamentally associated with these entities. This can be
formalised by introducing the concept of an *interpretation*. This is
simply a mapping I from run time object instances to entities in the
problem space.
Clarification 1: objects abstract entities from /some/ problem space. Complex applications typically abstract for multiple problem spaces, including the computing space for OOD/P.
Clarification 2: It is not an interpretation. It is a rule that objects must have unique identity. It is also a rule that identity, however it is represented, must be unambiguously traceable: problem space entity -> object abstraction -> run-time instance. However, that doesn't mean that identity must be represented the same way for each; it just has to be unique for each one and traceable between them.
Clarification 3: What is a matter of interpretation is what constitutes an identifiable problem space entity. Basically what that comes down to is that a non-developer domain expert would agree that the entity is known and identifiable in some way. But this is a methodological issue. That is, reviewers of UML OOA/D models are very rarely confused about what the model semantics are; their issues are about whether the authors view of the problem space is correct.
Now it is important that two run time object instances are not mapped
under the interpretation to the same entity in the problem space. In
other words, I must be 1-1. This can be written as
I(x) = I(y) => x = y
It is important to understand that the definition of 1-1 is tied to the
assumed domain of the function I. Making the domain smaller helps to
make an interpretation 1-1.
The only way to allow a single process to model an external entity in
more than one way is to divide the total system into sub-systems, each
with its own independent interpretation mapping. Each such sub-system
is said to work at a single, self-consistent "level of abstraction".
I mentioned subsystems because it happens to be a convenient way to introduce the notion of scope. That allows one to abstract the same entity differently in different scope so that the multiple abstractions can't cause confusion. One can do the same thing with layers. Though rarely done for other reasons, one even can do the same thing within object implementations. And in you code example you show yet another means of defining scope below.
The key idea is just that only one abstraction for a given entity is visible within a particular scope. So long as they are in different scope, one can have as many abstractions for a given problem space entity as one wants.
---- Section 3: Why is it a misconception?
This is demonstrated with the following code
class Employee
{
public:
string GetName() const { return name; }
void SetName(string newName) { name = newName; }
float GetSalary() const { return salary; }
void SetSalary(float newSalary) { salary = newSalary; }
private:
string name;
float salary;
};
void foo()
{
Employee* e = new Employee;
e->SetName("Albert Einstein");
e->SetSalary(25000);
e->SetName("Kurt Godel");
e->SetSalary(29000);
delete e;
}
This is a good example of the difference between object and instance. What you have is two objects but only one instance. The trick is that only one object is instantiated at a time. The Einstein object's instance ceases to exist when the Godel object's instance is initialized just as surely as if one had written:
void foo()
{
Employee* e = new Employee;
e->SetName("Albert Einstein");
e->SetSalary(25000);
delete e;
Employee* e = new Employee
e->SetName("Kurt Godel");
e->SetSalary(29000);
delete e;
}
[In part the OOPL is confusing things by allowing the object to be instantiated without proper initialization of identity. (One could not do that in any of the abstract action languages used for OOA/D that I know of.) In part the OOPL is confusing things by allowing an optimization by reusing the memory for the object without the overhead of heap operations. IOW, the OOPL designer is offering the developer an opportunity for foot-shooting by washing his hands of referential integrity issues and pushing them all on the developer. This is why I argued that looking at OOPL code is not a good place to learn OO.]
The identity of the Einstein object is "Albert Einstein" and the identity of the Godel object is "Kurt Godel". The attributes of those abstractions are defined to depend on that identity. The identity of the Einstein instance is the address of 'e', as is the identity of the Godel instance. That's fine so long as they do not both exist at the same time in the same scope. What the language has done is to butcher the notion of scope and make it the developer's responsibility. That is, the developer is going to be solely responsible to ensure nobody tries to access the Einstein instance outside the <artificial> scope of pairs of initializers.
That is a particularly nasty problem in a language where most relationships are instantiated with address pointers. Now when instantiating relationships one has a potential nightmare for referential integrity. But those problems largely evaporate if one writes the code as I did and creates a separate heap instance with a unique address for each object. That's because scope is terminated explicitly at the delete rather than implicitly at some other object's initializer.
This code is not intended to be an illustration of good design. That
is not its purpose!
It is generally assumed that when an object is created it has identity,
and it keeps that identity until it is destroyed. It is *not*
allowable for an object to change its identity over time. It can only
change its attributes. This allows pointer comparisons to be used for
object identity tests.
The objects' identities -- Einstein and Godel -- don't change in your example. And an instance of both objects has a unique identity at any given time by virtue of the fact that they do not coexist. The OOPL allows the mapping of object identity to instance identity to be ambiguous for purposes of relationship instantiation, but that is really a deficiency in the OOPL to allow the instance identity (address) to be reused for different objects anyway. Even then, technically the language defines what happens when the instance is re-initialized so the referential integrity problem (resolving the relationship ambiguity in all cases) is just moved to the developer's shoulders rather than being enforced in the language.
That is clearly in conflict with the "misconception" that was defined
in section 2. I am of course assuming that the interpretation map
makes use of the 'name' member of an Employee instance. Under this
interpretation, the definition of object identity changes from one call
to the next in function foo() above.
This poor definition of object identity makes it impossible for an
object to provide a Clone() method, such as
Employee* Employee::Clone() const
{
Employee* e = new Employee;
e->name = name;
e->salary = salary;
return e;
}
The reason is that under the interpretation the clone would map to the
same entity (in the problem space), in conflict with the assumption
that the interpretation is 1-1.
This is a different problem. A true clone function creates different instances with unique identity (address) but the instances all map to the same object abstraction Employee{name,...}. This creates an even nastier set of problems for referential integrity for relationships when one changes the salary. The solution here is to break the thumbs of any developer who does something like this.
*************
There is nothing wrong with me that could
not be cured by a capful of Drano.
H. S. Lahman
hsl@xxxxxxxxxxxxxxxxx
Pathfinder Solutions -- Put MDA to Work
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
Pathfinder is hiring: http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH
.
- Follow-Ups:
- Re: Object identity
- From: David Barrett-Lennard
- Re: Object identity
- References:
- Object identity
- From: David Barrett-Lennard
- Object identity
- Prev by Date: In book,Use case diagram is static or dynamic view? (for UML)
- Next by Date: Re: In book,Use case diagram is static or dynamic view? (for UML)
- Previous by thread: Re: Object identity
- Next by thread: Re: Object identity
- Index(es):
Relevant Pages
|