Why are "1...2" and "1....2" not syntax errors?
Asked Answered
U

2

22

Consider:

use 5.016;
use warnings "all";
use Data::Dumper;

my @abc = (1, 2, 3);

my @bbb = @abc[1..2];
my @ccc = @abc[1...2];
my @ddd = @abc[1....2];

say Dumper "@bbb"; # Output: '2 3'
say Dumper "@ccc"; # Output: '2 3'
say Dumper "@ddd"; # Output: ''

Why aren't there any syntax errors in the code above?

What do 1...2 (three dots) and 1....2 (four dots) mean here?

Unheardof answered 11/9, 2023 at 9:51 Comment(0)
D
40

1..2 is tokenized as 1 .. 2, and parsed as a range operator with two integer constant operands. When evaluated, it is evaluated in list context, and it produces the integers from 1 to 2 inclusive.

1...2 is tokenized as 1 ... 2, and parsed as a range operator with two integer constant operands. ... is different than .. in scalar context, but they're the same in list context.

1....2 is tokenized as 1 ... .2, and parsed as a range operator with two constant operands. When evaluated, it is evaluated in list context, and it produces the integers from 1 to 0.2 inclusive, which is to say it produces nothing.


A side note:

When tokenizing, Perl normally gobbles up as many characters as it can with no regard as to what follows. One exception is that a . will never be included in a numeric literal if followed by another ..

This means that 1..2 is always tokenized as 1, .., 2 and never 1. .2 or 1. . 2.

This means that 1...2 is always tokenized as 1, ..., 2 and never 1., .., 2 or 1, .., .2.

This also means that 1.....2 will never be tokenized as 1. ... .2 even though that would prevent the parser from throwing a syntax error.

(Thanks @Dada for helping me correct this.)


A side note:

At least some constant ranges are flattened into an array constant.

1..2 in list context and 1...2 in list context both compile to a two-element array constant, just like 1, 2.

1....2 in list context compiles to an empty array constant.

Dinghy answered 11/9, 2023 at 13:56 Comment(1)
See also Range Operator, in: Perl in a NutshellKbp
M
12

If you give Perl the option -MO=Deparse it will say how Perl parse your code.

The three-dot form (1...2) parses as (1..2). This is unexpected to me, but I assume it is a side effect of being able to parse both the two-dot and three-dot forms of the flip-flop operator.

The four-dot form parses as (1 .. .2). This is an empty range, so your array slice is also empty.

Madly answered 11/9, 2023 at 12:31 Comment(2)
Re "The three-dot form (1...2) parses as (1..2).", No. They are parsed differently, but they compile to the same the thing in this case. Specifically, they compile to a constant array of two elements, just like 1, 2. /// Re "it will say how Perl parse your code.", Deparse is a decompiler. It can help show how Perl understand codes, but it doesn't actually show how code is parsed. That's why 1..2, 1...2 and 1, 2 all Deparse as 1, 2. (They don't Deparse as 1..2 as you claim.)Dinghy
-MO=Deparse is really a good thing I haven't used before. It helped me understand the code. Thank you.Unheardof

© 2022 - 2024 — McMap. All rights reserved.