2

I was looking at a rather inconclusive question about whether it is best to use for(;;) or while(1) when you want to make an infinite loop and I saw an interesting solution in C where you can #define "EVER" as a constant equal to ";;" and literally loop for(EVER).

I know defining an extra constant to do this is probably not the best programming practice but purely for educational purposes I wanted to see if this could be done with Perl as well.

I tried to make the Perl equivalent, but it only loops once and then exits the loop.


#!/usr/bin/perl -w

use strict;
use constant EVER => ';;';

for (EVER) {
    print "FOREVER!\n";
}

Output:

FOREVER!

Why doesn't this work in perl?

Community
  • 1
  • 1
tjwrona1992
  • 8,614
  • 8
  • 35
  • 98

4 Answers4

5

It doesn't run forever because ';;' is an ordinary string, not a preprocessor macro (Perl doesn't have an equivalent of the C preprocessor). As such, for (';;') runs a single time, with $_ set to ';;' that one time.

nobody
  • 19,814
  • 17
  • 56
  • 77
  • Ahh I see... Does this mean that there is no way to mimic this functionality in perl? At this point i'm just curious to see if it can be done. – tjwrona1992 Nov 20 '14 at 20:58
  • 2
    You could probably hack it together with a [source filter](http://perldoc.perl.org/perlfilter.html). – nobody Nov 20 '14 at 20:59
  • @tjwrona1992 You could do it with a string eval and variable interpolation. E.g. `eval "for ($ever) ..."` However, why do that when you can simply use a while loop instead? `while (EVER) ...` – TLP Nov 20 '14 at 22:47
5

C's pre-processor constants are very different from the constants in most languages.

A normal constant acts like a variable which you can only set once; it has a value which can be passed around in most of the places a variable can be, with some benefits from you and the compiler knowing it won't change. This is the type of constant that Perl's constant pragma gives you. When you pass the constant to the for operator, it just sees it as a string value, and behaves accordingly.

C, however, has a step which runs before the compiler even sees the code, called the pre-processor. This actually manipulates the text of your source code without knowing or caring what most of it means, so can do all sorts of things that you couldn't do in the language itself. In the case of #DEFINE EVER ;;, you are telling the pre-processor to replace every occurrence of EVER with ;;, so that when the actual compiler runs, it only sees for(;;). You could go a step further and define the word forever as for(;;), and it would still work.

As mentioned by Andrew Medico in comments, the closest Perl has to a pre-processor is source filters, and indeed one of the examples in the manual is an emulation of #define. These are actually even more powerful than pre-processor macros, allowing people to write modules like Acme::Bleach (replaces your whole program with whitespace while maintaining functionality) and Lingua::Romana::Perligata (interprets programs written in grammatically correct Latin), as well as more sensible features such as adding keywords and syntax for class and method declarations.

IMSoP
  • 89,526
  • 13
  • 117
  • 169
3

Andrew Medico mentioned in his comment that you could hack it together with a source filter.

I confirmed this, and here's an example.

use Filter::cpp;
#define EVER ;;
for (EVER) {
    print "Forever!\n";
}

Output:

Forever!
Forever!
Forever!
... keeps going ...

I don't think I would recommend doing this, but it is possible.

hmatt1
  • 4,939
  • 3
  • 30
  • 51
0

This is not possible in Perl. However, you can define a subroutine named forever which takes a code block as a parameter and runs it again and again:

#!/usr/bin/perl
use warnings;
use strict;

sub forever (&) {
    $_[0]->() while 1
}

forever {
    print scalar localtime, "\n";
    sleep 1;
};
choroba
  • 231,213
  • 25
  • 204
  • 289