Value Object Hypotheses

Here are some properties I have been considering for the notion of a class of ValueObjects:

ValueObjectsShouldBeImmutable, therefore ValueObjects should have:

Also: Do these ideas make sense to you?

Are these hypotheses plausible? (Do you know of practical examples of ValueObjects that break any of these hypotheses?)

Comments welcome. -- some guy


The nature of things represented by ValueObjects

In addition to the above and what was mentioned in ValueObject, I find that ValueObjects often represent instances of mental abstractions rather than entities in physical reality.

Since any description that we make is finite, abstractions can be completely represented as ValueObjects. On the other hand, when we represent things in the physical world, the number of observations that can be made is theoretically infinite and all of our models are partial. The fact that nothing is immutable in the physical world, leads to the idea that representations of physical things are best handled by ReferenceObjects. I also notice that things in the physical world can always have their identities distinguished by more observation, so state is not sufficient to determine identity. -- MichaelFeathers

It strikes me that the real distinction concerns time:

ReferenceObjects change over time - they participate in a dynamic process, and that ValueObjects have the same state value throughout the lifetime of the system. (Hence the fact that equality of state is used when comparing ValueObjects, rather than unique identity.)

What I've read here has been really useful so far, anymore examples of ValueObjects referring to ReferenceObjects anyone? -- some guy

Yes. And it is kind of interesting that all physical things warmer than zero Kelvin change. Here is a neat idea. If there were no state changes in the world, could there be a concept of time? It seems that change and time are codependent concepts. -- MichaelFeathers (doesn't know why he thinks about this stuff)

The Situation Calculus, invented in 1969 or so, relies on just this notion. Actions are represented as functions that map situations to other situations. John McCarthys? web page (accessible from www-formal.stanford.edu) contains the seminal papers. -- WilliamGrosso

Steven Hawkins' A Brief History Of Time concludes with an explanation of why we perceive time as moving forwards, based on the second law of thermodynamics (as far as i can recall -- I'm not a physicist so feel free to correct this). I found it very convincing but then again, what do I know? :-) -- Anon.

See? Someone else thought of it. This thinking stuff does me no good at all. -- mf


Stuff moved to CanValueObjectsContainReferenceObjects


That's useful, because my hypotheses don't work, but it helps me describe that immutable property I'm trying to define.

2 strategies for making the Date example above consistent:

I think it's worth making a distinction between reference and composition here. (Thanks NatPryce.) ValueObjects shouldn't have an attribute which is a reference to a ReferenceObject, but they can contain a ReferenceObject, so long as that ReferenceObject is never divulged to another object (i.e. copies are returned by accessors and the ReferenceObject is private to the ValueObject.)

The hypotheses recast:

  1. ValueObjects should have an immutable interface
  2. The values of each attribute in a ValueObjectshould remain unchanged from the completion of its constructor to the last state of its existence. (i.e. immutability of all attributes is a ClassInvariant.)
  3. Methods in a ValueObject aren't idempotent (i.e. they are allowed to make changes to the overall system state)- they can instantiate new objects. (Particularly for return from accessors.)
  4. ValueObjects can contain attributes which are pure data values (or "primitives").
  5. ValueObjects should not contain attributes which are references to ReferenceObjects.
  6. ValueObjects can contain ReferenceObjects, thus making the entire state of the ReferenceObject immutable due to point 2 above. (Like instantiating a const object in c++.)
  7. ValueObjects may contain attributes which reference ValueObjects. (Hence these rules apply recursively.)
(The question of PhysicalState? and LogicalState? remains (which one does the above apply to?) - the physical state I think.)

[I'm embarrassed by the complexity of the above. I'll refactor it into something more understandable when I get time ;-)]

Any good examples or patterns where these rules wouldn't work? -- some guy

I would alter points 5 and 6 to be something like:

This allows a ValueObject's value to depend on the reference to or identity of a ReferenceObject, whether that identity is represented by the reference or by immutable members of the ReferenceObject.

How does that sound? -- NatPryce

Sounds fine in principle, but I think it'd be difficult to express "does not depend on any mutable state" in a model or diagram.(Still I'll think about using this approach.) Personally, I'd partition the ReferenceObject class into two classes, one immutable and another mutable. Trouble with that is that it causes class proliferation. -- some guy.

It seems to me that the definition can be reduced. Since ValueObjects have no identity and are immutable, there is no way that there could be a state dependency on a ReferenceObject. Further, if a ReferenceObject is fully encapsulated in a ValueObject and ValueObjects are immutable, the presence of the ReferenceObject would serve no purpose. But, I see what the intention is here. One could use a class whose instances are usually ReferenceObjects and place one of its instances in a ValueObject and it would be okay as long as the state is never allowed to change. But, in that case I'd say that we have a ValueObject holding a ValueObject (even though the contained object comes from a class that defines mutable objects). You could have a class with all manner of state modifying methods and instances could still be ValueObjects, if you make sure their state never changes.

IMO, classes don't determine ValueObject-ness or ReferenceObject-ness. The concept and the use does. -- MichaelFeathers

My crack at a set of rules: If we interpret ValueObjects strictly there is only one:

Since a ValueObject does not change, a ValueObjectshould never reference a ReferenceObject. However, the class of a ValueObject can provide keyed access to ReferenceObjects which are associated with a ValueObject.

Assume we have a date. There are many things that can happen on a particular date. If we allow a date instance X with value V (say 1/2/98) to hold reference to a list of events E that happen on that date, then we can easily create another instance of date Y with the same value V that does not have the same events E. When we ask what are the events that happen on date V, the answer should be the same regardless of which instance of date (with value V) that we ask.

So, in, say, C++, you can use all sorts of static data and methods on a ValueObject, but it must have immutable instance state.

Bear in mind, this is the strict strict interpretation. -- MichaelFeathers

What are we trying to get at here? We want to avoid aliasing problems by creating an object that can be freely passed around without having to worry about its state changing. But it's not really state changes that we care about, it is the results of messages. If the result of any message to one of these objects is always the same, then object A and object B can both refer to it safely, because nothing A does to the shared object can possibly affect B.

We can construct such immutable objects in any number of ways. The simplest is for the object to have no state. Then we are guaranteed that its responses to messages will always be the same. The next is to have state, but never to change an instance variable once the object has been constructed, and for each of the referenced objects to be immutable. But for the immutability of the referencing object to hold, it suffices that each of the referenced objects is immutable only from the perspective of the referencing object.

== in Smalltalk is an example of a message whose results never change. So, if an immutable object has an (unchanging) instance variable to whose contents it only ever sends ==, then it doesn't matter what sort of object occupies that variable, the referencing object is still immutable. (See "Semantics of ==" below)


More on ValueObjects and references

ValueObjects only access the immutable state of referenced ReferenceObjects The missing possibility is that you can refer to a ReferenceObject if you use only stable messages, like testing identity.

Can you elaborate on this please? I don't really know what you mean. -- some guy

Yes, the transaction log and KentBeck's timestamp are good examples of references to ReferenceObjects where the state of the ReferenceObject is not part of the state of the ValueObject that refers to it.

The identity of the ReferenceObject, however, is part of the state of the ValueObject. Presumably, once a timestamp object is created, the value of the posting date, the value of the effective date, and the identity of the business task would never change. But the state of the business task itself could change! -- KielHodges

This presents a strange difference between the timestamp example and the transaction log:

With the timestamp, the state of the reference object is irrelevant (i.e. the business task), but with the transaction log, the state of the customer is very relevant. For example, how would you list a transaction log by customer name when a log entity contains a reference to a customer that has been removed?

(This scenario with the accounting log is similar to printing out a listing of a Unix directory in which files are owned by users that have been removed... You get the old UID number, but no name - a dangling reference...)

What operations need to traverse the reference to the task from the timestamp?? - surely such operations can't depend on those aspects of the task which are affected by mutability? -- some guy

I typed this same comment in three times yesterday, but it mysteriously disappeared. Here goes again- the only messages sent from CSTime to its instance variable task are oid and isNil. These are stable for a Task, by which I mean the result never changes for a given instance of Task. So, the ValueObject is still a ValueObject. It never returns a different result from the same message. I checked with the ObjectExplorer? to be sure this was true. -- KentBeck

Here's another, slightly different, example of a value object referring to a reference object. An application I recently worked on had, as one of its tasks, to do the following: from a stream of radar data deduce what's going on in the battlespace.

We start with objects that don't have a notion of identity (but aren't really ValueObjects?): bits of radar data. They have state, but are definitely immutable. Basically, the attributes are things like time, location, speed, bearing, whether or not the observed thing was tracked, ....

The way you've described them, those sound *exactly* like ValueObjects.

Groups of these things get identified in the notion of vehicle, which is definitely a reference object (over time, as we learn more about the vehicle, we update our information about it. The most common thing we deduce are things like "type of vehicle" and "likely to need gas soon").

Now convoys are groups of vehicles that travel in a certain way. They have start times, stop times, start and stop locations, paths they travelled along, etcetera. They are immutable, represent a crystallized deduction (though not quite an instance of a mental abstraction), and are compared by attributes (since the inference algorithms can deduce "the same" convoy multiple times). Is a convoy a ValueObject?

Sounds like it. -- WilliamGrosso

I think convoys as you define them are ValueObjects. But I'd say the ultimate test is whether two, different convoy instances with exactly the same state are considered "the same" or "different". How would you overload operator== in C++ for convoy? that's the intuitive test I'd use. If unique identity of an instance is totally immaterial and only the state data is used to test equality, then a convoy is a ValueObject. -- some guy

I agree. It seems that the manner in which identity and instances relate conceptually is the key. -- MichaelFeathers


Immutable interface

I'm not sure what you mean about having an "immutable interface", please expand. -- RonJeffries

The interface specifies a list of methods (with signatures) that the class of objects agrees to implement. Invoking some methods will cause the object to change state, whilst other methods never cause the object to change state.

An immutable interface is one which provides only methods that explicitly guarantee not to change the state of the object providing the interface. (Immutable methods would be tagged "const" in C++. A const object in C++ can only accept a subset of all the method invocations defined by the class - the sublist of methods which are immutable.)

An example of a class with an immutable interface - java.lang.String, a class with a mutable interface java.lang.StringBuffer. I can append to a java.lang.StringBuffer, but I can't append to the same object with java.lang.String

Does this clear things up? -- some guy


ValueObjects in distributed systems

Something I realized this morning: the BOCA (Business Object Component Architecture) proposal for CORBA makes a very strong distinction between "entities" and "dependents." The distinction basically being "has identity and a location on the network" versus "can be passed between processes by value and doesn't have an identity beyond state." Which sounds a lot like ReferenceObject and ValueObject.

And Java RMI has the notion of "extending Remote" which serve much the same purpose.

I'm not sure where the line between ValueObject and ReferenceObject gets drawn in a single process application (and I think that a fairly common refactoring is to change something from a ValueObject to a ReferenceObject or vice versa). But the distinction seems much more important in distributed systems (I'm including database apps in "distributed systems").


Why are we talking about this?

Where did ValueObject come from? Why was the page originally put up and what prompted the distinction? -- WilliamGrosso

The distinction between ValueObjects and ReferenceObjects comes from MartinFowler s observation: ValueObjectsShouldBeImmutable and the update-consistency problems caused by changing the state of ValueObjects over time.

I put up this page because I'm trying to come up with a small set of rules which define consistent forms of reference and containment between ValueObjects and ReferenceObjects. If you had such a rule set, it would be easier to detect designs with update consistency problems. It's easy to come up with rules, but coming up with usable rules that guarantee consistency is another matter. I'm using this page to try out rules and get opinions on what kinds of rules are workable. -- some guy

I'm having trouble imagining what I would do better if I understood this topic better. Can anyone enlighten me? Thanks! -- RonJeffries

Recognize when you have a ValueObject or need a ValueObject, even if it is rather complicated so that you can enforce ValueObjectsShouldBeImmutable and avoid unintended consequences.

There are a number of objects in LifeTech that should have been ValueObject's, but aren't (or weren't, in some cases). I will be happier when I can explain better how to construct ValueObject's, and even better, when to construct them. -- KentBeck

I see two main categories of motivation for value objects: avoiding bugs through aliasing and increasing performance through value semantics.

Avoiding bugs through aliasing: because value objects typically either come as immutable object or with copy-on-write semantics, you don't have to worry about side-effects. So you avoid bugs.

Increasing performance. Value semantics make your value objects perform better in many ways. In memory, you optimize equality as identity. In distributed systems, you just know that you can copy your value objects across process boundaries without having to worry for references. In concurrent systems, you have no locking overhead. In mapping to relational tables, you can stream values into the table rather than maintaining them in a table of its own and hence increase query performance. Etc.

If you are interested, we discuss these advantages and their efficient implementation in a technical report at http://www.riehle.org/papers/1998/ubilab-tr-1998-10-1.html. -- Dirk Riehle

PS: IMO, collections are higher-level value objects. Collection class (types) are higher-level value type constructors. It just doesn't perform to implement collections with value semantics, so you handle them with reference semantics.


Semantics of "=="

For the unwashed, == is equality check? Identity check. Two objects are == iff there is no possible way to tell them apart. Typically this means that they occupy the same locations in memory. Then you're really, really sure they are the same. -- KentBeck

ScottMeyers says in EffectiveCPlusPlus that == can be declared as a method in any C++ class, but there is no "default" definition. Effectively, == in C++ means whatever you define it to mean on a class-by-class basis. -ouch!

From an intuitive point of view, if a C++ programmer overloads == for a class using equality of identity (they test the base address of the stored state), then I'd say the class concerns ReferenceObjects, whereas if they define == for the class purely in terms of state (equality of the whole state, or of a subset of state) then I'd say they intend to build a class of ValueObjects.

- It'd be better from a readability point of view if the C++ community used two equality methods as Java has. Doing this would make it easier to understand code fragments (because you know which type of equality semantics is intended without looking it up in the == method code). -- some guy

- In C++ I use pointers for my ReferenceObjects, whereas I use values for my ValueObjects. So equality just works out the way I want. I get == by state for values and == by identity for reference objects. I don't need to define == for reference objects. Copying also just works out the way I want. I get copying of state for values and copying of pointers for reference objects. I don't use inheritance for value objects, so the dreaded copy by slicing "problem" doesn't ever hit me. I don't allow copying of reference objects (I remove access to the copy constructor and assignment operator.) -- AmitPatel

== in C++ is not == in Smalltalk. It is more like = in Smalltalk. In theory, = can be defined specially for every class in Smalltalk, though in practice most classes use the default, which is ==. However, you cannot change ==. It is one of the few methods in Smalltalk that you cannot change. For every class, == means "is the same object". I always pronounce = as "equal" and == as "identical" when I am reading Smalltalk code aloud.

One interesting thing about Smalltalk is that most classes that define = are ValueObjects. Not all; the collection classes also define it. But by and large, a ReferenceObject uses identity for equality, while a ValueObject has to check equality by comparing instance variables. -- RalphJohnson


Aliasing

In my early Smalltalk days, I spent hours/days/weeks chasing aliases around, and went through a phase of making REALLYdeep copies. Then my difficulty vanished, and I didn't find the topic present, and never thought about why. Later, I worried about points and rectangles, and cows and what sex they are and what kind they are and how heavy they are and I came to a set of tentative conclusions.

A thing to note is that I have never yet had to put these conclusions to use (a reason I have never written or spoken them before. But Kent's admission makes me bold enough to), so you may end up asking how much this all matters.

First, when we create an instance variable to hold an attribute of an object, it is for one of two reasons, which we don't typically bother to distinguish (but one can with C++ const):

Originally, I thought that the sex of a cow is an unchanging attribute, but I realized that animals (and even people!) get operated on a lot. What a surprise for the programmer for whose initial requirements sex was immutable, and put that into the system.

Secondly, if I really want to protect my unchanging attributes in Smalltalk, I can create its initialize method to start with the phrase "(anyInstanceVariable == null) ifTrue: [ ...all the initialization... ]." Or extend lazy initialization to the setter method also, for the method 'specie: value', write, "(specie == null) ifTrue: [ specie := value ]" (that way, the value can only be set once in the life of the object).So when I care, I can make unchanging (immutable) attributes. I have learned that the C++ 'const' construct, which seems like a compile-time counterpart to this, has the most amazing and unexpected ripple effects throughout the system.

And so far I have not had to put either into practice. Comments welcome from people who have tried these approaches. -- AlistairCockburn

I haven't been tempted to do the one-shot initialization thing in C++, usually those turn into constructor arguments for me. I've used const attributes at times. In C++ there are very necessary uses for const, but I tend to be sparse in my use because of the ripple effects that Alistair mentions.

I notice that species is like a TypeObject. It is kind of interesting that the immutable part of an object is often considered it's type: a description that works across the lifetime of an object. On the other hand, reflection allows people to change parts of objects which are normally immutable. How about this for a definition of reflection: when your TypeObject (either explicit or part of the language) is not a ValueObject? Er, at least by one definition of reflection. Java's reflection is more like introspection, isn't it?

At OOPSLA98 I had chance to ask RalphJohnson a brief question.. and I ran past him the idea it seems that any use of delegation could be seen as an instance of the TypeObject pattern. I often think about what software looks like when you erase the names of the classes. An ostrich is a bird, or it has Birdness. Is the type of a widget that has a socket socket-holding-widget? I notice sometimes that half the fun of refactoring comes from looking at the software and seeing where new concepts can arise. -- MichaelFeathers

Example of an immutable attribute that is not a type: dateOfBirth. In fact, anythingAtBirth. transactionDate. anything date-stamped. Your other sentences touch nicely on the DualityBetweenStateAndClass. -- AlistairCockburn

A constant is just a variable bound at a higher level. -- SomeLISPGuy


ValueObject collections

With regards to ValueObject collections:

My motivation for looking at ValueObject(s) concerns modelling: "if it doesn't behave like an object, it isn't an object". ("behave" - it actually needs a unique identity as well as having state) Consider the elements of the periodic table for instance - all code aside it just doesn't make sense to instantiate two Hydrogen objects and make arbitrary decisions between the two based on identity. Worse, if we just pretend the elements are ordinary objects, you might be able to change the atomic mass held in the state(!). I find it's simpler and more natural to think of the hydrogen element as a member of a set.

If you have a language that insists that "everything is an object", or doesn't support enums then you can code up these.


EditText of this page (last edited April 22, 2012) or FindPage with title or text search