Skip to content

Commit 3308069

Browse files
committed
Rewrite for [~] trap
Closes #2124.
1 parent e25f712 commit 3308069

File tree

1 file changed

+42
-34
lines changed

1 file changed

+42
-34
lines changed

doc/Language/traps.pod6

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1789,53 +1789,61 @@ This happens partly because of the
17891789
L<single argument rule|/language/functions#Slurpy_Conventions>, and
17901790
there are other cases when this kind of a generalization may not work.
17911791
1792-
=head2 Beware of empty lists (and any other kind of element) when concatenating Bufs or Blobs.
17931792
1794-
The L<C<~> infix operator|/routine/~#(Operators)_infix_~> can be used to
1795-
concatenate L<Buf>s or L<Blob>s; we can then use this reduction operator in this
1796-
form:
1793+
=head2 Using [~] for concatenating a list of Blobs
17971794
1798-
say [~] Buf.new(0x3, 0x33), Blob.new(0x2,0x22); # OUTPUT: «Buf:0x<03 33 02 22>␤»
1795+
The L<C<~> infix operator|/routine/~#(Operators)_infix_~> can be used
1796+
to concatenate L<Str>s I<or> L<Blob>s. However, an empty list will
1797+
I<always> be reduced to an empty C<Str>. This is due to the fact that,
1798+
in the presence of a list with no elements, the
1799+
L<reduction|/language/operators#Reduction_Operators> metaoperator
1800+
returns the
1801+
L<identity element|https://en.wikipedia.org/wiki/Identity_element>
1802+
for the given operator. Identity element for C<~> is an empty string,
1803+
regardless of the kind of elements the list could be populated with.
17991804
1800-
However, an empty array will I<always> be reduced to an empty C<Str>:
1805+
=for code
1806+
my Blob @chunks;
1807+
say ([~] @chunks).perl; # OUTPUT: «""␤»
18011808
1802-
my @bufs;
1803-
say [~] @bufs; # OUTPUT: «␤»
1804-
my Buf @buffs;
1805-
say [~] @buffs; # OUTPUT: «␤»
18061809
1807-
This is due to the fact that, in the presence of a list with no elements, the
1808-
reduction operator applies the C<identity> for the operator used to reduce, C<~>
1809-
in this case. And this results in an empty string, independently of the kind of
1810-
elements the list could be populated with.
1810+
This might cause a problem if you attempt to use the result while
1811+
assuming that it is a Blob:
18111812
1812-
my Int @bufs;
1813-
say [~] @bufs; # OUTPUT: «␤»
1813+
=for code :skip-test<Documenting the error>
1814+
my Blob @chunks;
1815+
say ([~] @chunks).decode;
1816+
# OUTPUT: «No such method 'decode' for invocant of type 'Str'. Did you mean 'encode'?␤…»
18141817
1815-
This might cause a problem if an empty list enters in a situation where you are
1816-
concatenating buffers (for instance, reading from an empty file):
18171818
1818-
=for code :skip-test<Documenting the error>
1819-
my @array-of-arrays= [[], [Buf.new(0x2, 0x22), Buf.new( 0x3, 0x33)]];
1820-
my @bufs;
1821-
for @array-of-arrays -> @a {
1822-
@bufs = [~] |@bufs, | @a;
1823-
}
1824-
# OUTPUT: «(exit code 1) Cannot use a Buf as a string, but you called the Stringy method on it␤»
1819+
There are many ways to cover that case. You can avoid C<[ ]>
1820+
metaoperator altogether:
1821+
1822+
=for code
1823+
my @chunks;
1824+
# …
1825+
say Blob.new: |«@chunks; # OUTPUT: «Blob:0x<>␤»
18251826
1826-
In the code above, the first element of C<@array-of-array> will be reduced to an
1827-
empty string, causing the error when entering the second iteration.
18281827
1829-
So if you want to avoid this problem with L<Buf>s, initialize the array with an
1830-
empty element.
1828+
Alternatively, you can initialize the array with an empty Blob:
18311829
1832-
my Buf @buffs = Buf.new;
1833-
say [~] @buffs; # OUTPUT: «Buf:0x<>␤»
1830+
=for code
1831+
my @chunks = Blob.new;
1832+
# …
1833+
say [~] @chunks; # OUTPUT: «Blob:0x<>␤»
1834+
1835+
1836+
Or you can utilize L<C<||>|#infix || > operator to make it use an
1837+
empty Blob in case the list is empty:
1838+
1839+
=for code
1840+
my @chunks;
1841+
# …
1842+
say [~] @chunks || Blob.new; # OUTPUT: «Blob:0x<>␤»
18341843
1835-
That way, you can safely concatenate it later on:
18361844
1837-
my Buf @buffs = Buf.new;
1838-
say [~] |@buffs, Buf.new(0x2, 0x22); # OUTPUT: «Buf:0x<02 22>␤»
1845+
Please note that a similar issue may arise when reducing lists with
1846+
other operators.
18391847
18401848
=head1 Maps
18411849

0 commit comments

Comments
 (0)