Documentation/Chapters

Values, variables and expressions

On this page

A type describes what a value represents and which operations make sense for it. BASIL checks types before the program runs. This catches mistakes such as adding a customer’s name to an invoice total without an explicit conversion.

Declare and initialize variables

LET quantity = 3
DIM price AS DOUBLE = 2.5
DIM description AS STRING
description = "notebook"
quantity += 1
PRINT description
PRINT quantity
PRINT price

LET is optional on a first assignment. DIM ... AS ... supplies a type explicitly. It is especially useful for empty collections and optionals, where the initializer does not provide an element type. A declaration without a value requires proven initialization before a read. Do not expect an ordinary DIM count AS INTEGER to initialize a local to zero. Dense array cells have separate default rules.

Blocks introduce lexical scope: a variable declared inside a branch is local to that branch. Use an outer typed declaration when multiple branches must initialize one variable used afterward. The compiler checks that every reaching path assigns it.

The scalar types

Type Use
INTEGER Signed whole numbers from -2^63 through 2^63 - 1
DOUBLE Binary64 floating-point measurements and fractional values
BOOLEAN TRUE or FALSE
BYTE Unsigned numbers from 0 through 255; packed binary data
UINT32 Unsigned 32-bit values
UINT64 Unsigned 64-bit values
STRING Valid UTF-8 text

Decimal whole literals normally have type INTEGER. A decimal point or exponent produces DOUBLE: 1.0, 2.5, 1.0e3. Hexadecimal &H, binary &B and octal &O literals have UINT64 type. Numeric types do not generally convert implicitly. Use explicit conversions such as CDBL(count), BYTE(255) or UINT32(7). Conversions check the target’s range; do not use conversion as an overflow workaround.

PRINT 7 / 2
PRINT 7 MOD 2
PRINT 7.0 / 2.0
PRINT CDBL(3) + 0.5
PRINT 2 + 3 * 4
PRINT (2 + 3) * 4

INTEGER division truncates toward zero. Parentheses make grouping explicit. INTEGER and unsigned arithmetic check overflow and invalid division; these fatal runtime checks are distinct from catchable operational failures. DOUBLE has a finite precision, so decimal fractions such as 0.1 are generally approximate. Use an application’s chosen representation and rounding policy for money.

Operators and conditions

= and == test equality in an expression; <> means unequal. Numeric ordering uses <, <=, > and >=. Assignment is selected by statement context, as in count = 3. AND and OR short-circuit: the right operand runs only when needed. NOT negates a Boolean. &, | and XOR provide integer bit operations; Boolean XOR is also supported. ^ is not an XOR spelling.

From lowest to highest precedence: optional fallback ??; OR; AND; comparisons; + - | XOR; * / MOD &; unary + - NOT; primary expressions and postfix access. Use parentheses whenever the intended grouping might surprise a reader.

count = 4
ready = count > 0 AND count < 10
PRINT ready
PRINT NOT ready
PRINT count <> 0

Conditions require BOOLEAN. Zero, an empty string, an empty collection and NONE are not Boolean false values. Write LEN(items) > 0 or use IF LET for an optional. This makes a missing value distinguishable from a present zero or empty string.

Constants

CONST MinutesPerHour = 60
CONST Greeting AS STRING = "Hello"
CONST Squares AS LIST OF INTEGER = [0, 1, 4, 9]
PRINT MinutesPerHour
PRINT Greeting
PRINT Squares[3]
copy = Squares
copy[0] = 99
PRINT Squares[0]

CONST names a compile-time value. A scalar table is an immutable flat list of scalars or one enum type. It supports reads, iteration and slicing without mutable access to its storage. Assigning it to an ordinary owned variable creates an independent value. It cannot be passed BYREF or moved with TAKE. Constants cannot execute arbitrary functions or initialize arbitrary nested owned objects.

Nonfinite floating-point results

Floating operations can produce NaN (not a number) or infinity. NaN is unequal even to itself; signed zeros compare equal. Use IsNaN, IsInfinite or IsFinite to classify results, and Finite when a nonfinite result should be a checked error.

PRINT IsNaN(SQRT(-1.0))
PRINT IsInfinite(EXP(1000.0))
TRY
    PRINT Finite(SQRT(-1.0))
CATCH problem AS NonFiniteError
    PRINT "A finite result was required"
END TRY

Floating results are not automatically operational errors. Integer conversions and integer-result operations still need a representable result. See the floating-point reference for exact policies.

From the BASIL documentation. View source ↗

Find your way around BASIL

Type to search the manual.