brace notation warning
Brace notation extract and assign are much faster than conventional alternatives for reading and writing single bytes in a string.  But either will cause memory faults if used on empty strings, and brace notation assign will cause obscure and disastrous results if used to write beyond the current end of a string.  The byte written will overwrite the zero terminator, another variable, or, even worse, a memory allocation header.   In most cases, the program and probably the program development environment will crash.

Therefore, brace notation assign in particular should be considered an advanced feature for experienced programmers when the fastest possible string processing is needed.

When programs run in the development environment with bounds checking enabled, dangerous brace notation accesses are prevented. Instead, recoverable out-of-bounds errors occur. If bounds checking is disabled, the program and the environment will probably crash.   Programs that use brace notation must be designed so improper brace notation accesses are impossible.

Internally, every string is represented by a handle, an XLONG value at a fixed location in memory.  It contains the address of the string data, which is elsewhere in memory.  Empty strings are represented by a handle containing 0.  Any attempt to access an empty string element is therefore an error, usually one that will cause a segment violation or memory fault.

Accesses beyond the end of strings return invalid values, and may cause segment violations.  LEN(theString$) returns the offset of the null character that terminates strings, so as long as the length of the string is non-zero, offsets up to LEN(theString$) are valid.  Be careful not to write over the zero terminator at offset LEN(theString$)!

To prevent access of empty strings, test for contents first, as in the following example:

  IF a$ THEN firstChar = a${0} ELSE firstChar = -1

To prevent an attempted read or write from the null terminator or beyond, the brace notation offset should be limited to the length of the string minus one, as in either of the following two-line examples:

  stringLength = LEN (a$)
  IF (n < stringLength) THEN thisChar = a${n} ELSE thisChar = -1

  maxOffset = UBOUND (a$)
  IF (n <= maxOffset) THEN thisChar = a${n} ELSE thisChar = -1

The following examples illustrate a similar strategy to prevent improper brace notation accesses in loops.  The first calculates a hash value for a symbol, and the second converts a symbol to lower case with a UBYTE conversion array.  UBOUND() returns -1 for empty strings, so these examples will not accidentally attempt to access empty strings - which cause runtime memory access violations.

  hash = 0
  FOR i = 0 TO UBOUND (symbol$)
    hash = hash + symbol${i}
  NEXT i
  i = 0
  z = UBOUND (symbol$)
  DO WHILE (i <= z)
    symbol${i} = charsetUpperToLower[symbol${i}]
    INC i