Thanks to Rosetta Code, I found out about Eric Lippert's comma quibbling exercise:

Write me a function that takes a non-null IEnumerable and returns a string with the following characteristics:

- If the sequence is empty then the resulting string is
`"{}"`

.- If the sequence is a single item "ABC" then the resulting string is
`"{ABC}"`

.- (3) If the sequence is the two item sequence "ABC", "DEF" then the resulting string is
`"{ABC and DEF}"`

.- (4) If the sequence has more than two items, say, "ABC", "DEF", "G", "H" then the resulting string is
`"{ABC, DEF, G and H}"`

. (Note: no Oxford comma!)

Also note “*I am particularly interested in solutions which make the
semantics of the code very clear to the code maintainer.* (emphasis
mine)”

I am going to ignore the requirement that the returned string be enclosed in braces.

Here is the straightforward Perl example that satisfies the clarity requirement:

```
#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';
use Test::More;
run();
sub run {
my @cases = (
[[], ''],
[[qw(ABC)], 'ABC'],
[[qw(ABC DEF)], 'ABC and DEF'],
[[qw(ABC DEF G H)], 'ABC, DEF, G and H'],
);
for my $x (@cases) {
my ($case, $expected) = @$x;
ok(comma_quibbling($case) eq $expected);
}
done_testing;
return;
}
sub comma_quibbling {
my $x = shift;
my $n = @$x;
$n or return '';
$n == 1 and return $x->[0];
return join(' and ' =>
# array slice and range operator
join(', ' => @$x[0 .. ($n - 2)]),
$x->[-1],
);
}
```

If the maintenance programmer has issues with the use of the array
slice and range
operator above,
s/he might use this as an opportunity to learn about them. At the point
we construct the range, we know that `$n ≥ 2`

. If `$n == 2`

, the slice
collapses to the single string `$x->[0]`

, and the join has no effect.

Now, Eric also says “*There’s no size limit on the sequence; it could be
tiny, it could be thousands of strings. But it will be finite.*” When I
get a chance, I'll compare the solution above to:

```
sub comma_quibbling {
my $x = shift;
my $n = @$x;
$n or return '';
my $r = $x->[0];
$n == 1 and return $r;
$n == 2 and return ($r .= ' and ' . $x->[1]);
for my $i (1 .. ($n - 2)) {
$r .= ', ' . $x->[$i];
}
return ($r .= ' and ' . $x->[-1]);
}
```

because I am curious.

**PS:** See also brian's post and replies to
it
on blogs.perl.org.