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} format unitFormat
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: