8.9. String
A string is a language-supplied typealias for vector<character>:
the two are the same type by strong equivalence, not a distinct sub-type.
Anything true of a vector<character> is therefore true of a string,
and the two may be used interchangeably except for their print format.
Because a string is a vector, it is runtime-sized and unbounded
like any other vector: its length is simply the length of its underlying
character sequence, which may grow (for example through the push and
append methods). There is no separate sized or bounded string type.
Growth needs a mutable receiver, though: push and append require a
var string, and a string is const by
default, so a const string (or one whose qualifier is elided) is effectively
fixed for its lifetime:
var string greeting = "hi";
call greeting.append(" there"); // greeting == "hi there"
call greeting.push('!'); // greeting == "hi there!"
const string fixed = "constant"; // const by default; it cannot grow
Although a string and a plain character array/vector
behave alike in most
respects, Gazprea still treats the two differently in a couple of places:
strings have an extra literal style and special
behavior when sent to an output stream.
(Concatenation is not one of these differences – see
Operations.)
8.9.1. Declaration
A string may be declared with the keyword string. The same rules of
vector declarations also apply to strings, which means
that all lengths are inferred:
[<qualifier>] string <identifier>;
[<qualifier>] string <identifier> = <type-expr>;
[<qualifier>] string <identifier> = <type-array>;
8.9.2. Literals
Strings can be constructed in the same way as arrays using character literals. Gazprea also provides a special syntax for string literals. A string literal is any sequence of character literals (including escape sequences) in between double quotes. For instance:
string cats_meow = "The cat said \"Meow!\"\nThat was a good day.\n";
Although strings and character arrays look similar, they are still treated differently by the compiler:
character[*] carray = ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\n'];
string vec = carray;
vector<character> charvec = carray;
carray -> std_output;
charvec -> std_output;
vec -> std_output;
prints:
[h e l l o w o r l d
][h e l l o w o r l d
]
hello world
8.9.3. Operations
As character vectors, strings have all of the same operations defined on them
as the other array data types. Remember that because a string is a
vector<character>, the concatenation operator || may be used to combine
string values with character arrays (which are a distinct array type).
Concatenation takes the kind of its receiver, the
rightmost operand: when that receiver is a string (or any vector), the whole
concatenation is a string, so "x = " || format(x) is a string and
prints as text when sent to a stream. When instead the receiver is a
character array, the result is a character array, which is implicitly
cast back to a string whenever it is stored into one (see
Character Array to/from String). Either way
var string letters = ['a', 'b'] || "cd"; below is legal – here its receiver
"cd" is a string, so the concatenation is itself a string. Every
scalar operand of || is promoted to a single-element
array of its type, so no operand need be composite and two scalars may be
concatenated: character || character yields a two-element character
array – never a string, and never a TypeError. Because the result is a
string only when the rightmost operand already is one, a scalar character on
the right, as in "ab" || 'c', gives a character array, whereas
"ab" || "c" gives a string. You may also append a slice of
characters to a string using the append method. As well, a scalar character may
be concatenated onto a string in the same way as it would be concatenated onto
an array of characters. Note that because string is a typealias for
vector<character>, concatenation may also be accomplished with the
append and push methods (see Method Calls; strings have
exactly the vector method set):
var string letters = ['a', 'b'] || "cd";
call letters.append("ef");
call letters.push('g');
letters -> std_output;
prints the following:
abcdefg
Operator precedence and associativity are specified once, for all types, in the table of operator precedence.
8.9.4. Type Casting and Implicit Casts
To see the types that a string may be cast to – explicitly with
as<>() or through an implicit cast – see the sections on
Type Casting and Implicit Casts respectively.