• Aucun résultat trouvé

FIGURE 2.13 Characteristics

Dans le document Object-Oriented (Page 71-76)

The T&M Object Metamodel

FIGURE 2.13 Characteristics

of values and objects.

Yet another difference is that a value is immutable or invariable.

Though you can calculate and relate values to other values, they won’t change.

Values can be named. The value of a name or an identifier (of an “unknown quantity”) cannot yet be calculated or can be undefined. The same name can be bound to another value, depending on the context. For example, when looking at the equation 40x42; pi3.14, the idea that adding x would change the value of the number 40to 42is wrong. Also, xis not a variable, but has a calculable value. We can call the number 3.14by the name piand use the same name to bind it to the value 3.1415in another context.

In contrast, an object can change over time, that is, its state can change without losing its identity. And this identity does not have to be linked to a specific name. For example, you can edit an application form that you created yesterday and sign it tomorrow. You could change the form’s name from “New application”

to “Edited application” without risking that it might lose its identity.

Yet another difference relates to how you can use values and objects.

Considering that a value has no identify and no location, and that it is invariable, it would be hard to build communication and cooperation on the basis of values alone, because values cannot be exchanged or edited. In situations where you have to communicate and cooperate on the basis of values, you often use a specific value to “build” an identity. For example, an abstract value of $500 won’t be of much use in the banking business. It will become useful only if it is connected with an account, and if this account is seen in its temporal change. Only then can you use that value for cooperative work. For instance, to build an account in a value-based database, you can use the account number for unique identification of all other values related to this account.

In contrast, objects can be used jointly, if you can access them by references.

Then they can be known by different names in different locations, and you can use them as a common work object. Unfortunately, there is an alias problem to be solved: An object can be changed in one context without another context taking notice of that change. For example, a form can be accessed by identifiers on two different electronic desktops. This means that two employees can use it for cooperative work and coordinate their work through this form. Problems will arise when one employee does not see that the other employee changed the form without prior agreement to do so.

2.6.3 Using Values

When we think of using values, we probably first think of mathematics or engineering, where numerical analysis is of prime interest. For example, mathematical problems are solved by operations on numbers, a form of values. However, in our everyday lives, val-ues and numbers have a much broader meaning. We use them to identify, characterize, count, or order things and eventually to represent them as measurable entities.

We basically always use values when we model abstract entities and do not want to be distracted by concrete and objective characteristics. In doing this, we also abstract from the context of the thing represented by a value. In this sense, the authors of a popular textbook, Richard Bird and Philip Wadler, discussed functional programming

Using values

as follows: “Somewhere, in outer space perhaps, one can imagine a universe of abstract values, but on earth they can only be recognized and manipulated by their representations. There are many representations for one and the same value” (p. 5).

What does this mean? It probably means that we always need values and numbers when we have to calculate or order things. There is no doubt that we then need inte-gers or real numbers, as well as currency values or periods of time. Even when we try to represent measurable parameters, ignoring the concrete circumstances of an object, values like bank codes or the current Dow Jones index are certainly useful values.

2.6.4 Context: Values and Objects in Programming Languages

Many object-oriented languages support both value and object concepts. The differ-ence between these concepts is normally implicit and hardly discussed explicitly. The conceptual separation is least clear in a language like Smalltalk. When talking about values, it is important to understand that a truly smooth transfer of the abstract con-cept of values to programming languages was successful only in purely functional lan-guages, such as Miranda or Hope. These languages let us write value-oriented program code; for example:

They use expressions that are almost algebraic, consisting of functions.

Functions have no side effects, so that they are similar to the concept of algebraic expressions.

They use mathematical variables. A variable is a name for a known or yet unknown value (as in “an equation in two unknowns”), but this value cannot change.

The idea behind functional languages is referential transparency.

Referential transparency means that an expression can be fully understood on the basis of its partial expressions.

Each partial expression (subexpression) is independent of its context.

A variable is a name for a (known or unknown) immutable value.

Object-oriented programming languages suggest a totally different programming model.

They use objects that encapsulate an internal state, which can only be changed through permissible operations.

They use an imperative variable concept. A variable is an identifier for a memory location or container, the state (or value) of which can be changed through assignment.

Each expression depends on its context, that is, on the state of all participating objects. An object can be known by different names in different contexts, so that changing the parts of an expression will normally lead to side-effects.

A closer look at values in object-oriented programming languages shows that many languages use values as so-called primitive types, such as integers, floating point num-bers, or booleans. These value types behave as we would expect from values or numbers (apart from precision errors caused by representing them on a finite computer).

Some “puristic” languages—like Java, Eiffel, or Smalltalk—embed these value types in the normal class concept. However, such embedding can be problematic, because Values in the

object metamodel

certain properties of objects cannot simply be transferred onto “value objects.” For exam-ple, arithmetic expressions would lose their mathematical semantics if an operation would change object 3to an internal value 4. This is why we find it confusing when text-books, such as the Smalltalk handbook of Adele Goldberg and David Robson, use num-ber arithmetics as one of their primary examples for objects and their operations. We want to have numbers that behave like values, and objects that have all object properties.

2.6.5 Definition: Domain Values

The primitive built-in value types of an object-oriented programming language are easy to use. A problem can normally occur when you try to introduce user-defined value types. We refer to these values as domain values, because they are motivated by the application domain of a system.

A domain value is a user-defined value. It represents values from the application domain.

A domain value type is a data type with a defined set of values and defined operations. Its internal representation of values is hidden.

Object-oriented languages define domain value types as classes. It is important to understand that the instances of a domain value type always have value semantics, that is, once you set a value, you can’t change it.

The motivation for domain values is obvious. Language developers have tried to supply such data types, specific to an application domain, since the development of early programming languages. The only difference is that it was not as obvious as it is today, because most early applications were oriented to number-crunching tasks.

2.6.6 T&M Design: Domain Values

Domain values are of prime importance in the T&M approach. When we say we want to use classes and objects to model the concepts and things of our application domain, then this also applies to the values that play a role in that application domain.

Let’s look at the idea of domain values versus conventional programming in our bank example. Assume that we have accounts with account numbers. In an object-oriented application system, a specific account is an instance of the class Account. The account number in this object should be a domain value of the type AccountNumber.

The appropriate attribute would have an identifier, AccountNumber.

In conventional programming, we would also have an attribute called AccountNumber, but declare it as an attribute of the type integer. The fact that it represents an account number can be seen only in the identifier AccountNumber.

2.6.7 Implementing Domain Values

In object-oriented languages, we have to use the class construct to build user-defined domain values. This is because classes are the only way to add new types and instances of these types to the system. This appears to have several benefits:

In a user-defined class, you can specify the set of values that can be created as instances of a type. To do this, a class can take an external representation of the desired value and only create a domain value object when the representation can be trans-ferred into a valid (well-formed) value.

The Bank example

In this connection, we could implement further concepts, such as adding a so-called

“undefined” (bottom) value and other special values to the set of valid values. The ben-efit is that you can distinguish explicitly between defined and special values, as suggested by Ward Cunningham. For example, many developers would use a workaround like 999 for a yet-unknown account number they have to represent as an integer. This means that, by convention, they turned a defined value of type integer into a special undefined value. Problems occur in programs that do not observe this convention; the above method would cause serious domain errors that such a program would not catch. To avoid this problem, you must not handle domain values as a simple set of values.

We have known since the seminal work of Tony Hoare that typing should include not only the defined set of values, but also the operations permissible on values of that type. Although this had been hard to implement for user-defined types in classic imper-ative languages, we actually get this option “for free” in object-oriented languages.

For example, we can think of permissible operations on values of the type AccountNumber. This is not as trivial as it may sound, because our account num-bers should allow addition as well as relational operations. The reason is that the sum of account numbers is normally transmitted as a checksum in batch money transfers between banks. In addition, some banks add additional information to an account number. For example, you can derive the customer number or the type of account from an account number. All of these are permissible operations of the type.

Together with the introduction of special values, you can also define appropriate semantics for handling these values. In our bank example, an attempt to add an unde-fined account number to a “normal” number could lead to an exception.

On the other hand, implementing domain value types as classes has some drawbacks.

To avoid a serious trap we have to take care that values belonging to domain value classes are always handled by value semantics rather than by reference semantics. This means that a domain value object must not be accessible for modification over two identifiers. More specifically, a domain value object should not be modifiable at all.

This is the only way to maintain the referential transparency of the values we require.

Some of the proposed solutions will be discussed in Section 8.10. In summary, we have compiled the following different techniques for building domain values:

Domain values are instances of “normal” classes. Domain value objects are always passed as copies. This is an insecure programming convention.

Domain values are built from classes allowing one single value-setting operation, while otherwise offering only probing operations. This uses a lot of memory.

Refined techniques to build value objects are known from the literature by the name of body/handle (see James Coplien).

A pattern that implements value objects with minimum space requirements is the Flyweight pattern of Gamma et al.

2 . 7 M E TA O B J E C T P R O T O C O L S 2.7.1 Introduction

When developing interactive programs, we often observe that it is not sufficient to write program code to implement domain concepts or objects. We additionally have to be able Operations on

values subjects

The Bank example

Building domain values

to handle the elements of our program, that is, we have to be able to query and modify properties of objects and classes in our program. How important this meta-information really is becomes clear when we work with components. We have to rely on components giving us information about their interfaces and other properties, because such program code is normally inaccessible. This section discusses such meta-information. It is aimed at the more advanced reader because using or even designing metaobject protocols is not an everyday task. But when dveloping programming tools or components, you should understand the concepts and means of this type of meta-programming.

2.7.2 Motivation for a Metaobject Protocol

Simply speaking, we have used objects in object-oriented application development to model the concepts and things of a real-world application domain. Now let’s have a look at software engineering as a potential application domain. We normally do this when building programming tools or other software development tools. If software engineer-ing is our application domain, then there is nothengineer-ing that would deter us from selectengineer-ing an object-oriented program as our object of modeling. To work with this object, we need a metaobject protocol, which should sound familiar to Smalltalk programmers. The fol-lowing section explains what a metaobject protocol is all about. Figure 2.14 shows a schematic view of modeling an application domain versus modeling a software program.

2.7.3 Definition: Metaobject Protocol (MOP)

A metaobject protocol (MOP) is based on the constructs of the programming language you use to write your program. These constructs themselves can be modeled as objects. Such objects are called metaobjects. Like all objects, metaobjects are instances of classes, only we call them metaclasses. The set of interfaces of these metaclasses form a metaobject protocol.

Metaobjects can be classified in two categories:

1. Objects representing the (static) application model (e.g., which operations does an object offer).

2. Objects representing the runtime system (e.g., how an operation is executed;

how an object accesses its attributes).

The organization of metaclasses and the behavior of metaobjects are described in a metalevel architecture. Metalevel architectures can be used for many different

executable program with MOP

meta constructs application domain

model of the application

domain

program model of the

program

executable program

FIGURE 2.14

Dans le document Object-Oriented (Page 71-76)