10

I'm sure there are several ways of getting the value 'bar' to interpolate in the <> below, but what is the cleanest way, and why?

use constant FOO => 'bar';

my $msg = <<EOF;
Foo is currently <whatever goes here to expand FOO>
EOF
gcbenison
  • 11,723
  • 4
  • 44
  • 82

5 Answers5

15

There are two kinds of here-docs:

  • <<'END', which behaves roughly like a single quoted string (but no escapes), and
  • <<"END", also <<END, which behaves like a double quoted string.

To interpolate a value in a double quoted string use a scalar variable:

my $foo = "bar";
my $msg = "Foo is currently $foo\n";

Or use the arrayref interpolation trick

use constant FOO => "bar";
my $msg = "Foo is currently @{[ FOO ]}\n";

You could also define a template language to substitute in the correct value. This may or may not be better depending on your problem domain:

my %vars = (FOO => "bar");
my $template = <<'END';
Foo is currently %FOO%;
END

(my $msg = $template) =~ s{%(\w+)%}{$vars{$1} // die "Unknown variable $1"}eg;
amon
  • 57,091
  • 2
  • 89
  • 149
9

The problem with a lot of the CPAN modules that do a nicer job of constants than the use constant pragma is that they just aren't part of the standard Perl package. Unfortunately, it can be very difficult to download CPAN modules on machines you might not own.

Therefore, I've just decided to stick to use constant until Perl starts to include something like Readonly as part of its standard modules (and only when distros like RedHat and Solaris decide to update to those versions of Perl. I'm still stuck with 5.8.8 on our production servers.)

Fortunately, you can interpolate constants defined with use constant if you know the arcane and mystical incantations that has been passed down from hacker to hacker.

Put @{[...]} around the constant. This can also work with methods from classes too:

use 5.12.0;
use constant {
    FOO => "This is my value of foo",
};

my $data =<<EOT;
this is my very long
value of my variable that
also happens to contain
the value of the constant
'FOO' which has the value
of @{[FOO]}
EOT

say $data;

Output:

this is my very long
value of my variable that
also happens to contain
the value of the constant
'FOO' which has the value
of This is my value of foo

Using a method:

say "The employee's name is @{[$employee->Name]}";

Aside:

There is also another way to use constants that I used to employ before use constant was around. It went like this:

*FOO = \"This is my value of foo";
our $FOO;

my $data =<<EOT;
this is my very long
value blah, blah, blah $FOO
EOT

say $data;

You can use $FOO as any other scalar value, and it can't be modified. You try to modify the value and you get:

Modification of a read-only value attempted at ...

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
David W.
  • 105,218
  • 39
  • 216
  • 337
  • 1
    "Unfortunately, it can be very difficult to download CPAN modules on machines you might not own" - it's amazing how much influence that can have in a production environment. – gcbenison Jun 18 '13 at 04:46
4

Use Const::Fast instead of Readonly or constant. They interpolate without any contortions. See CPAN modules for defining constants:

For conditional compilation, constant is a good choice. It's a mature module and widely used.

...

If you want array or hash constants, or immutable rich data structures, use Const::Fast. It's a close race between that and Attribute::Constant, but Const::Fast seems maturer, and has had more releases.

On the other hand, you seem to be writing your own templating code. Don't. Instead, use something simple like HTML::Template:

use HTML::Template;

use constant FOO => 'bar';

my $tmpl = HTML::Template->new(scalarref => \ <<EOF
Foo is currently <TMPL_VAR VALUE>
EOF
);

$tmpl->param(VALUE => FOO);
print $tmpl->output;
Community
  • 1
  • 1
Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
3

Have you considered using "read-only variables" as constants?
perlcritic recomends it at severity level 4 (default is level 5)

use Readonly;
Readonly my $FOO => 'bar';

my $msg = <<"EOF";
Foo is currently <$FOO>
EOF

P.S. Module Const::Fast (inspired by noduleReadonly) seems to be a better choice.

AnFi
  • 10,493
  • 3
  • 23
  • 47
  • Please be aware that while constants are subject to constant folding and optimization (thus allowing interesting compile-time magic), readonly variables are a bit slow. They are not one-to-one equivalent. But I have to admit that this is a good situation for Readonly. – amon Apr 03 '13 at 17:22
1

Late to the party, but another version of the arrayref trick can do this in a scalar context: ${\FOO}. Example, tested in perl 5.22.2 on cygwin:

use constant FOO=>'bar';
print <<EOF
backslash -${\FOO}-
backslash and parens -${\(FOO)}-
EOF

produces

backslash -bar-
backslash and parens -bar-

Thanks to d-ash for introducing me to this technique, which he uses in his perlpp source preprocessor here (see also this answer). (Disclaimer: I am now the lead maintainer of perlpp - GitHub; CPAN.)

cxw
  • 16,685
  • 2
  • 45
  • 81