refactor(lang): rename the str type (and stringify builtin) to string
Expand the abbreviated string type and its conversion builtin to the full
word everywhere:
str -> string (the immutable-string type)
str(x) -> str -> string(x) -> string (the stringify builtin;
what `{…}` interpolation calls)
Types are recognized by identifier, and llty maps both spellings to LLVM
`ptr`, so this is an atomic source rewrite: type annotations, the Ludic
type tags, the builtin name/dispatch, and the interpolation desugar, plus
the grammars, LSP, docs (type-str -> type-string, fn-str -> fn-string), and
inventory. int/bool stay (universally accepted, like Math).
Reseeded; C-free fixpoint holds; all suites green (45/24/29); site + check.py OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
4c48077d68
commit
b7745a4600
70 changed files with 207 additions and 207 deletions
|
|
@ -4,7 +4,7 @@ name: arg
|
|||
category: builtins
|
||||
kind: builtin
|
||||
tokens: arg
|
||||
sig: arg(i) -> str
|
||||
sig: arg(i) -> string
|
||||
tip: The i-th command-line argument as a string.
|
||||
order: 50
|
||||
---
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ name: getenv
|
|||
category: builtins
|
||||
kind: builtin
|
||||
tokens: getenv
|
||||
sig: getenv(name) -> str
|
||||
sig: getenv(name) -> string
|
||||
tip: Read an environment variable, returning empty when it is unset.
|
||||
order: 23
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
---
|
||||
id: fn-str
|
||||
name: str
|
||||
id: fn-string
|
||||
name: string
|
||||
category: builtins
|
||||
kind: builtin
|
||||
tokens: str
|
||||
sig: str(x) -> str
|
||||
tokens: string
|
||||
sig: string(x) -> string
|
||||
tip: Convert an int, bool, or fixed value to text; a string passes through unchanged.
|
||||
order: 1
|
||||
---
|
||||
|
||||
Converts a value to its textual form: an <code>int</code>, <code>bool</code>, or <code>fixed</code> becomes a string, and a value that is already a string is returned unchanged. This is what backtick <code>`{…}`</code> interpolation calls under the hood, so most of the time you can interpolate directly instead of calling <code>str</code> yourself. Reach for the explicit form when you need to store or pass around the text, or build a string in pieces. The result can be printed, drawn with <code>Screen.draw_text</code>, or concatenated.
|
||||
Converts a value to its textual form: an <code>int</code>, <code>bool</code>, or <code>fixed</code> becomes a string, and a value that is already a string is returned unchanged. This is what backtick <code>`{…}`</code> interpolation calls under the hood, so most of the time you can interpolate directly instead of calling <code>string</code> yourself. Reach for the explicit form when you need to store or pass around the text, or build a string in pieces. The result can be printed, drawn with <code>Screen.draw_text</code>, or concatenated.
|
||||
|
||||
Parameters:
|
||||
- `x` — the value to convert to text
|
||||
|
|
@ -19,7 +19,7 @@ program LabelValue {
|
|||
var score: int = 250
|
||||
|
||||
handler ReportScore phase Start {
|
||||
let label = str(score)
|
||||
let label = string(score)
|
||||
print(label)
|
||||
}
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ program ResolveField {
|
|||
handler Inspect phase Update {
|
||||
let position_property = world_prop_id("Position")
|
||||
let column_field = world_field_id(position_property, "column")
|
||||
Screen.status(str(column_field))
|
||||
Screen.status(string(column_field))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ program ReadField {
|
|||
let column_field = world_field_id(position_property, "column")
|
||||
for (position) in query [Position, {Player}] {
|
||||
let value = world_get(self(), position_property, column_field)
|
||||
Screen.status(str(value))
|
||||
Screen.status(string(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ program ResolveModel {
|
|||
|
||||
handler Inspect phase Update {
|
||||
let player_model = world_model_id("Player")
|
||||
Screen.status(str(player_model))
|
||||
Screen.status(string(player_model))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ program ResolveProperty {
|
|||
|
||||
handler Inspect phase Update {
|
||||
let position_property = world_prop_id("Position")
|
||||
Screen.status(str(position_property))
|
||||
Screen.status(string(position_property))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ program ModComponent {
|
|||
handler Boot phase Start {
|
||||
spawn Hero { Position { column: 4, row: 4 } }
|
||||
let stamina_property = world_register_prop("Stamina", 1)
|
||||
Screen.status(str(stamina_property))
|
||||
Screen.status(string(stamina_property))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ program SnapshotOut {
|
|||
if Input.key() == 's' {
|
||||
let buffer = bytes(4096)
|
||||
let written = world_save(buffer)
|
||||
Screen.status(str(written))
|
||||
Screen.status(string(written))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ program Reinforcements {
|
|||
if Input.key() == ' ' {
|
||||
let enemy_model = world_model_id("Enemy")
|
||||
let new_enemy = world_spawn(enemy_model)
|
||||
Screen.status(str(new_enemy))
|
||||
Screen.status(string(new_enemy))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@ The access operators reach into a compound value. `value.field` reads or writes
|
|||
```ludic
|
||||
let head_column: int = segments[0].column
|
||||
segments[0].column = head_column + 1
|
||||
let extension: str = file_name[len(file_name) - 4 .. len(file_name)]
|
||||
let extension: string = file_name[len(file_name) - 4 .. len(file_name)]
|
||||
```
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ tip: Compare two values and yield a bool; on strings == compares contents.
|
|||
order: 1
|
||||
---
|
||||
|
||||
The comparison operators — `==` (equal), `!=` (not equal), `<`, `<=`, `>`, `>=` — take two values and yield a `bool`, the kind of test an `if` or `where` clause wants. On `str` values `==` and `!=` compare <b>by content</b>, so `direction == "left"` checks the characters, not the pointer (a comparison against `null` stays a pointer test). Comparison binds looser than arithmetic and looser than the bitwise operators, so `flags & MASK == 0` reads as `(flags & MASK) == 0` with no parentheses needed. Chain several conditions together with `and` / `or`.
|
||||
The comparison operators — `==` (equal), `!=` (not equal), `<`, `<=`, `>`, `>=` — take two values and yield a `bool`, the kind of test an `if` or `where` clause wants. On `string` values `==` and `!=` compare <b>by content</b>, so `direction == "left"` checks the characters, not the pointer (a comparison against `null` stays a pointer test). Comparison binds looser than arithmetic and looser than the bitwise operators, so `flags & MASK == 0` reads as `(flags & MASK) == 0` with no parentheses needed. Chain several conditions together with `and` / `or`.
|
||||
|
||||
```ludic
|
||||
if current_health <= 0 { become GameOver }
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ tip: A backtick string with {expr} holes, each stringified and concatenated.
|
|||
order: 7
|
||||
---
|
||||
|
||||
A backtick string `` `…` `` is an interpolated string: any `{expr}` hole inside it is evaluated, converted to text, and concatenated with the surrounding literal parts. Numbers, `bool`s, and `fixed` values are stringified automatically and `str` values pass through, so `` `score: {score}` `` desugars to `"score: " + str(score)`. It is the readable way to build a message from mixed pieces without hand-writing a `+` chain. Write a literal brace with `{{` or `}}`.
|
||||
A backtick string `` `…` `` is an interpolated string: any `{expr}` hole inside it is evaluated, converted to text, and concatenated with the surrounding literal parts. Numbers, `bool`s, and `fixed` values are stringified automatically and `string` values pass through, so `` `score: {score}` `` desugars to `"score: " + string(score)`. It is the readable way to build a message from mixed pieces without hand-writing a `+` chain. Write a literal brace with `{{` or `}}`.
|
||||
|
||||
```ludic
|
||||
let status_line: str = `score {score} — health {current_health}/{maximum_health}`
|
||||
let status_line: string = `score {score} — health {current_health}/{maximum_health}`
|
||||
Screen.status(status_line)
|
||||
print(`wave {wave_number} incoming`)
|
||||
```
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ tip: Integer, hex, character, string, boolean, and null-pointer literals.
|
|||
order: 8
|
||||
---
|
||||
|
||||
Literals are the fixed values you write directly in source. `42` is a decimal `int` and `0x1E90FF` is a hex `int` — hex is how colors are written, so a raw color is just an integer. A number with a decimal point (`1.5`) is a `fixed`. `'w'` is a character literal, an `int` code point handy for comparing against `Input.key()`. `"text"` is a `str`, `true` / `false` are `bool`s, and `null` is the null-pointer literal used to test an unset record, slice, or `ptr` field.
|
||||
Literals are the fixed values you write directly in source. `42` is a decimal `int` and `0x1E90FF` is a hex `int` — hex is how colors are written, so a raw color is just an integer. A number with a decimal point (`1.5`) is a `fixed`. `'w'` is a character literal, an `int` code point handy for comparing against `Input.key()`. `"text"` is a `string`, `true` / `false` are `bool`s, and `null` is the null-pointer literal used to test an unset record, slice, or `ptr` field.
|
||||
|
||||
```ludic
|
||||
let sky_color: int = 0x1E90FF
|
||||
let banner: str = "GAME OVER"
|
||||
let banner: string = "GAME OVER"
|
||||
if Input.key() == 'w' { row = row - 1 }
|
||||
if next_segment == null { is_tail = true }
|
||||
```
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ program Physics {
|
|||
handler MeasureSpeed phase Update {
|
||||
for (velocity) in query [Velocity, {Projectile}] {
|
||||
let speed = c_hypot(a: fx(velocity.delta_x), b: fx(velocity.delta_y))
|
||||
Screen.status(str(flr(speed)))
|
||||
Screen.status(string(flr(speed)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ name: System.arg
|
|||
category: system
|
||||
kind: namespace-method
|
||||
tokens: System.arg
|
||||
sig: System.arg(i) -> str
|
||||
sig: System.arg(i) -> string
|
||||
tip: A command-line argument by index.
|
||||
order: 0
|
||||
ns: System
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ name: System.env
|
|||
category: system
|
||||
kind: namespace-method
|
||||
tokens: System.env
|
||||
sig: System.env(name) -> str
|
||||
sig: System.env(name) -> string
|
||||
tip: Read an environment variable.
|
||||
order: 4
|
||||
ns: System
|
||||
|
|
|
|||
|
|
@ -4,4 +4,4 @@ title: Text
|
|||
order: 6
|
||||
---
|
||||
|
||||
String queries and building over <code>str</code> values — length, character access, substrings, search, prefix/suffix tests, and int conversion. Arguments are positional. Strings are byte sequences, so indices and lengths count bytes.
|
||||
String queries and building over <code>string</code> values — length, character access, substrings, search, prefix/suffix tests, and int conversion. Arguments are positional. Strings are byte sequences, so indices and lengths count bytes.
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ Parameters:
|
|||
|
||||
```ludic
|
||||
program FirstIsDigit {
|
||||
var entry: str = "7up"
|
||||
var entry: string = "7up"
|
||||
|
||||
handler Check phase Update {
|
||||
let c = Text.char_at(entry, 0)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ name: Text.concat
|
|||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.concat
|
||||
sig: Text.concat(a, b) -> str
|
||||
sig: Text.concat(a, b) -> string
|
||||
tip: Join two strings into a new one.
|
||||
order: 8
|
||||
ns: Text
|
||||
|
|
@ -19,7 +19,7 @@ Parameters:
|
|||
|
||||
```ludic
|
||||
program Greeting {
|
||||
var name: str = "world"
|
||||
var name: string = "world"
|
||||
|
||||
handler Build phase Update {
|
||||
let line = Text.concat("hello ", name) # "hello world"
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ Parameters:
|
|||
|
||||
```ludic
|
||||
program Filter {
|
||||
var line: str = "error: disk full"
|
||||
var line: string = "error: disk full"
|
||||
|
||||
handler Scan phase Update {
|
||||
if Text.contains(line, "error") {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ Parameters:
|
|||
|
||||
```ludic
|
||||
program IsImage {
|
||||
var filename: str = "hero.png"
|
||||
var filename: string = "hero.png"
|
||||
|
||||
handler Classify phase Update {
|
||||
let png = Text.ends_with(filename, ".png") # true
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ Parameters:
|
|||
|
||||
```ludic
|
||||
program Guess {
|
||||
var answer: str = "swordfish"
|
||||
var attempt: str = "swordfish"
|
||||
var answer: string = "swordfish"
|
||||
var attempt: string = "swordfish"
|
||||
|
||||
handler Check phase Update {
|
||||
if Text.equals(attempt, answer) {
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ name: Text.from_int
|
|||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.from_int
|
||||
sig: Text.from_int(n) -> str
|
||||
sig: Text.from_int(n) -> string
|
||||
tip: Render an integer as a string.
|
||||
order: 10
|
||||
ns: Text
|
||||
member: from_int
|
||||
---
|
||||
|
||||
Returns the decimal text of the integer <code>n</code> — <code>Text.from_int(1234)</code> is <code>"1234"</code>, and negatives keep their sign. It is the same conversion as the bare <code>str(n)</code> and the inverse of <code>Text.to_int</code>. Use it when you need a number as characters — to measure its width, concatenate it, or store it — though drawing a number to the screen is better done with <code>Screen.draw_number</code>.
|
||||
Returns the decimal text of the integer <code>n</code> — <code>Text.from_int(1234)</code> is <code>"1234"</code>, and negatives keep their sign. It is the same conversion as the bare <code>string(n)</code> and the inverse of <code>Text.to_int</code>. Use it when you need a number as characters — to measure its width, concatenate it, or store it — though drawing a number to the screen is better done with <code>Screen.draw_number</code>.
|
||||
|
||||
Parameters:
|
||||
- `n` — the integer to render
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ Parameters:
|
|||
|
||||
```ludic
|
||||
program KeyValue {
|
||||
var pair: str = "hp=42"
|
||||
var pair: string = "hp=42"
|
||||
|
||||
handler Parse phase Update {
|
||||
let eq = Text.index_of(pair, "=") # 2
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ name: Text.join
|
|||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.join
|
||||
sig: Text.join(parts, sep) -> str
|
||||
sig: Text.join(parts, sep) -> string
|
||||
tip: Join a list of strings with a separator.
|
||||
order: 18
|
||||
ns: Text
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ Parameters:
|
|||
|
||||
```ludic
|
||||
program NameWidth {
|
||||
var label: str = "player one"
|
||||
var label: string = "player one"
|
||||
|
||||
handler Draw phase Render {
|
||||
let width = Text.length(label) * 6 # 6 px per glyph
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ name: Text.lower
|
|||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.lower
|
||||
sig: Text.lower(s) -> str
|
||||
sig: Text.lower(s) -> string
|
||||
tip: A lowercased copy of a string.
|
||||
order: 12
|
||||
ns: Text
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ name: Text.pad_left
|
|||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.pad_left
|
||||
sig: Text.pad_left(s, width) -> str
|
||||
sig: Text.pad_left(s, width) -> string
|
||||
tip: Pad with spaces on the left to a width.
|
||||
order: 15
|
||||
ns: Text
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ name: Text.pad_right
|
|||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.pad_right
|
||||
sig: Text.pad_right(s, width) -> str
|
||||
sig: Text.pad_right(s, width) -> string
|
||||
tip: Pad with spaces on the right to a width.
|
||||
order: 16
|
||||
ns: Text
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ name: Text.repeat
|
|||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.repeat
|
||||
sig: Text.repeat(s, n) -> str
|
||||
sig: Text.repeat(s, n) -> string
|
||||
tip: A string repeated n times.
|
||||
order: 14
|
||||
ns: Text
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ name: Text.replace
|
|||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.replace
|
||||
sig: Text.replace(s, from, to) -> str
|
||||
sig: Text.replace(s, from, to) -> string
|
||||
tip: Replace every occurrence of a substring.
|
||||
order: 19
|
||||
ns: Text
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ name: Text.slice
|
|||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.slice
|
||||
sig: Text.slice(s, a, b) -> str
|
||||
sig: Text.slice(s, a, b) -> string
|
||||
tip: A substring covering bytes [a, b).
|
||||
order: 2
|
||||
ns: Text
|
||||
|
|
@ -20,7 +20,7 @@ Parameters:
|
|||
|
||||
```ludic
|
||||
program FirstWord {
|
||||
var line: str = "hello world"
|
||||
var line: string = "hello world"
|
||||
|
||||
handler Split phase Update {
|
||||
let space = Text.index_of(line, " ") # 5
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ name: Text.split
|
|||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.split
|
||||
sig: Text.split(s, sep) -> []str
|
||||
sig: Text.split(s, sep) -> []string
|
||||
tip: Split a string on a separator into a list.
|
||||
order: 17
|
||||
ns: Text
|
||||
member: split
|
||||
---
|
||||
|
||||
Splits <code>s</code> at every occurrence of the non-empty separator <code>sep</code> and returns the pieces as a <code>[]str</code> — the inverse of <code>Text.join</code>. Adjacent separators yield empty pieces, and a string with no separator returns a one-element list holding the whole string. Use it to parse CSV rows, command arguments, or delimited save data.
|
||||
Splits <code>s</code> at every occurrence of the non-empty separator <code>sep</code> and returns the pieces as a <code>[]string</code> — the inverse of <code>Text.join</code>. Adjacent separators yield empty pieces, and a string with no separator returns a one-element list holding the whole string. Use it to parse CSV rows, command arguments, or delimited save data.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ Parameters:
|
|||
|
||||
```ludic
|
||||
program Command {
|
||||
var input: str = "/say hello"
|
||||
var input: string = "/say hello"
|
||||
|
||||
handler Parse phase Update {
|
||||
if Text.starts_with(input, "/say ") {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ Parameters:
|
|||
|
||||
```ludic
|
||||
program ParseAmount {
|
||||
var typed: str = "250"
|
||||
var typed: string = "250"
|
||||
|
||||
handler Apply phase Update {
|
||||
let gold = Text.to_int(typed) # 250
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ name: Text.trim
|
|||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.trim
|
||||
sig: Text.trim(s) -> str
|
||||
sig: Text.trim(s) -> string
|
||||
tip: A copy with surrounding whitespace removed.
|
||||
order: 13
|
||||
ns: Text
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ name: Text.upper
|
|||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.upper
|
||||
sig: Text.upper(s) -> str
|
||||
sig: Text.upper(s) -> string
|
||||
tip: An uppercased copy of a string.
|
||||
order: 11
|
||||
ns: Text
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ tip: A 64-bit signed integer for values that overflow a 32-bit int.
|
|||
order: 1
|
||||
---
|
||||
|
||||
`long` is a 64-bit signed integer — reach for it when a value would overflow the 32-bit `int`: a 64-bit hash or content id, an accumulated playtime in milliseconds, a large score or currency total, packed bit flags. Arithmetic (`+ - * / %`), comparison, and the bitwise operators all work on it, and mixing an `int` with a `long` promotes the `int` to 64 bits automatically — so `big * count` where `big` is a `long` computes in 64 bits and does not overflow. `print` and `str` render all its digits.
|
||||
`long` is a 64-bit signed integer — reach for it when a value would overflow the 32-bit `int`: a 64-bit hash or content id, an accumulated playtime in milliseconds, a large score or currency total, packed bit flags. Arithmetic (`+ - * / %`), comparison, and the bitwise operators all work on it, and mixing an `int` with a `long` promotes the `int` to 64 bits automatically — so `big * count` where `big` is a `long` computes in 64 bits and does not overflow. `print` and `string` render all its digits.
|
||||
|
||||
One limit to know: a numeric *literal* is still parsed as a 32-bit `int`, so build large values by widening — assign a smaller literal into a `long` and compute from there (`let m: long = 1000000` then `m * m`) rather than writing a 10-digit literal directly.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
---
|
||||
id: type-str
|
||||
name: str
|
||||
category: types
|
||||
kind: type
|
||||
tokens: str
|
||||
sig: str
|
||||
tip: An immutable string — compared by content, sliceable, and interpolatable.
|
||||
order: 3
|
||||
---
|
||||
|
||||
`str` is an immutable string of bytes. Strings are true <b>values</b>: `+` concatenates two of them and `==` / `!=` compare them <b>by content</b>, not by pointer, so `"go" + direction == "goleft"` behaves as written. Index a single byte with `text[index]` (an `int` code point), take a fresh substring with `text[start..end]`, and measure the byte length with `len(text)`. The readable way to build one is backtick interpolation — `` `score: {score}` `` — which stringifies each `{…}` hole and concatenates.
|
||||
|
||||
```ludic
|
||||
let player_name: str = "Ada"
|
||||
let greeting: str = `hello {player_name}, score {score}`
|
||||
if player_name == "Ada" { Screen.status(greeting) }
|
||||
```
|
||||
18
docs/language/types/type-string.md
Normal file
18
docs/language/types/type-string.md
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
id: type-string
|
||||
name: string
|
||||
category: types
|
||||
kind: type
|
||||
tokens: string
|
||||
sig: string
|
||||
tip: An immutable string — compared by content, sliceable, and interpolatable.
|
||||
order: 3
|
||||
---
|
||||
|
||||
`string` is an immutable string of bytes. Strings are true <b>values</b>: `+` concatenates two of them and `==` / `!=` compare them <b>by content</b>, not by pointer, so `"go" + direction == "goleft"` behaves as written. Index a single byte with `text[index]` (an `int` code point), take a fresh substring with `text[start..end]`, and measure the byte length with `len(text)`. The readable way to build one is backtick interpolation — `` `score: {score}` `` — which stringifies each `{…}` hole and concatenates.
|
||||
|
||||
```ludic
|
||||
let player_name: string = "Ada"
|
||||
let greeting: string = `hello {player_name}, score {score}`
|
||||
if player_name == "Ada" { Screen.status(greeting) }
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue