Here are some properties I have been considering for the notion of a class of ValueObject
, therefore ValueObject
s should have:
- an immutable public interface, and
- an invariant object state (after termination of the object construction process).
- Methods defined in a ValueObject are not necessarily idempotent (they can change the state of the system). ValueObject methods can change the system only by creating new objects (For example Java.lang.String is a class of ValueObjects - there is a method for creating a corresponding StringBuffer.)
- ValueObjects can only contain references to other ValueObjects. (If a ValueObject referred to a ReferenceObject it would not be truly immutable.) (For example a class of measurements define a magnitude attribute and refer to a "units" ValueObject.)
Do these ideas make sense to you?
Are these hypotheses plausible? (Do you know of practical examples of ValueObject
s 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 ValueObject
s 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 ValueObject
s. 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 ReferenceObject
s. 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
change over time
- they participate in a dynamic process, and that ValueObject
s have the same state value throughout the lifetime of the system
. (Hence the fact that equality of state is used when comparing ValueObject
s, rather than unique identity.)
What I've read here has been really useful so far, anymore examples of ValueObject
s referring to ReferenceObject
s 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
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.
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:
- Discover the essential data necessary for producing the ReferenceObject, store these data as attributes in an immutable wrapper. To access a date, the ValueObject returns a new instantiation of Date. (A variation of ReturnNewObjectsFromAccessorMethods)
- Ensure that the Date value object wrapper is the only object to which the mutable instantiation of date can be accessed (so no other object could send messages to the mutable object.)
I think it's worth making a distinction between reference
here. (Thanks NatPryce
s shouldn't have an attribute which is a reference to a ReferenceObject
, but they can contain
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:
- ValueObjects should have an immutable interface
- 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.)
- 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.)
- ValueObjects can contain attributes which are pure data values (or "primitives").
- ValueObjects should not contain attributes which are references to ReferenceObjects.
- 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++.)
- ValueObjects may contain attributes which reference ValueObjects. (Hence these rules apply recursively.)
(The question of PhysicalState?
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 ValueObject
s strictly there is only one:
Since a ValueObject
does not change, a ValueObject
should never reference a ReferenceObject
. However, the class of a ValueObject
can provide keyed access to ReferenceObject
s 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 ReferenceObject
s where the state of the ReferenceObject
is not part of the state of the ValueObject
that refers to it.
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 ValueObject
s?): 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").
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.
I think convoys as you define them are ValueObject
s. 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
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
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 Java RMI has the notion of "extending Remote" which serve much the same purpose.
I'm not sure where the line between ValueObject
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 ValueObject
s and ReferenceObject
s comes from MartinFowler
s observation: ValueObjectsShouldBeImmutable
and the update-consistency problems caused by changing the state of ValueObject
s 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 ValueObject
s and ReferenceObject
s. 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
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 ReferenceObject
s, 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 ValueObject
- 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 ReferenceObject
s, whereas I use values for my ValueObject
s. 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 ValueObject
s. 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
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):
- We don't intend for the value ever to change, it is just that we don't know the value of the attribute at compile time (different instances will have different values). The specie of a cow is an example of an unchanging attribute.
- We intend for the value to change, and want a place to describe the current value. The weight of a cow is an example.
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
With regards to ValueObject
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.