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
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
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 dollars"
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
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.
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, resulting in "23.32 centimeters"
put (8 inches + 3 cm) as inches
-- as above, but converts to inches before output, so "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.
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
-- "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)
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
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
-- 50.265482 square meters
function areaOfCircle radius
if radius.units is empty then set units of radius to "meters"
return pi * radius squared
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
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
The unitTypes() function returns a list of all of the different unit type names that are recognized by the is a operator. Synonyms are included for some types, such as length and distance, velocity and speed, and others.
The unitNames() function returns a list of all of the valid names for units. The list includes singular and plural names, abbreviations, prefixed names, and in some cases alternate spellings.
Units Global Properties
SenseTalk has two global properties that affect the units system, the unitsEnabled and the strictUnits. Both are set to true by default.
The unitsEnabled Global Property
The unitsEnabled global property can be used to turn the units system off if desired. When the unitsEnabled is set to false, most units will be 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
The strictUnits global property 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).