# Binary strings

```perl
# Raku is perfectly fine with NUL *characters* in strings:
my Str $s = 'nema' ~ 0.chr ~ 'problema!';
say $s;

# However, Raku makes a clear distinction between strings
# (i.e. sequences of characters), like your name, or …
my Str $str = "My God, it's full of chars!";
# … and sequences of bytes (called Bufs), for example a PNG image, or …
my Buf $buf = Buf.new(255, 0, 1, 2, 3);
say $buf;

# Strs can be encoded into Blobs …
my Blob $this = 'round-trip'.encode('ascii');
# … and Blobs can be decoded into Strs …
my Str $that = $this.decode('ascii');

# So it's all there. Nevertheless, let's solve this task explicitly
# in order to see some nice language features:

# We define a class …
class ByteStr {
    # … that keeps an array of bytes, and we delegate some
    # straight-forward stuff directly to this attribute:
    # (Note: "has byte @.bytes" would be nicer, but that is
    # not yet implemented in Rakudo.)
    has Int @.bytes handles(< Bool elems gist push >);

    # A handful of methods …
    method clone() {
        self.new(:@.bytes);
    }

    method substr(Int $pos, Int $length) {
        self.new(:bytes(@.bytes[$pos .. $pos + $length - 1]));
    }

    method replace(*@substitutions) {
        my %h = @substitutions;
        @.bytes.=map: { %h{$_} // $_ }
    }
}

# A couple of operators for our new type:
multi infix:<cmp>(ByteStr $x, ByteStr $y) { $x.bytes.join cmp $y.bytes.join }
multi infix:<~>  (ByteStr $x, ByteStr $y) { ByteStr.new(:bytes(|$x.bytes, |$y.bytes)) }

# create some byte strings (destruction not needed due to garbage collection)
my ByteStr $b0 = ByteStr.new;
my ByteStr $b1 = ByteStr.new(:bytes( |'foo'.ords, 0, 10, |'bar'.ords ));

# assignment ($b1 and $b2 contain the same ByteStr object afterwards):
my ByteStr $b2 = $b1;

# comparing:
say 'b0 cmp b1 = ', $b0 cmp $b1;
say 'b1 cmp b2 = ', $b1 cmp $b2;

# cloning:
my $clone = $b1.clone;
$b1.replace('o'.ord => 0);
say 'b1 = ', $b1;
say 'b2 = ', $b2;
say 'clone = ', $clone;

# to check for (non-)emptiness we evaluate the ByteStr in boolean context:
say 'b0 is ', $b0 ?? 'not empty' !! 'empty';
say 'b1 is ', $b1 ?? 'not empty' !! 'empty';

# appending a byte:
$b1.push: 123;
say 'appended = ', $b1;

# extracting a substring:
my $sub = $b1.substr(2, 4);
say 'substr = ', $sub;

# replacing a byte:
$b2.replace(102 => 103);
say 'replaced = ', $b2;

# joining:
my ByteStr $b3 = $b1 ~ $sub;
say 'joined = ', $b3;
```

Note: The ␀ represents a NUL byte.

```
nema␀problema!
Buf:0x<ff 00 01 02 03>
round-trip
b0 cmp b1 = Less
b1 cmp b2 = Same
b1 = [102 0 0 0 10 98 97 114]
b2 = [102 0 0 0 10 98 97 114]
clone = [102 111 111 0 10 98 97 114]
b0 is empty
b1 is not empty
appended = [102 0 0 0 10 98 97 114 123]
substr = [0 0 10 98]
replaced = [103 0 0 0 10 98 97 114 123]
joined = [103 0 0 0 10 98 97 114 123 0 0 10 98]
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://trizen.gitbook.io/perl6-rosettacode/programming_tasks/b/binary_strings.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
