523

I'm running ActiveState's 32 bit ActivePerl 5.14.2 on Windows 7. I wanted to mess around with a Git pre-commit hook to detect programs being checked in with syntax errors. (Somehow I just managed to do such a bad commit.) So as a test program I randomly jotted this:

use strict;
use warnings;

Syntax error!

exit 0;

However, it compiles and executes with no warnings, and errorlevel is zero on exit. How is this valid syntax?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bill Ruppert
  • 8,956
  • 7
  • 27
  • 44
  • 138
    Did you just prove that typing random words into perl produces working programs??!?!?!?! – Peter M Aug 10 '12 at 19:16
  • 13
    @PeterM Hardly random words. I proved I don't know enough about Perl syntax. Now I know a bit more. – Bill Ruppert Aug 12 '12 at 12:06
  • 11
    You probably want `no indirect` to stop those ones from happening – LeoNerd Mar 11 '14 at 16:39
  • 3
    This is the **most famous** perl question ever. Even better as [Schwartz's snippet](http://www.perlmonks.org/?node_id=663393): `whatever / 25 ; # / ; die "this dies!";` – clt60 Mar 06 '17 at 08:00
  • Written by linguist Larry Wall, Perl allows authors a lot of creative space. There is a sub-category in perl programming called Perl Poetry, valid Perl expressing stuff beyond computer interpretation: https://www.perlmonks.org/?node_id=1111395 – bbaassssiiee Jan 26 '21 at 20:48

6 Answers6

573

Perl has a syntax called "indirect method notation". It allows

Foo->new($bar)

to be written as

new Foo $bar

So that means

Syntax error ! exit 0;

is the same as

error->Syntax(! exit 0);

or

error->Syntax(!exit(0));

Not only is it valid syntax, it doesn't result in a run-time error because the first thing executed is exit(0).


This feature can be disabled using any of the following:

no feature qw( indirect );  # Perl 5.32+

use v5.36;                  # Perl 5.36+

no indirect;                # CPAN module
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Good explanation! But shouldn't the not operator (`!`) cause a syntax error? –  Jul 27 '12 at 20:39
  • 1
    @Hassan, Why? It's followed by an expression. – ikegami Jul 27 '12 at 20:39
  • 1
    Okay, maybe because I don't know perl, but in many other languages, that would only work if `exit`'s return value is a boolean (or something else that can be the operand of `!`), ie simply being an expression is not enough. –  Jul 27 '12 at 20:43
  • 3
    I got as far as reading it as "Syntax error !exit 0;", but I didn't think about indirect invocation. Spent a lot of time forgetting that! – Bill Ruppert Jul 27 '12 at 20:43
  • 1
    @Hassan, When `exit` returns (never), it does return a boolean, just like every single other op and sub in scalar context. That's wouldn't be a syntax error anyway, that would be a type error. – ikegami Jul 27 '12 at 20:47
  • Ahh, I see. Again, I'm pretty perl-ignorant, so sorry about that. –  Jul 27 '12 at 20:48
  • 6
    @Hassan, Think of it this way, `!exit(0)` can no more be a type error than `!$x` since neither are typed. – ikegami Jul 27 '12 at 20:51
  • 1
    Non-typed languages give me the jitters. –  Jul 27 '12 at 20:58
  • 12
    @Hassan, The language has types. Specifically, values have types. Operators and subs are simply not confined to returning specific types of values. This turns out to be *very* useful at little cost (thanks to warnings). – ikegami Jul 27 '12 at 21:25
  • 6
    @Nawaz, It's actually quite popular. It's used by everyone that constructs objects in Java and C++, and a large body of Perl programmers that uses `new Class` and `print $fh ...` instead of `Class->new(...)` and `$fh->print(...)`. I will grant you that it causes a weird error messages, though – ikegami Jul 28 '12 at 14:51
118

I don't know why, but this is what Perl makes of it:

perl -MO=Deparse -w yuck
BEGIN { $^W = 1; }
use warnings;
use strict 'refs';
'error'->Syntax(!exit(0));
yuck syntax OK

It seems that the parser thinks you're calling the method Syntax on the error-object... Strange indeed!

Wilfred Hughes
  • 29,846
  • 15
  • 139
  • 192
pavel
  • 3,488
  • 1
  • 20
  • 20
  • 3
    That's indirect method call syntax. It's (sort of) working here because the `exit(0)` is evaluated first, making the program exit before it tries to pass the result to `'error'->Syntax()`. –  Jul 27 '12 at 20:29
  • 7
    Perl seems to assume the "indirect (object) syntax", usually used like `new Class` instead of `Class->new()`. To call the method `Syntax`, the `exit` function is executed, so the run-time error never occures. – amon Jul 27 '12 at 20:30
  • 119
    Congratulations. You found a program where you need to add a semi-colon in order do get the compile to fail. – mob Jul 27 '12 at 20:32
  • `use strict; use warnings; error->Syntax(! print "hi");` Yields: Syntax Ok on perl -MO=Deparse as well, but with `use warnings` it should probably say something since it can figure out that its not being loaded. Instead it throws a runtime error "Can't locate object method .. ". –  Dec 14 '15 at 03:43
57

The reason you do not get an error is that the first executed code is

exit(0);

Because you did not have a semicolon on the first line:

Syntax error!

The compiler will guess (incorrectly) that this is a subroutine call with a not operator ! thrown in. It will then execute the arguments to this subroutine, which happens to be exit(0), at which point the program exits and sets errorlevel to 0. Nothing else is executed, so no more runtime errors are reported.

You will notice that if you change exit(0) to something like print "Hello world!" you do get an error:

Can't locate object method "Syntax" via package "error" ...

and your error level will be set:

> echo %errorlevel%
255
hugomg
  • 68,213
  • 24
  • 160
  • 246
TLP
  • 66,756
  • 10
  • 92
  • 149
  • 7
    `>The compiler will guess (incorrectly)` The compiler can't do anything incorrectly. – Liam Laverty Mar 10 '15 at 20:15
  • 16
    @LiamLaverty Yes, it can. It can guess incorrectly what the human meant. – TLP Mar 10 '15 at 22:47
  • 4
    The human is the incorrect one in the equation. The compiler can only be "correct" or "broken". It doesn't get an opinion on the definition of the language or a user's intention. – Liam Laverty Mar 10 '15 at 22:54
  • 4
    @LiamLaverty It would be a pretty neat compiler if it could guess the user's intention in this case, yes. Hence, the compiler cannot guess correctly. You might be doing some technical jargon analysis of my statement, which is, I might add, the incorrect way to read it. – TLP Mar 11 '15 at 01:01
  • Isn't it an interpretater? ;-) – Rikki Sep 03 '16 at 17:08
  • @Rikki Possibly an interpreter. :P – TLP Sep 03 '16 at 20:46
35

As noted above this is caused by the indirect method calling notation. You can warn on this:

use strict;
use warnings;
no indirect;

Syntax error!

exit 0;

Produces:

Indirect call of method "Syntax" on object "error" at - line 5.

This requires the indirect CPAN module.

You can also use no indirect "fatal"; to cause the program to die (this is what I do)

Mark Fowler
  • 1,264
  • 11
  • 20
  • From Perl 5.32 onwards you can disable indirect feature and you longer need to add a CPAN module: `use v.5:32; no feature 'indirect';` – Rsh Nov 04 '20 at 04:58
6

Try Perl 6, it seems to fulfill your expectations more readily:

===SORRY!=== Error while compiling synerror.p6
Negation metaoperator not followed by valid infix
at synerror.p6:1
------> Syntax error!⏏<EOL>
    expecting any of:
        infix
        infix stopper
moritz
  • 12,710
  • 1
  • 41
  • 63
3

In this paper, we aim to answer a long-standing open problem in the programming languages community: is it possible to smear paint on the wall without creating valid Perl?

TLDR; Hardly

Holli
  • 5,072
  • 10
  • 27