Quantity


Represent dimensioned values with both their amount and their unit

There are many cases where we want computers to represent dimensioned quantities: values such as six feet, or thirty kilograms. Usually these are represented as bare numbers, mainly because that is the best we can do in the limited type systems that languages give us.

But using objects invites us to add new fundamental types whenever they add value, and having a specific type for dimensioned quantities adds quite a lot of value. This is particularly true when the dimensioned value is that of Money. Money is a special case of Quantity, but also one that perhaps the most widely used, as plenty of people are prepared to spend money to watch money.

How it Works

The basic idea of Quantity is a class that combines the amount with the unit. In saying that a quantity is a simple representation. However the real fun with Quantity comes with the behavior that you can apply to it.

The first kind of behavior is arithmetic. You should be able to add two quantities together just as easily as you can add two numbers. Furthermore more the quantities should be intelligent about addition and subtraction: at the least preventing you from adding 6 feet to 180 pounds.

More complicated issues with addition arise where you are trying to add similar units, such as adding 500 meters to 3 kilometers. The simplest approach is to deny that addition, forcing the client to make the conversion. A more sophisticated approach is to see if you can convert one argument to the other, if so you can perform the addition. How well you can do this depends on the sophistication of your Convertor.

Multiplication has similar variations in sophistication. The simplest approach is to only permit multiplication and division by scalar numbers. A more sophisticated approach is to allow multiplication by other quantities, but then you have to work out the units of the result. So if you divide 150 miles by 2 hours you get 75 miles/hour.

Comparison operations are needed so you can find out if six feet is more than five feet. The issues here are much the same as those for addition - you have to choose how much conversion you do.

It's useful to provide a simple interface to allow conversion on a quantity directly, although the conversion work is usually best left using Convertor. If you only have a few units, however, it's easier to embed them directly in quantity classes.

One of the most useful behaviors you can give to quantities is to provide printing and parsing methods that allow you easily produce strings and to produce a quantity from a string. This simple pattern can do much to simplify a lot of input and output behavior, either to files or in GUI interfaces.

For simple printing you can have a default, such as first printing the amount and then the unit. That breaks down when in some cases you want to print the unit before the number and other cases afterwards. Usually this kind of variation will depend on the unit, so in these cases you can put the printing and parsing behavior on the unit and delegate to that.

Money

I use Quantity on almost every system I work with, but I rarely use it to represent physical units. Most of the time I use it to represent money. Much of the comments for physical units are the same, but money does have its own spin to bear in mind when you're working with it.

The biggest change surrounds the whole area of conversion. While physical units' forms of conversion don't change over time, exchange rates for money are always changing. Obviously this affects conversion operations, but the effect ripples into the addition, subtraction, and comparison operations as well.

When you convert money, at the least you need to provide some kind of time reference, whose granularity will depend on the application. But in many cases you may have separate conversions in different contexts - all of which I explore in Convertor

The upshot of all this is that you need to be much more careful about automatic conversion inside arithmetic or comparison operations with money. So often you'll find they are not allowed. However there is an ingenious solution to addition operations with money that you'll find in Money Bag.

A particularly useful feature with Money in addition to those for Quantity is the handling of rounding. Money is often expressed with a decimal part, yet you should never use real numbers for handling Money. The reason for this is that the rounding behavior of real numbers almost never corresponds to what's needed for money, and ignoring this fact can easily lead to intermittent bugs which are small in denomination and high in frustration.

A money object, however, can encode its own rules for rounding, which means that most of the time you don't have to be aware of the rounding rules while you are working with money.

Connected to this is the knotty matter of division. If you divide $100 by three, what do you get? Usually the answer is not as simple $33.33. The problem is that if you multiply $33.33 you get $99.99 - meaning that a penny goes missing. Accountants don't like pennies to go missing. So you'll have to find out what policy applies to the situation you're looking at. Often the rule is that someone should get extra penny, although it doesn't matter who. So you can put a method in the money object to return a collection of the monies that you need to hand out from the division.

Relational Databases

A common question with Quantity is how to use it for relational databases and other systems without the ability to create new lightweight types. Do you store an amount and a currency code with every monetary value?

The issue here comes when there is a constraint in place that forces all monies to be of the same currency in a certain context. So consider the case where you have an account with many entries. Each entry has a money attribute to show the amount of the entry, yet all the entries on an account have the same currency. Is it reasonable to store the currency once on the account and not duplicate the currency across the entries?

I'm inclined to punt on this question, and leave it to the specifics of your database design. I would still urge you to use money objects in your code: it's up to you whether how you store those in the database. After all the database doesn't give you any behavioral advantages from Quantity. You only get those in the code.

When to Use it

As you've gathered I use Quantity, at least in the money variation, a lot. Indeed with an object-oriented environment there's little reason not use it. Often I've noted that people are scared about using small objects like this mostly due to unfamiliarity. Performance is an oft-cited concern, although I've not seen or heard of Quantity being a really problem for performance.

There's an argument that says that using Quantity isn't worth it when there's only one unit, so you shouldn't use money when you only have one currency. But much of the value of money comes from its behavior, not its multi-unit capabilities, so I would use it even then.

Example: Money

Money is my most common use of Quantity, so it makes a good place for an example. First the basic representation:

class Money... 
public class Money implements Comparable{
	private BigInteger amount;
	private Currency currency;

Notice that I use a BigInteger. In Java I could equally well use a BigDecimal, but in many languages an integer is the only decent option, so using an integer seems the best for explanation. Don't be afraid to choose your representation of the amount part of a quantity based on performance factors. The beauty of objects is that you can choose any data structure you like on the inside, providing you hide it on the outside.

So moving to the interface. You'll probably want the obvious getting methods.

class Money... 
	public double amount() {
		return amount.doubleValue() / 100;
	}
	public Currency currency() {
		return currency;
	}

Although you shouldn't find yourself using them very much. Usually other methods will be better for your purpose. Indeed using the getters on quantity should always spark a thought in your mind as to whether there is a better way. Usually there is.

You'll notice there are no setters. Money is a Value Object and is thus immutable.

It helps to have a variety of constructors to make it easy to make monies. Constructors that convert from basic numeric types are always useful.

class Money... 
	public Money (double amount, Currency currency) {
		this.amount = BigInteger.valueOf(Math.round (amount * 100));
		this.currency = currency;
	}
	public Money (long amount, Currency currency) {
		this.amount = BigInteger.valueOf(amount * 100);
		this.currency = currency;
	}

If you use one currency a lot, you may want a special constructor for that currency.

class Money... 
	public static Money dollars(double amount) {
		return new Money (amount, Currency.USD);
	}

For addition and subtraction I'm not trying to do any fancy conversion. Notice that I'm using a special constructor with a marker argument.

class Money... 
	public Money add (Money arg) {
		assertSameCurrencyAs(arg);
		return new Money (amount.add(arg.amount), currency, true);
	}
	public Money subtract (Money arg) {
		return this.add(arg.negate());
	}
	void assertSameCurrencyAs(Money arg) {
		Assert.equals("money math mismatch", currency, arg.currency);
	}
	private Money (BigInteger amountInPennies, Currency currency, boolean privacyMarker) {
		Assert.notNull(amountInPennies);
		Assert.notNull(currency);
		this.amount = amountInPennies;
		this.currency = currency;
	}
	public Money negate() {
		return new Money (amount.negate(), currency, true);
	}

Multiplication is very straightforward.

class Money... 
	public Money multiply (double arg) {
		return new Money (amount() * arg, currency);
	}

But division is not, as we have to take care of errant pennies. We'll do that by returning an array of monies, such that the sum of the array is equal to the original amount, and the original amount is distributed fairly between the elements of the array. Fairly in this sense means those at the begriming get the extra pennies.

class Money... 
	public Money[] divide(int denominator) {
		BigInteger bigDenominator = BigInteger.valueOf(denominator);
		Money[] result = new Money[denominator];
		BigInteger simpleResult = amount.divide(bigDenominator);
		for (int i = 0; i < denominator ; i++) {
			result[i] = new Money(simpleResult, currency, true);
		}
		int remainder = amount.subtract(simpleResult.multiply(bigDenominator)).intValue();
		for (int i=0; i < remainder; i++) {
			result[i] = result[i].add(new Money(BigInteger.valueOf(1), currency, true));
		}
		return result;
  	}

Next we'll look at comparing monies, in Java the approach is to implement comparable.

class Money... 
	public int compareTo (Object arg) {
		Money moneyArg = (Money) arg;
		assertSameCurrencyAs(moneyArg);
		return amount.compareTo(moneyArg.amount);
	}

It's also useful to provide some better named operations such as:

class Money... 
	public boolean greaterThan(Money arg) {
		return (this.compareTo(arg) == 1);
	}
	public boolean lessThan(Money arg) {
		return (this.compareTo(arg) == -1);
	}

That makes methods that need the comparison much easier to read.

Since money is a value, it should override equals.

class Money... 
	public boolean equals(Object arg) {
		if (!(arg instanceof Money)) return false;
		Money other = (Money) arg;
		return (currency.equals(other.currency) && (amount.equals(other.amount)));
	}

Since you override equals, don't forget to also override hash (here's a simple suggestion for that).

class Money... 
	public int hashCode() {
		return amount.hashCode();
	}


© Copyright Martin Fowler, all rights reserved