Concatenation Written
Joins two values as strings — and sits three precedence levels looser than arithmetic, which is where the surprises come from.
~- R1It stringifies both operands and joins them
- R2A list stringifies to its elements joined with a space
- R3It is at concatenation, looser than arithmetic and replication
- R4
~=appends in place - R5It metaoperates like any other infix
- T1
~is three different operators depending on position - T2An undefined operand is a warning in Rakudo and an error in Raku++
- T3Concatenating in a loop is quadratic
~ glues its two operands together as strings. Like +, it does not require the right types; it imposes them.
Rules #
R1 It stringifies both operands and joins them
Each side is put in string context — .Str — so anything with a string form concatenates without a cast.
say "a" ~ "b"; say 1 ~ 2;
ab
121 ~ 2 is "12", not 3. The operator decides the context, not the operands.
R2 A list stringifies to its elements joined with a space
This is .Str on a list, not a rule of ~. It is why building a message out of a list rarely gives what you meant.
say (1, 2) ~ "x";
1 2xR3 It is at concatenation, looser than arithmetic and replication
The chips above place ~ at concatenation 10/27. Multiplicative (7), additive (8) and replication (9) are all tighter, so arithmetic on either side happens first and you very rarely need parentheses around it.
say "n=" ~ 1 + 2; say "x" x 2 ~ "y";
n=3
xxyBoth read the way you want: "n=" ~ (1 + 2) and ("x" x 2) ~ "y". That ordering is deliberate — concatenation is the operator you almost always want to apply last.
R4 ~= appends in place
my $s = "a"; $s ~= "b"; say $s;
abR5 It metaoperates like any other infix
[~] reduces a list with it, Z~ zips pairwise, X~ crosses.
say [~] <a b c>;
say ("a", "b") Z~ ("1", "2");
abc
(a1 b2)Traps #
T1 ~ is three different operators depending on position
The same character is an infix here, a prefix elsewhere, and part of several compound spellings. They are unrelated in meaning and in precedence.
| Spelling | Category | Meaning | |
|---|---|---|---|
$a ~ $b | infix, concatenation (10) | concatenate | |
~$a | prefix, symbolic unary (5) | coerce to Str | |
$a ~~ $b | infix, chaining (15) | smartmatch | |
$a ~& $b, ~\ | , ~^ | infix | string bitwise ops |
~$a is the idiomatic stringification, and being at symbolic-unary precedence it binds tighter than everything except method calls and **.
my @a = 1, 2, 3; say ~@a; say (~@a).WHAT;
1 2 3
(Str)T2 An undefined operand is a warning in Rakudo and an error in Raku++
Rakudo warns Use of Nil in string context (or uninitialized value) and treats the operand as the empty string. Raku++ diverges, and not gracefully:
say Nil ~ "x";Rakudo: warns, then prints x
Raku++: No such method 'Nil' for invocant of type 'Str'
"a" ~ Any is the same story: Rakudo warns and prints a, Raku++ prints a silently. Either way, an undefined value reaching ~ means a missing // default somewhere upstream.
T3 Concatenating in a loop is quadratic
$s ~= … builds a new string each time. For anything longer than a few hundred appends, push onto an array and .join once.
my @parts;
@parts.push("x$_") for ^5;
say @parts.join(",");
x0,x1,x2,x3,x4See also #
prefix:<~>— coercion toStrinfix:<x>— string replication, one level tighterinfix:<+>— the numeric counterpart, three levels tighter
Observed behaviour #
Each expression below was executed by both interpreters when this page was built; the results are recorded, not written. The operands are chosen to cross the boundaries that catch people out: string against number, a list where a scalar was meant, a boolean, an undefined value, and an exact rational.
1 of 7 of these disagree between Raku++ and Rakudo — shown side by side below. A disagreement here is a defect report waiting to be written, not a documented rule.
| Expression | Raku++ | Rakudo |
|---|---|---|
1 ~ 2 | Str | 12 | |
"a" ~ "b" | Str | ab | |
1 ~ "2" | Str | 12 | |
(1, 2) ~ (3, 4, 5) | Str | 1 23 4 5 | |
True ~ False | Str | TrueFalse | |
Nil ~ 1 | ERR No such method 'Nil' for invocant of type 'Str' | Str | 1 |
1/2 ~ 1/3 | Str | 0.50.333333 | |