Numbers
Units & Casting
There are 3 types of numbers in Stof: integer, float, and units. In the above section, we saw a brief example of the integer and floating-point number types. However, there is a variant of "float" that helps immensely in Stof - unit types.
Number Operations
#[main]
fn main() {
let res = 10 + 10; // addition
res = 10 - 5; // subtraction
res = 10 * 10; // multiplication
res = 10 / 2; // division
res = 10 % 2; // modulo/remainder
res = 0b0101 & 0b0100; // bit and
res = 0b0101 | 0b0110; // bit or
res = 0b0101 ^ 0b0100; // bit xor
res = 0b0011 << 2; // bit shift left
res = 0b1100 >> 2; // bit shift right
res += 10; // res = res + 10
res -= 10; // res = res - 10;
res *= 10; // res = res * 10;
res /= 10; // res = res / 10;
res %= 10; // res = res % 10;
res &= 0b0100; // res = res & 0b0100;
res |= 0b0110; // res = res | 0b0110;
res ^= 0b0100; // res = res ^ 0b0100;
res >>= 2; // res = res >> 2;
res <<= 2; // res = res << 2;
}
Casting
Casting (and conversions) are done with the "as" keyword.
#[main]
fn main() {
let floating = 45 as float;
let another: float = 22; // also can just define the type
}
Casting also automatically occurs with function calls (parameters and return type).
fn add_hour(time: seconds) -> milliseconds {
// time is in units of seconds
time + 1hr
}
#[main]
fn main() {
const time = self.add_hour(5hr);
// time is now in units of milliseconds
assert_eq(time, 6hr);
}
Units
In Stof, units are additional number types that can be used in place of "float". The "float" type will match all unit types (so you can have a float parameter that accepts any units); however, the unit types will not match each other and will perform conversions when cast to other unit types.
All logical operators (greater than, less than, equals, etc.) and number operations consider units, performing conversions automatically when necessary (and able). Units of the same category will always have a common unit that is the larger of the two (Ex. m + mm -> m). For angles, it will always be radians if the types are mixed.
Examples
#[main]
fn main() {
const distance = 234m;
const func = (dist: km): ft => dist; // m -> km -> ft
let res: m = func(distance); // ft -> m
assert_eq(res, distance);
assert_eq(str(res), "234m");
assert_eq(str(res as km), "0.234km");
}
// Can define fields with unit types
m height: 135cm + 5ft + 123in
#[main]
fn main() {
pln(self.height); // meters
}
Memory
Computer memory/storage units are helpful for configuration files, among many other use cases. Like all units, conversions between any memory unit can be done via a simple cast (either "as" or by declaring units as a type).
#[main]
fn main() {
const bit_mem: bits = 1bit; // "bit" or "bits"
const byte_mem: bytes = 1byte; // "byte" or "bytes"
const kb_mem: kilobytes = 1KB; // "KB" or "kilobytes"
const kib_mem: kibibytes = 1KiB; // "KiB" or "kibibytes"
const mb_mem: megabytes = 1MB; // "MB" or "megabytes"
const mib_mem: mebibytes = 1MiB; // "MiB" or "mebibytes"
const gb_mem: gigabytes = 1GB; // "GB" or "gigabytes"
const gib_mem: gibibytes = 1GiB; // "GiB" or "gibibytes"
const tb_mem: terabytes = 1TB; // "TB" or "terabytes"
const tib_mem: tebibytes = 1TiB; // "TiB" or "tebibytes"
const pb_mem: petabytes = 1PB; // "PB" or "petabytes"
const pib_mem: pebibytes = 1PiB; // "PiB" or "pebibytes"
const eb_mem: exabytes = 1EB; // "EB" or "exabytes"
const eib_mem: exbibytes = 1EiB; // "EiB" or "exbibytes"
const zb_mem: zettabytes = 1ZB; // "ZB" or "zettabytes"
const zib_mem: zebibytes = 1ZiB; // "ZiB" or "zebibytes"
const yb_mem: yottabytes = 1YB; // "YB" or "yottabytes"
const yib_mem: yobibytes = 1YiB; // "YiB" or "yobibytes"
}
Time
One of the most useful applications of Stof units is with time, which is all over the place in configurations and intersystem communications.
As an example, the Time.now() function returns "ms" instead of an integer. This allows users to subtract days, for example, and have Stof handle the complexity.
#[main]
fn main() {
const day_time: days = 1day; // "day" or "days"
const hour_time: hours = 23hr; // "hr" or "hours"
const min_time: minutes = 45min; // "min" or "minutes"
const sec_time: seconds = 60s; // "s" or "seconds"
const mil_time: milliseconds = 1000ms; // "ms" or "milliseconds"
const mic_time: microseconds = 200us; // "us" or "microseconds"
const nan_time: nanoseconds = 79_23ns; // "ns" or "nanoseconds"
}
Angles
There are 4 angle types in Stof: radians (rad), degrees (deg), positive radians (prad), and positive degrees (pdeg).
Positive variations ensure the angle is (and remains) positive (-90deg as pdeg == 270deg) and are used for comparisons.
Radians (rad) and degrees (deg) clamp the angle between [0, +-360deg]. The positive variations clamp the angle between [0, 360deg) (transforming +-360deg into 0 for comparisons). If you don't like the casting and clamping, use a normal float and do it yourself.
#[main]
fn main() {
const rad_angle: radians = 0rad; // "rad" or "radians"
const deg_angle: degrees = 90deg; // "deg" or "degrees"
const prad_angle: pradians = 3.14prad; // "prad" or "pradians"
const pdeg_angle: pdegrees = -45pdeg; // "pdeg" or "pdegrees"
let res: pdeg = 90deg - 270deg; // cast to pdeg always returns [0, 360)
assert_eq(res, 180deg);
pln(res as radians); // cast using the "as" keyword like normal
}
Length
#[main]
fn main() {
const kilo: kilometers = 3km; // "km" or "kilometers"
const hecto: hectometers = 4hm; // "hm" or "hectometers"
const deca: decameters = 5dcm; // "dcm" or "decameters"
const met: meters = 6m; // "m" or "meters"
const deci: decimeters = 45dm; // "dm" or "decimeters"
const centi: centimeters = 67cm; // "cm" or "centimeters"
const milli: millimeters = 500mm; // "mm" or "millimeters"
const micro: micrometers = 567um; // "um" or "micrometers"
const nano: nanometers = 67nm; // "nm" or "nanometers"
const mil: miles = 1mi; // "mi" or "miles"
const yar: yards = 5yd; // "yd" or "yards"
const fee: feet = 55ft; // "ft" or "feet"
const inc: inches = 79in; // "in" or "inches"
}
Temperature
#[main]
fn main() {
const kel: kelvin = 273K; // "K" or "kelvin"
const cel: celsius = 10C; // "C" or "celsius"
const far: fahrenheit = 72F; // "F" or "fahrenheit"
// conversions are then pretty fun
const res = cel as F; // celsius -> fahrenheit
const exp: K = cel; // can just define the type too
}
Mass
#[main]
fn main() {
const giga: gigatonnes = 10Gt; // "Gt" or "gigatonnes"
const mega: megatonnes = 10Mt; // "Mt" or "megatonnes"
const tonn: tonnes = 56t; // "t" or "tonnes"
const kilo: kilograms = 78kg; // "kg" or "kilograms"
const gram: grams = 78g; // "g" or "grams"
const mill: milligrams = 67mg; // "mg" or "milligrams"
const micr: micrograms = 34ug; // "ug" or "micrograms"
const nano: nanograms = 78ng; // "ng" or "nanograms"
const pico: picograms = 89pg; // "pg" or "picograms"
const ton: tons = 55Ton; // "Ton" or "tons"
const pou: lbs = 12lb; // "lb" or "lbs" for imperial pounds
const ozz: ounces = 77oz; // "oz" or "ounces"
}
Incompatible Units
If two units do not have compatible types (Ex. mass & time), then the units are removed.
#[test]
fn undefined_units() {
// behavior should be to remove the units when they don't make sense
const val = 12km + 34seconds;
assert_eq(typeof val, 'float');
assert_eq(val, 46);
assert_not(val.has_units());
}
Last updated
Was this helpful?