# Using Numbers with Units

In SenseTalk, you can use numbers, either as numerals or text, for many types of operations and comparisons. Numbers often represent a quantity of some particular type, not merely an abstract value. For instance, the area of a rectangle might be referenced as "9 square inches" or an account balance might contain $698.53.

SenseTalk lets you associate a unit type such as inches or dollars with a number to add meaning and relevance. Assignments to variables and calculations using those values maintain and convert units as needed.

## Working with Units

To specify a numeric value with a unit type, you include the unit name after the value. (The exception to this rule is the dollar symbol — $ — as described below.) SenseTalk recognizes singular, plural, and abbreviated unit names as well as "square" and "cubic" modifiers for area and volume:

`put 3 ft --> "3 feet"`

set weight to four grams

put 9 sq in --> "9 square inches"

Note: You do not include a period with unit abbreviations.

You can use chained values of the same type, with one value after another or with values joined by `and`

. Such representations are commonly used for weight or distance measurements:

`put 6 ft 3 in --> "6.25 feet"`

set weight to 2 pounds and 3 ounces

put weight --> "2.1875 pounds"

As you begin to see in the examples above, you can mix units in your expressions. Units are preserved or converted as needed in assignments and calculations:

`put 3 ft into width`

add 1 yard to width -- 1 yard is automatically converted to 3 ft in order to add it to the existing width

put width --> "6 feet"

put width * 4 feet into area

put area --> "24 square feet"

add 2 liters to area -- throws a mismatched units exception

You can combine units to form complex unit types such as speed (distance per timeInterval) or volume (length times width times depth):

`set speed to 25 mi/hr`

put speed --> "25 miles per hour"

put 3 hrs 45 min * speed --> "93.75 miles"

set accelerationOfGravity to 32 ft/s^2

set flow to 5 gallons per minute

set clickRate to 500/hr

set price to $5.96 per lb -- same as: 5.96 dollars per pound

set weight to 4 oz

put price * weight --> "$1.49"

### A Note on Unit Compatibility

SenseTalk converts units to combine values when it makes sense (as in combining 3 feet and 1 yard to get 6 feet). However, if you try to combine units that can't logically be combined (such as a flat area measurement and a volume measurement), you will get an error.

Units must be compatible (represent the same type of measure) to be added, subtracted or compared. That is, a unit of length (for example) can be added to another unit of length, even if the specific unit type is different (meters + feet + inches = OK!). These types are said to be compatible.

However, attempting to perform addition, subtraction, or comparison with incompatible units will throw an exception:

`put average(4 in, 5 ft, 1 meter) --> 0.8752 meters`

put average(4 in, 5 ft, 1 pint) -- throws an exception because of differing unit types

## Unit Conversions

As mentioned above, SenseTalk will automatically convert values from one unit type to another. This ability can be particularly useful in mathematical operations. You can also explicitly convert units from one type to another.

### Addition, Subtraction

SenseTalk automatically converts values to compatible units for addition and subtraction operations, and to compare two values for equality. For addition and subtraction, the resulting value will favor one unit type over another based on the internal ordering of the units in the system.

For example, adding inches and centimeters gives the result in centimeters regardless of the order of the operands. Adding meters and centimeters results in meters. However, you can use the `as`

operator to specify the result type:

`put 8 inches + 3 cm -- converts 8 inches to centimeters and adds 3 centimeters to it,`

-- so prints: "23.32 centimeters"

put (8 inches + 3 cm) as inches -- as above, but converts to inches before output,

-- so prints: "9.181102 inches"

Addition or subtraction of a number with a unit type and a plain number (i.e., a number without a unit type) results in an error.

### Multiplication, Division

When multiplying and dividing with units, whether the unit is maintained or converted is a little more complicated. You can use plain numbers to multiply or divide numbers with units, and the result preserves the unit type:

`set height to 20 feet`

set width to 3 times height

put width --> 60 feet

set var1 to 2

put 10 hours / var1 --> 5 hours

When dividing where both numbers include units, values with compatible unit types are converted to the same unit, just as for addition. The units, however, are dropped from the results:

`Put 4 yards divided by 2 feet -- Prints: "6" (4 yards can be divided into 6 2-foot segments)`

When numbers with units are multiplied, whether compatible or incompatible, the units are kept and a complex unit type is formed. For example, dividing miles by hours will keep both units, resulting in a value with the complex unit type miles per hour:

`put 500 miles divided by 4 hours --> 125 miles per hour`

put 4 yard * 2 feet --> 24 square feet

put 2 liters times 2 liters --> 4 liters^2

You can use lists of units with mathematical operators. With multiplication and division, you can use a single plain number against a list. With addition, subtraction, multiplication, and division, you can use multiple lists of numbers with units, provided the number of items in the lists match:

`put [4 oz, 2 g, 0.3 m] / 3 --> [1.333333 ounces,0.666667 grams,0.1 meters]`

`put [4 oz, 2 g, 0.3 m] + [4 oz, 2 g, 0.3 m] --> [8 ounces,4 grams,0.6 meters]`

`put [4 oz, 2 g, 0.3 m] - [4 oz, 2 g, 0.3 m] --> [0 ounces,0 grams,0 meters]`

`put [4 oz, 2 g, 0.3 m] * [4 oz, 2 g, 0.3 m] --> [16 ounces^2,4 grams^2,0.09 square meters]`

`put [4 oz, 2 g, 0.3 m] / [4 oz, 2 g, 0.3 m] --> [1,1,1]`

### Ranges

You can use units when you specify a range. If a unit is specified for only one end of a range, the other end is assumed to be the same unit type:

`put 3..7 m/s --> 3 meters per second to 7 meters per second`

Similarly, the `between`

operator assumes matching units if units are given for only the second value:

`put 4 cm is between 1 and 3 inches --> True`

### Conversion with As

You can use the `as`

operator to convert a value to a specific unit:

`put 5 feet as inches --> 60 inches`

put 27 grams as oz --> 0.952397 ounces

put totalWeight as kilograms

set distance to (var1 + var2) as yards

In the final example above, it is necessary to enclose "var1 + var2" in parentheses to ensure that the final result will be expressed in yards. Without the parentheses (i.e., "var1 + var2 as yards"), the value of var2 would be converted to yards before adding to the value of var1 because the `as`

operator has a higher order of precedence than the `+`

operator. So the resulting unit might be yards or something else, depending on the units of var1.

### The Convert Command

A value in a variable can be converted to a particular unit by using the `convert`

command. If the source value being converted is not a variable or other container, the resulting value is stored in the variable `it`

.

`convert depth to fathoms -- the value in depth is now in fathoms`

convert 3.5 gallons to cc -- the result is stored in it

Note: The convert command can also be used to convert date and time formats, as described in Date and Time Values in SenseTalk.

### The Units Property

It's possible to access or change the `units`

property of a variable directly. However, note that this method doesn't convert the value:

`set width to 6 ft`

put width's units --> feet

put width --> 6 feet

convert width to yards

put width's units --> yards

put width --> 2 yards

set width's units to "feet"-- this sets the value's unit directly, replacing the previous unit

put width's units --> feet

put width --> 2 feet

Note that width's `units`

property could also be referred to as `width.units`

or `the units of width`

. Remember that changing the units property directly doesn't perform a value conversion, so be sure to use this method with care.

You might want to set the units for a plain number value that doesn't already have a unit. For example, a handler might assume that a parameter passed in represents meters if it's not explicitly given in some other unit:

`put areaOfCircle(6 in) --> 113.097336 square inches`

put areaOfCircle(4) --> 50.265482 square meters

function areaOfCircle radius

if radius.units is empty then set units of radius to "meters"

return pi * radius squared

end areaOfCircle

## Unit Types

SenseTalk supports units for time intervals (duration in days, minutes, etc.), length or distance (miles, feet, meters, etc.), mass or weight (grams, ounces, etc.), liquid measures (liters, gallons, etc.), rotation and angles (degrees, radians, etc.), electrical measures (amps, volts, etc.), and many others.

You can test values to see if they are of a particular type by using the `is a`

operator:

`if mySize is not a length then put "size must be a length"`

if amount is a weight then set calculateByWeight to true

### Currency

You can specify currency amounts in dollars by preceding a value with a dollar sign ($), since that's the common method for writing monetary amounts. Currency can also be specified by using unit names such as dollars and cents following the number, as with other unit types:

`set cost to 5 dollars and 27 cents`

set cost to $5.27

## Unit Type Functions

`FormattedUnits`

Function

**Behavior:** Applies a unit format to a numeric value with units and returns the formatted value. Learn more about how to write unit formats.

**Parameters:** The unit format string followed by the value that you would like to format. Alternatively, the same result is achieved by using the format operator to apply a unit format to a numeric value.

Syntax:

formattedUnits(unitFormat,valueWithUnits)

valueWithUnits{with|using}formatunitFormat

**Example:**

`put formattedUnits("[miles] @, [feet] @", 8765 ft) --> 1 mile, 3485 feet`

put formattedUnits("[earthMass] @ + [moonMass] @", 1 sunMass) --> 332948 earthMasses + 28 moonMasses

put 35 ounces using format "[lb] lb [oz] oz" --> 2 lb 3 oz

**Related:**

`SplitUnits`

Function

**Behavior:** Converts a numeric value of a certain unit type into a specified list of units that add up to the original value. For example, convert a weight into pounds and ounces, or a duration into hours, minutes, and seconds.

This function cycles through the requested unit names in order, and allocates the whole number of each of those units in turn from the original value. The final unit in the list receives the remaining part of the value, including any fractional part.

**Parameters:** The value that you want to convert, or 'split', followed by the names of the units that you want to convert the value to, either as separate parameters, or as a list of names.

Pass in `“”`

or `empty`

as an additional unit type when you don't want to return a fraction for the final unit. See the example.

Syntax:

splitUnits(valueWithUnits,listOfRequestedUnitNames)

splitUnits(valueWithUnits,unitName1{,unitName2, …})

**Example:**

`put splitUnits(4288.321 seconds, ["hrs","mins","secs",empty]) --> [1 hour,11 minutes,28 seconds] // Use 'empty' to absorb any amount that is smaller than the final unit type`

put splitUnits(4288.321 seconds, "hrs", "mins", "secs") --> [1 hour,11 minutes,28.321 seconds]

**Related:**

`UnitNames`

Function

**Behavior:** Returns a list of all unit names that SenseTalk recognizes, or a list of all unit names for a specific unit type.

**Parameter:**

- (Default) Use
`"all"`

, or no parameter, to get a list of all unit names in SenseTalk. - Pass the name of a unit type, such as
`"length"`

, to get a list of all units of that type.

Syntax:

unitNames({unitTypeOrAll})

**Example:**

`put unitNames("speed") --> ["knot","mph","mps","kph","knots"]`

put unitNames() into allUnitNames

**Related:**

`UnitTypes`

Function

**Behavior:** Returns a list of the names of all unit types that SenseTalk recognizes, with or without synonyms.

**Parameter:**

- (Default) Use
`"all"`

, or no parameter, to get a list of all unit types in SenseTalk, including synonyms. - Pass in
`"standard"`

, to get a list of only the standard names for each unit type, excluding synonyms.

Syntax:

unitTypes({allOrStandard})

**Example:**

`put unitTypes("standard") --> ["length","mass","byteSize","duration","calendarDuration","rotation","electric_charge","area","volume","electric_current","force","pressure","stress","energy","power","electric_potential","electric_resistance","resistance","electric_conductance","conductance","electric_capacitance","magnetic_flux","inductance","magnetic_flux_density","frequency","velocity","acceleration","flow","angular_velocity","temperature_difference","currency"]`

**Related:**

`UnitType`

Function

**Behavior:** Returns the standard unit type for a unit name, or the unit name of a numeric value.

**Parameter:** Accepts either a unit name or numeric value with units.

Syntax:

unitType({unitNameOrValueWithUnits})

**Example:**

`put unitType("weight") --> mass`

put unitType(765 ft) --> length

**Related:**

## Units Global Properties

SenseTalk has three global properties that affect the configuration and formatting of units in SenseTalk.

`the unitFormats`

Global Property

**Values:** A property list that holds the default unit format for one or more unit types.

**Default:** `{:}`

An empty property list.

**Behavior:** Determines the format used for displaying values with units. If the `unitFormats`

property includes a format for a given unit type, that format is used unless a different specific format is requested for the value.

The keys of the `unitFormats`

must be valid unit types returned by the `unitTypes`

function. The corresponding value for each unit type must be a unit format string.

The keys for unit types are standardized automatically to the standard name for that type. For example, assigning a format to the key `weight`

is perfectly valid, but actually sets the `mass`

property of the `unitFormats`

. See example.

**Example:**

`set the unitFormats.weight to "[lbs?] @ [oz.] @" // This actually sets the 'mass' property`

put 67 ounces --> 4 lb 3 oz

put 5432 grams --> 11 lbs 15.608161 oz

**Example:**

`put 5432 sec --> 5432 seconds`

set the unitFormats.duration to "[hours 00]:[minutes 00]:[seconds 00]"

put 5432 sec --> 01:30:32

**Example:**

`set the unitFormats to {`

duration: "[hrs? 00*]:[mins]:[secs]",

byteSize: "[GB? 0.0*] @||MB?||KB?||Bytes",

electric_current: "Milliamp 0.###",

}

put 139 sec --> 02:19

put 789234 bytes --> 770.7 KB

put 5.6 amperes --> 5600 Milliamps

`the unitsEnabled`

Global Property

**Values:** `True`

, `False`

**Default:** `True`

**Behavior:** Turns the units system on or off. When `the unitsEnabled`

is set to `False`

, most units are ignored. For compatibility with earlier versions, units of duration (hours, minutes, seconds, etc.) and dataSize (kilobytes, megabytes, etc.) are honored when `the unitsEnabled`

is turned off. Other units are ignored.

`the strictUnits`

Global Property

**Values:** `True`

, `False`

**Default:** `True`

**Behavior:** Controls how strictly the units system is honored. Setting the property to `False`

makes the system more relaxed about unit operations. For example, if you set this property to `False`

, then add a plain number to one with units, SenseTalk treats the plain number as having the same units (so 7 ft + 3 = 10 feet) rather than throwing an exception. Other operations will drop the units (e.g., specifying a range of 4 acres to 6 lbs will give "4 to 6" and 3 ft + 4 gallons = 7).