May
2004 Issue: 32
Journal of Conceptual Modeling
www.inconcept.com/jcm
The Message Paradigm in Object-Oriented Analysis
By Dr Manuj Darbari and Dr. Vipin Saxena
Abstract. The message paradigm is one of the most specific concepts of object orientation. This paradigm works well as long as one object is involved. When more than one object is involved, a choice has to be made with which type the message will be associated. In our opinion, this choice has to be postponed during object-oriented analysis. We propose to extend the concept of the message paradigm to messages with more than one implicit argument. Postponing the choice results in one model for one reality. Another problem rises when no object is involved. In our opinion this issue can best be tackled by introducing a domain layer and a functionality layer.
Introduction
Object-oriented software development is now generally accepted as the most promising approach for the construction of complex software systems. As for other areas of engineering, the development of a software system is split into a number of activities, namely analysis, design, implementation and verification or testing. The development of a software system is considered to be an incremental process.
The major purpose of object-oriented analysis is to establish the requirements for the software system to be developed. In view of the object-oriented paradigm, a conceptual model of relevant objects is developed including a specification of their characteristics and their behaviour. The conceptual model is also referred to as the business model or domain model of the external world. This model describes the problem context in all its facets. The model will therefore be as close as possible to the facts, as they can be observed in the external world. We are using UML and OCL as modelling technique in this paper [12][13].
Object-oriented analysis is a relative young research area and its concepts are, derived from object-oriented programming. This can explain why many conceptual models are oriented towards system implementation and a lot of design decisions are already taken. As a result, the border between object-oriented analysis and design is vague. We are convinced that we have to rethink and extend object-oriented concepts used at the level of analysis in order to add a surplus value.
It's a very blind assumption that techniques that are convenient in some object- oriented programming languages are valid also for analysis.
During object-oriented design we transform the conceptual model into an operational model. Software quality factors will dominate the transformation. In the design phase we describe how a conceptual model can be implemented In terms or software. Any decision that adds nothing new to the conceptual model or the observed world is a design decision.
One of the most specific concepts in object orientation, aside inheritance, is that one can send messages to an object. This principle is known as the message paradigm. The receiving object is the sole responsible for -responding to the message. This message has access to the characteristics of the object. In order to respond to a message, a proper method will be selected. The receiving object may appeal to other objects by sending them messages in turn. The receiving object is the implicit argument for the underlying method. The message paradigm forces the software engineer to associate a message with a type. This leads to a more consistent structure of the software system.
The message paradigm in object-oriented analysis works well as long as one object is involved. Problems arise when none or more than one object is involved in a message. These topics are described in the following sections.
Messages with One and with More than One Object Involved
As
an introduction we briefly discuss messages with one object involved. As an
example consider figure 1. If we want to know the total amount of money we can
withdraw from a specific account, we send the message “moneyToWithdraw()” to
this account
context Account inv:
sufficientBalance()
context Account: : sufficientBalance (): Boolean
post: result = getBalance() >= getLimit()
context Account : : getBalance() : Integer
post : result = self.transaction.getAmount()®
sum
context
Acccount : : moneyToWithdraw() : Integer
post : result = getBalance() – getLimit()
Fig. 1. A message with one implicit argument
This message in turn will send the message “getBalance()” to the same account. The getBalance() sends the message “getAmount()” to all the transactions linked to this account. For each of these messages only one object is involved.
The message paradigm simulates the way people interact with all kinds of things in their surroundings. When turning on a television, a signal (message) is sent by means of a remote control. In responding, the television will sent proper messages to some of its components. It is a natural way of communicating.
Aside the natural way of communication the message paradigm permits us also to encapsulate the characteristics of objects of a class. Encapsulation is again a faithful reproduction of the way human beings deal with objects in their surrounding. When driving a car or watching television, internal details are completely irrelevant for a model user. Technicians and more advanced users need more information, resulting in a gradual presentation of internal details.
When
more than one object is involved in a message, the question rises with which
type we will associate the message. Consider the example in figure 2. We want to
model a message returning the total balance of all the accounts of a specific
person at a specific bank. The message "totalBalance()" could be attached to the
type Person or to the type Bank. The answer to the above question will be rather
arbitrary. Also looking at the different specification of the postconditions
will not help: the specifications are each other's mirror image.

context Person : : totalBalance(bank:Bank) : Integer
post: let accounts =
self.account®select(account
| account.bank = bank) in
result = accounts.getBalance()-+sum
context Bank : : totalBalance(person: person) : Integer
post: let accounts =
self.account®select(account
| account.person = person) in
result = accounts.getBalance()-+sum
Fig. 2. A message with one implicit argument and one explicit argument
In this case two solutions are possible, modelling the same external world. In analysis we strive at only one model for the same reality. In our opinion, the decision to which type a message with more than one object involved belongs, adds nothing new to our model about the facts in the external world. This decision is clearly a design decision and must not be taken during object-oriented analysis.
For that reason we propose to introduce messages with more than one implicit argument. We call these messages binary or more general binary messages. These messages have access to the characteristics of the implicit arguments. Binary messages in conceptual models are illustrated for the bank case in figure 3. As a result we have only one possible model for the requirements of the domain.
Graphically these kinds of messages are modelled in all context types adding the other types before the name of the message. Remember that in UML the returning value is given at the end of the message.
Instead
of one context type, we now have two context types. The implicit arguments are
referenced by "self" followed by the name of the type. If more than one object
of the same type is involved the implicit arguments are numerated with
self1Type, self2Type and so on. If no other classes are involved we could
abbreviate to self1, self2 and so on. When calling the message the involved
objects are separated through a comma.

context Bank, Person : : totalBalance() : Integer
post :
result = selfBank.account
®
intersection (selfPerson.account).
getBalance()®
sum
-- intersection could also be interpreted as a message with
two - - implicit arguments
-- result =
selfBank.account, selfPerson.account.intersection().
-- getBalance ()®
sum
Fig.3. A message with more than one implicit argument
More important is that also the specification for the postcondition is changed. Instead of starting with one object and navigating through the model, the postcondition in figure 3 has two starting objects. This way of modelling is more declarative and abstract in the sense that it doesn't suggest an implementation strategy.
Notice that also the intersection could be interpreted as a message with two implicit arguments. This specification is worked out in the comment. The specifications in figure 2 and figure 3 could be interchanged, in our opinion however the specifications in figure 3 reveal better "the way of thinking".
A typical application of this concept is the linking of two or more objects. Consider the relationship among persons and cars. How should the acquisition of a car by a given person be reflected in term of messages? Should there be a message applicable to a person, to a car or both? When using n-ary messages the answer is already given.
One could argue that we don't have to make this choice if we use a characteristic instead of an object as an argument. In our example one could have associated a message totaIBalance(nameOfTheBank:String) to the type Person, assuming that the name of the bank is unique. In the next section the answer is given why this is not a valid option.
3 Messages with No Objects Involved
Another
problem with the message paradigm arises when no specific object is involved.
This is the case when an object or a set of objects has to be searched among a
collection of objects based on a certain characteristic. This is also the case
when new objects have to be created. For that purpose class-scoped operations
are introduced in UML. These kinds of operations are underlined. Two examples
are illustrated in figure 4. The name of the bank is assumed to be unique for
each bank. This is not formally modelled.

context Bank : : getBank (name : String) : Bank
post: result =
AllInstances ®
select (bank | bank.getName () = name)
Context Bank : : getBank (rating : String) : set of Bank
post : result =
AllInstances
®
select (bank | bank.getRating () = rating
Fig.4. Class-scoped operations
A problem with class-scoped operations is that they easily could be misused: object-scoped operations could be modelled as class-scoped operations. This is frequently observed in practice. The use of class-scoped operations could, in an extreme way, lead to functional decomposition or structured design. In functional decomposition the ystem function is organised as a hierarchy of functional procedures, and the development consists of elaborating this hierarchy from the top downwards [9].
As
an example consider figure 5. We have modelled our object-scoped operation
totalBalance() of section 2 as a class-scoped operation. The two explicit
arguments are objects, they could be replaced by characteristics identifying the
person and the bank.
context Account : : totalBalance (person: Person, bank : Bank) : Integer
post: result = AllInstances®
select (account | account.person =
person and account.bank = bank) .balance
®
sum
Fig. 5. TotalBalance() as a class-scoped operation
Another, more object-oriented way to select objects is to introduce a new type. In our banking example, one could introduce the type "BankAssociation". A bank is then always linked with one bankassociation. The messages for selecting banks are associated with this new type. Consider as an example figure 6. This approach also has a lot of disadvantages:
The first is that we introduce an artificial type not belonging to the domain context. In fact the only reason why we introduce this type is that it permits us to model a message for the selection of objects. This is a technical reason. In our opinion only types that play an important role in the domain context of our system must to be modelled.
Further we assume that there is only one bankassociation object. Only then is it possible to select all the banks with a specific characteristic. We also postpone our problem. How could we select our bankassociation object? By introducing a new type? Or by introducing a class-scoped operation "getBankAssociation()"?
If we adopt this approach we have to introduce new singleton types for every type without an existential dependency constraint. In our problem we had to introduce a new artificial type for messages selecting persons.
A next problem is that. if we want to select objects of types with an existential dependency constraint we may have to make a choice between more than one type to attach this kind of messages. In our example, if we want to select accounts on creation date we could use the type Bank or the type Person for it. The choice is rather arbitrary in object-oriented analysis.
A last problem is that this approach leads to long navigation expressions. Suppose we want to select all transactions on accounts for a certain date. We could attach this message to the type "BankAssociation" From bankassociation we are navigating to all the banks, and from there to all the accounts and at last to all the transactions on accounts.
In
our point of view the two important tasks of our conceptual model, working on
sets, containing all objects of a specific type and working on objects, have to
be separated into two layers: a domain layer and a functionality layer.

context BankAssociation : : getBank(name: String) : Bank
post : result = self.bank
®
select (getName() = name)
context BankAssociation : : getBank(rating : String) : set of Bank
post : result = self.bank®select(getRating()
= rating)
Fig.6. Introducing a new type for selecting objects
The functionality layer, which works on sets of objects, has several responsibilities: operations on sets of objects, like the conversion of characteristics in involved objects or counting the number of elements in a set, the selection of the right accessible messages of the domain layer to be send to the involved objects and operations on basic types converting the input or output. The basic types in OCL are Integer, Real, String and Boolean. In the domain layer, which works with objects, most of the relevant facts about the real world are modelled.
Consider our example in figure 7. We assume that the name of the bank is a unique characteristic and that we can select one person on the basis of his name and address. These uniqueness constraints are not modelled. The main task of the functionality layer in our example is the selection of the tight person and bank and sending the right message, totalBalance(), to these two involved objects.
The functionality layer is built as a set of input and output services, offering the desired information functionality to the users of the model. In this sense we see the functionality layer as a more formal approach of use cases [14]. We could use the functionality layer as a way to control whether all the necessary domain knowledge and all user requirements have been modelled.
By separating functional requirements and domain knowledge we are able to focus in a first phase on our domain layer. Users tend to mix these specifications, together with technical requirements. Like Jackson we are convinced that a great part of the complexity of a system is caused by the complexity of the real world [9]. Jackson suggests first modeling reality and in a later step considering functionality. We agree on this, from a theoretical point of view. In practice this process will be iterative.
The functionality layer may send accessible messages of the domain layer. The domain layer has no access to the functionality layer. In this way we want to stimulate maintainability of our model. We consider the domain layer as more stable as the functionality layer. Types that exist in the domain layer are quite stable. The functional requirements tend to change more often. This ensures that modifications in the functionality layer have no or little effect on the domain layer. Technically this means that we can only use the OCL-expression AllInstances in the functionality layer.
We explicitly haven't modelled the messages of the functionality layer as part of one or more types to underline that this layer has other responsibilities than the domain layer. Further research has to be done on how to structure the messages of this layer.
One could argue that even with these two layers it is possible to model the message totalBalance() as in figure 5. This is true, but the idea is to work as early as possible with objects and to send as soon as possible accessible messages of the domain layer to these objects. So when respecting these rules this way of modelling is not an option anymore.
One could argue that we don't need this functionality layer. We could agree with this argument to a certain extent but never the less we are convinced that we better model our domain layer not only on the basis of facts about the real world but with the combined knowledge of the real world and the knowledge of the functional requirements. It makes no sense to model reality without having any functionality in mind. We strive for formalisation of this functionality.
As an example consider that we could model a mutator as a type. The functional layer helps us to decide how to model it. Also the decision on which types, message, characteristics, constraints, ...are relevant is influenced by the functional layer. We already described that we use the functional layer as away to control completeness of the domain layer.
One could argue that using and defining characteristics as key attributes has to be done at the design phase. In fact this has nothing to do with the uniqueness or non- uniqueness of a characteristic. On the functionality layer one could also select a set of involved objects. In our example we could have selected a set of banks by the rating characteristic modelling not the totalBalance() of one specific person by one specific bank but by a specific set of banks.

personExists (name : String, address: String) : Boolean
post : result = getPerson(name, address)
®
size = 1
getPerson (name : String, address: String) : set of Person
post : result = Person.AllInstances
®
select(getName() = name and
getAddress() = address)
bankExists (name : String ) : Boolean
post : result = getBank(name)
®
size = 1
getBank(name: String) : set of Bank
post: result = Bank.AllInstances
®select(getName()
= name)
totalBalance(namePerson : String, address : String, nameBank : String) :
Integer
pre: personExists(namePerson, address)
BankExists(nameBank)
post:
let
person = getPerson(namePerson, address)
bak = getBank(nameBank)
in
result = person, bank.totalBalance()
Fig.7. Modelling with the functionality layer and domain layer
One could argue that instead of modelling a functional layer, we could have modelled this by a type user, in our case, for example the fiscal authority. In other words there is always a context for a message. Every message of the functional layer is attached to this type. The advantages are that we don’t use another concept and we don’t have problems anymore modelling the class-scoped constraints. So a constraint about the average rating of all banks is associated with the type FiscalAuthority. The singleton constraint for the type User could be modelled as object-scoped6. The disadvantages are that this type is still, in our view, artificial. Every person and bank is linked to the fiscal authority. In reality this is not the case. A more fundamental disadvantage is that all of the messages of the functional layer are associated with this type. This type is a receptacle of different kinds of messages without structure. This is certainly true if more types without existence dependency constraint are added to the model.
The link with the user is made by this user type, without explicitly specifying this. Also the responsibilities for this user type and the other types are not clear. It is just a type like another. The disadvantages mentioned by figure 6 are here still valid: long navigations and choice in navigation.
We underline that not the notation, in our case a rectangle or an oval, is important but the method, the segregation of responsibilities in hierarchical layers and the intention to further structure the functional layer.
4 Conclusion
In traditional object-oriented analysis one has to make a choice as to which object will be the implicit argument and which object(s) will be the explicit argument(s) when more than one object is involved in a message. This choice is an arbitrary one during object-oriented analysis. By making all the involved objects implicit arguments we can postpone this decision. This results in one model for one reality. The specification of the message is also changed: instead of writing the specification starting from one point. we write the specification in view of more than one starting point. This leads to specifications with a more intuitive character.
By introducing a functional layer we bridge the gap between the domain layer and the user. The main responsibilities of the functional layer are the selection of the involved objects and messages and the preparation of the input or output for the user. The functional layer is helping the analyst to control the completeness of the domain layer and the user requirements.
Segregation of responsibilities leads to a large degree of independence between the two layers. The formal specification of the functionality layer, in contrast with use cases, makes in combination with the domain layer, rigorous and tool-based verification possible. The conceptual model is not only structured by its types but also hierarchical structured by its layers. This should improve maintainability, especially for larger systems.
Further Research
When combining inheritance, the other fundamental concept in object orientation, and n-ary messages ambiguity is possible. Consider the figure below. Two binary messages m() with different contexts are modelled. If we send the message m() to the involved objects a1 of type A1 and bl of type B1 the selection of one of the binary messages is arbitrarily. Some possible solutions are proposed here. The simplest one is to forbid ambiguity. Another one could be the obligation to introduce a binary message m() with contexts A1 and B1. A more complex one is to combine the postconditions of both messages through the logical operator AND.

context A, B1 :: m()
…context A1, B: : m()
Fig.8. Combining inheritance and n-ary messages
Further research has to be done on how to structure the messages in the functionality layer. A possible way is to group messages that are using the same set of all objects of a type. Another interesting question to be resolved is: is it desirable to have sets of objects as implicit arguments? We think that it isn't, because it's in our view another way of modelling static messages.
A strict separation of responsibilities between the two layers is needed. Although we already draw a strict line between the two layers some issues are still open. Class- scoped constraints are an example of such an issue. Another one is how far we could go in transformation, or conversion of objects in the functional layer.
As an example consider as input for the model the number of an account. For this account we want to know the totalBalance() of the owner of this account by the bank of this account. Two solutions are possible: either we query the person and the bank of this account and then send the already modelled binary message totalBalance() to person and bank or, we model a new objectmessage totalBalance() with as context the type Account.
References
[1] BODART F., PIGNEUR Y., Conception assistée des systèmes d'information, 1989, Masson, 302 p.
[2] BOOCH G., Object-Oriented Analysis and Design, 1994, The Benjamin/Cummings Publishing Company, 589 p.
[3] COOK S., DANIELS J., Designing Object Systems: Let's get formal, 1994. The Journal of Object Oriented Programming, Vol. 7, p. 22- 24.
[4] D'SOUZA D., WILLS A., Catalysis Book, 1998,684 p.
[5] ERIKSSON H.E., PENKER M., Business Modelling with UML, 2000, Wiley Computer Publishing, 459 p.
[6] FOWLER M., SCOTT K., UML Distilled, Applying the Standard Object Modeling Language, 1997, Addison-Wesley, 179 p.
[7] FOWLER M., Analysis Patterns, 1997, Addison-Wesley, 357 p.
[8] RUMBAUGH J., Object-Oriented Modeling and Design, 1991, Prentice Hall, 500 p. [9] JACKSON M., System Development, 1983, Prentice Hall, 418 p.
[10] SNOECK M., DEDENE G., VERHELST M., DEPUYDT A., Object-Oriented Enterprise Modelling with Merode, 1999, Unversitaire Pers Leuven. 227 blz.
[11] STEEGMANS, E., LEWI, J., DE BACKER, S., DOCKX, J., SWENNEN, B., AND VAN BAELEN, S., EROOS Reference Manual Version 1.1, Department of Computer Science, K.U.Leuven, Leuven, B, 1995, 173 p.
[12] OBJECT MANAGEMENT GROUP, Unified Modeling Language Specification, 1999. 808p.
[13] WARMER J., KLEPPE A., The Object Constraint Language, Precise Modeling with UML, 1999, Addison-Wesley, 112 p.
[14] WARMER J., KLEPPE A., Praktisch UML, 1999, Addison-Wesley, 252 p.
![]()
© Copyright, 1998-2004 InConcept (Information Conceptual Modeling, Inc.) All Rights Reserved. Privacy Statement. ISSN: 1533-3825