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.
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.
topaz check strings-templates.tpz
topaz run strings-templates.tpzThe check succeeds, and the program prints the following text.
Topaz 💎: 7title 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
| Task | Form | Result |
|---|---|---|
| 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 path | p"config/app.toml" | A path template for platform-specific normalization |
| Describe a regular expression | r"^[a-z]+$" | A regex template with reduced escaping |
| Describe a shell command | sh"tool {argument}" | A template that keeps the argument separate from command text |
| Describe a SQL query | sql"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.
| Escape | Meaning |
|---|---|
\n, \t, \r | Newline, 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 tried | Use instead |
|---|---|
text[0] or text.length | text.scalars()[0] for a nonempty string, or text.scalars().length |
| String slicing | Array operations on text.scalars() when scalar boundaries fit the task |
Backticks, single quotes, or ${expression} | Double quotes and {expression} |
html"..." or a custom tag | An 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.