package gw.lang; /** * A Dimension is a measurement of size or capacity of something. According to * the International System of Units (SI) there are seven base physical dimensions * from which all other physical dimensions are derived. These are (in no * particular order): Length, Mass, Time, Current, Temperature, Luminosity, and * Amount. Of course non-physical dimensions are not limited to this set. For * instance, Cost is a dimension which has no basis in physics, yet is often * a critical dimension in business calculations involving physical quantities. * <p> * The unit of measurement for any particular type of dimension can be specified * using any number of measure systems. For instance, a Length dimension could * be specified in Metric units (kilometers, millimeters, etc.) or Imperial * units (miles, inches, etc.) or what have you. * <p> * The stability of a dimension determines how it will be implemented in terms of * this interface. Essentially a dimension is either stable or volatile. A stable * dimension is one that does not change over time. The standard physical dimensions * such as Length are stable because, for example, an inch today is the same length * as an inch tomorrow, relative to physical objects in our universe. Also the logic * to compare two different units of length is stable e.g., 1 inch always equals * 2.54 centimeters. Thus, a stable dimension can be "pegged" on any given measure * unit. As a consequence there is no need to store a unit type within a stable * dimension instance e.g., all Length instances could be stored as millimeters * in a BigDecimal -- the unit of measure is only a user interface concern. * <p> * Conversely, a volatile dimension is one that may change over time. For instance, * the units of a Cost dimension change over time relative to one another e.g., * a US Dollar today may not equal the same number of British Pounds tomorrow. * Essentially, the exchange rates between currency systems is based on purchasing * power and the balance of trade between systems, very fuzzy calculations. Thus, * an instance of a Cost dimension must store not only the amount, but also the * unit of measure e.g., US Dollars. For this reason it is recommended that for a * given volatile dimension separate dimensions should be specified for each type * of measure system. For instance, two distinct Dimensions should be defined for * USDollar and Euro. E.g., * <pre> * abstract class Cost<C extends Cost<C>> implements IDimension<C, BigDecimal> {...} * class Dollar extends Cost<Dollar> {...} * class Euro extends Cost<Euro> {...} * </pre> * Note a dimension can be an operand in any Gosu arithmetic expression: + - * / %<br> * as well as in any relational or equality expression: == != < <= > >= <br> * <p> * The default behavior for these operations follows:<br> * For addition and subtraction both operands must be of the same exact type. * e.g., adding inches to dollars has no practical meaning; nor does adding * a plain number to a dimension. Likewise for relational expressions. * For multiplication, division, and modulo only one operand may be a dimension * i.e., multiplication between dimensions is undefined. * <p> * To override default arithmetic operations a dimension may provide one or * more methods with the following format: * <pre> * <resulting-dimension-type> <operator-name>( <rhs-dimension-type> rhsValue ); * </pre> * Where <operation-name> is one of the following: * <pre> * add * subtract * multiply * divide * modulo * </pre> * Examples: * <pre> * class Length implements IDimension<Length, BigDecimal> * { * ... * * // Defines a method for producing a Rate dimension when dividing by a Time dimension. * // E.g., the following divide operation is legal now (provided dimensions are defined for Rate and Time) * // var rate = distance / time * public Rate divide( Time rhsValue ) * { * return new Rate( _value.divide( rhsValue.toNumber() ) ); * } * } * </pre> * * Copyright 2010 Guidewire Software, Inc. */ public interface IDimension<S extends IDimension<S,T>, T extends Number> { /** * The Gosu runtime call this method when performing default operations. * For instance, when adding two of the same dimension types, Gosu calls * this method on each operand, adds the numbers, and then calls fromNumber() * for the result. * * @return the number of units for this dimension instance. */ T toNumber(); /** * Returns a separate instance of this type with the given number of units. * <p> * The Gosu runtime call this method when performing default operations. * For instance, when adding two of the same dimension types, Gosu calls * toNumber() on each operand, adds the numbers, and then calls fromNumber() * for the result. * * @return a separate instance of this type given the number of units. */ S fromNumber( T units ); /** * @return The static Number derivation for this class. Must be the same * as the T parameter. Note this is only useful in Java where the type * is lost at runtime due to type erasure. In Gosu the type parameters * are preserved due to type reification. */ Class<T> numberType(); }