Program Structure

Strings & Templates

Choose a string or tagged template, count Unicode scalars, and write multiline text.

Choose a string for text you want to print or compare. Choose a tagged template to keep path, regex, shell, or SQL data with its tag and interpolation structure.

Count characters in a string

With Topaz installed as described in First Program, save this as strings-templates.tpz.

TOPAZ
let title = "Topaz 💎"
let scalarCount = title.scalars().length
let configPath = p"config/topaz.toml"
let query = sql"SELECT name FROM projects WHERE title = {title}"

print("{title}: {scalarCount}")

Check and run it from the folder containing the file.

BASH
topaz check strings-templates.tpz
topaz run strings-templates.tpz

The check succeeds, and the program prints the following text.

Output
Topaz 💎: 7

title contains seven Unicode scalar values, one for each letter, the space, and the emoji. A scalar is one Unicode code point for text. scalars() returns these values as an Array<string>, with one scalar per element.

A visible character can contain several scalars, such as a letter followed by a combining accent. This visible unit is called a grapheme cluster. scalars() counts scalars, so its result can differ from the number of visible characters or storage bytes.

Topaz compares the scalar sequence as written. Text that looks the same can compare unequal if its scalar sequences differ.

Choose a string or template

TaskFormResult
Print or compare text"Hello, {name}"A string with the value inserted using the standard renderer
Write several lines"""..."""Multiline text with the whitespace rules below
Describe a pathp"config/app.toml"A path template for platform-specific normalization
Describe a regular expressionr"^[a-z]+$"A regex template with reduced escaping
Describe a shell commandsh"tool {argument}"A template that keeps the argument separate from command text
Describe a SQL querysql"WHERE id = {id}"A template that keeps the inserted value as a query parameter

In the example, query keeps the SQL text and title parameter separate. Creating a template does not run a query or shell command. Regex templates do not define a complete regex dialect shared by all platforms.

All four tags produce the built-in type template. Use it in type annotations, such as let query: template = sql"...". Pass a string to print. Interpolating a template into a string prints a summary such as <sql template, 1 part(s), 0 interpolation(s)>. It does not render an executable query.

You can inspect a template's tag and text segments. query.tag returns "sql". query.parts returns an Array<string> containing "SELECT name FROM projects WHERE title = " and "". These accessors do not expose interpolated values.

Write interpolation and multiline text

Interpolation inserts an expression with {expression}. Ordinary and triple-quoted strings share these escapes.

EscapeMeaning
\n, \t, \rNewline, tab, carriage return
\\, \"Backslash, double quote
\{, \}Literal braces

Triple quotes allow line breaks. When the closing quotes stand on their own indented line, every nonblank content line must start with that exact spaces-and-tabs prefix. The checker rejects a line that lacks it. Tabs are matched as characters.

The language rule removes the initial newline and closing indentation. The public 5.20.3 interpreter currently preserves them. For exact text in that interpreter, write an ordinary string with explicit escapes, such as "one\ntwo\n".

The tags p, r, sh, and sql also work with triple quotes. Place the tag directly before the opening quote. A space in p "file" causes a parse error.

Correct rejected forms

If you triedUse instead
text[0] or text.lengthtext.scalars()[0] for a nonempty string, or text.scalars().length
String slicingArray operations on text.scalars() when scalar boundaries fit the task
Backticks, single quotes, or ${expression}Double quotes and {expression}
html"..." or a custom tagAn ordinary string, or one of the four supported tags for its stated purpose

Topaz has no grapheme-cluster API or direct string-slicing syntax. The built-in name template is reserved for that type, so record template, enum template, and newtype template are rejected.

Continue with Lexical Structure & Layout for line breaks, Runtime Behavior for value rendering, or Forbidden & Deferred Forms for other syntax replacements.