function within qq{}

C

cate

I know you can do this, I just can't find it.
How do you call a sub within a qq{} construct

qq{The common term for H2O is chem("H2O").}

Thank you

(As soon is this post is complete... I'll find it) :)
 
J

John W. Krahn

cate said:
I know you can do this, I just can't find it.
How do you call a sub within a qq{} construct

qq{The common term for H2O is chem("H2O").}

perldoc -q "How do I expand function calls in a string"



John
 
U

Uri Guttman

c> @{[mysub(1,2,3)]}
c> good grief. Thanks

and that is considered a poor construct. i never use it (or its scalar
cousin) nor do i recommend it. when i review code, i downgrade when i
see that used. it is simpler and better to just assign to a variable
before the string and then interpolate it. also it will likely be faster
as you don't need the reference/dereference. also it will only call your
code in a list context (even the scalar form!) which may be a
problem. assigning to your own variable allows you to control the
context as well.

uri
 
J

John Bokma

cate said:
I know you can do this, I just can't find it.
How do you call a sub within a qq{} construct

qq{The common term for H2O is chem("H2O").}

Thank you

(As soon is this post is complete... I'll find it) :)

perl -e '
sub chem {
my $term = shift;
return "*$term*";
}
print qq{The common term for H2O is ${\( chem("H2O") ) }};
'

use @{...} for list expressions, ${...} for scalar.

See perldoc perlref section Using References, item 4.
 
U

Uri Guttman

JB> perl -e '
JB> sub chem {
JB> my $term = shift;
JB> return "*$term*";
JB> }
JB> print qq{The common term for H2O is ${\( chem("H2O") ) }};
JB> '

JB> use @{...} for list expressions, ${...} for scalar.

partly incorrect.

perl -le 'sub context {return "array" if wantarray} ; print "scalar ${\context()}"'
scalar array

that is an obscure bug that has been around a long time. the scalar form
still calls the sub in list context. this is one of the reasons i don't
recommend using this trick. and a trick it is. it isn't really meant to
be used like that but perl's syntax supports interpolating of
dereferenced expressions. the interpolate module supports this in a
better way and so does perl6.

uri
 
U

Uri Guttman

JB> perl -e '
JB> sub chem {
JB> my $term = shift;
JB> return "*$term*";
JB> }
JB> print qq{The common term for H2O is ${\( chem("H2O") ) }};
JB> '
BM> It's not a bug. \($x, $y, $z) is perfectly valid, and returns a list of
BM> refs. (This also means that \(@a) is not the same as \@a: one of the few
BM> cases where parens *are* necessary to denote a list.)

yes, but the "${\foo()}" idiom looks like it will be in scalar
context. that is the issue. you need to put a scalar() in there. whether
it is a true bug or not, i say this is one reason to not use this
trick. using a variable is simpler, probably faster and safer.

uri
 
U

Uri Guttman

BM> It's not a bug. \($x, $y, $z) is perfectly valid, and returns a list of
BM> refs. (This also means that \(@a) is not the same as \@a: one of the few
BM> cases where parens *are* necessary to denote a list.)
BM> Oh, I agree there. The right answer is of course some sort of template
BM> system: sprintf will do for starters, and there are plenty on CPAN.

and what is wrong with my suggestio of a simple variable assignment
before the string is built? that is all the OP needs.

uri
 
J

John Bokma

Uri Guttman said:
JB> perl -e '
JB> sub chem {
JB> my $term = shift;
JB> return "*$term*";
JB> }
JB> print qq{The common term for H2O is ${\( chem("H2O") ) }};
JB> '

JB> use @{...} for list expressions, ${...} for scalar.

partly incorrect.

I stand corrected, thanks (Ben too). I haven't used this construct for
ages, don't really like it.
 
E

Eric Pozharski

with said:
yes, but the "${\foo()}" idiom looks like it will be in scalar
context. that is the issue. you need to put a scalar() in there. whether
it is a true bug or not, i say this is one reason to not use this
trick. using a variable is simpler, probably faster and safer.

s/probably/definetely/

#!/usr/bin/perl

use strict;
use warnings;
use Benchmark qw{ cmpthese timethese };

sub abc {
return "abc";
}
sub def {
my $t = "def";
return "*$t";
}
my( $x, $y );

cmpthese timethese -5, {
code00 => sub { $x = "@{[ abc ]}"; },
code01 => sub { $x = "${\( def )}"; },
code02 => sub { $y = abc; $x = "$y"; },
};

__END__
Benchmark: running code00, code01, code02 for at least 5 CPU seconds...
code00: 6 wallclock secs ( 5.17 usr + 0.00 sys = 5.17 CPU) @ 559916.63/s (n=2894769)
code01: 7 wallclock secs ( 5.09 usr + 0.00 sys = 5.09 CPU) @ 667528.49/s (n=3397720)
code02: 7 wallclock secs ( 5.27 usr + 0.00 sys = 5.27 CPU) @ 941641.56/s (n=4962451)
Rate code00 code01 code02
code00 559917/s -- -16% -41%
code01 667528/s 19% -- -29%
code02 941642/s 68% 41% --

p.s. "faster" is strawman, anyway
 
M

Marc Girod

and what is wrong with my suggestio of a simple variable assignment
before the string is built? that is all the OP needs.

It requires a block around it when used with 'for'?
I.e. one might consider it as needless verbosity, in a context where
compacity would enhance readability...

print qq{The common term for $_ is ${ \chem($_) }} for @molecule;

Suppose you have 10 such lines...

Marc
 
W

Wolf Behrenhoff

Marc said:
It requires a block around it when used with 'for'?
I.e. one might consider it as needless verbosity, in a context where
compacity would enhance readability...

print qq{The common term for $_ is ${ \chem($_) }} for @molecule;

Suppose you have 10 such lines...

Use printf.

printf "The common term for %s is %s\n", $_, chem($_) for @molecule;

I never do a function call in a qq string because I consider that bad style.

- Wolf
 
U

Uri Guttman

WB> Use printf.

and that was mentioned by ben iirc. i would use sprintf instead as my
rule is print rarely, print late. i can't recall ever using printf
directly, whereas i use sprintf when i need too.

WB> I never do a function call in a qq string because I consider that
WB> bad style.

and we have another true believer! :)

uri
 
M

Marc Girod

Use printf.

This was Ben's answer, and... I agree, at least in that case
(and I cannot make another one now).

But I was replying to Uri's challenge.

Marc
 
S

sln

I know you can do this, I just can't find it.
How do you call a sub within a qq{} construct

qq{The common term for H2O is chem("H2O").}

Thank you

(As soon is this post is complete... I'll find it) :)

Its a little like the tail wagging the dog.
-> "The common term for %s is %s."
This doesen't change, so a sprintf is all you need.
Sometimes its a problem if you need to print the same thing
at different places in the program.

Taking your theme of qq(), you can split a message format string
from the data and consistently call a message formatter that puts
it all together.

This is just for example purposes. Should you need a full
blown formatter, there are probably dozens of safe ones on
Cpan.

-sln

---------------
use strict;
use warnings;


my $common_msg = qq{"The common term for '%s' is '%s'."};
my $chem_msg = qq{"'%s' is the common term for '%s'."};
my %chemterms = (
'H20' => 'water',
'C02' => 'carbon dioxide',
'02' => 'oxygen',
'NaCL' => 'sodium chloride',
);
my %commonterms = reverse %chemterms;

##
for (sort keys %chemterms) {
print getMsg($common_msg, $_, chem($_)), "\n";
}
for (sort keys %commonterms) {
print getMsg($chem_msg, '\u'.$_, chem(-$_)), "\n";
}
exit 0;
##

sub chem {
my ($key) = @_;
return $commonterms{$key} || 'undefined' if $key =~ s/^-//;
return $chemterms{$key} || 'undefined'
}
sub getMsg {
my ($msg, @data) = @_;
my $retval = '';
my $evstr = "\$retval = sprintf ($msg, ". "@{[map {qq(\"$_\",)} @data]}" .");";
eval $evstr;
return $retval;
}
__END__

The common term for '02' is 'oxygen'.
The common term for 'C02' is 'carbon dioxide'.
The common term for 'H20' is 'water'.
The common term for 'NaCL' is 'sodium chloride'.
'Carbon dioxide' is the common term for 'C02'.
'Oxygen' is the common term for '02'.
'Sodium chloride' is the common term for 'NaCL'.
'Water' is the common term for 'H20'.
 
S

sln

This is just for example purposes. Should you need a full
blown formatter, there are probably dozens of safe ones on
Cpan.

my $evstr = "\$retval = sprintf ($msg, ". "@{[map {qq(\"$_\",)} @data]}" .");";

Shorter:
my $evstr = "\$retval = sprintf ($msg, @{[map {qq(\"$_\",)} @data]} );";
or
my $evstr = "\$retval = sprintf ($msg, @{[map {qq('$_',)} @data]} );";

if you don't want to interpolate @data's elements during eval.

-sln
 
T

Ted Zlatanov

This is just for example purposes. Should you need a full
blown formatter, there are probably dozens of safe ones on
Cpan.

my $evstr = "\$retval = sprintf ($msg, ". "@{[map {qq(\"$_\",)} @data]}" .");";

s> Shorter:
s> my $evstr = "\$retval = sprintf ($msg, @{[map {qq(\"$_\",)} @data]} );";
s> or
s> my $evstr = "\$retval = sprintf ($msg, @{[map {qq('$_',)} @data]} );";

s> if you don't want to interpolate @data's elements during eval.

That's like putting a band-aid on someone who's being electrocuted.
Yeah, it might help with the skin burns, but...

Ted
 
S

sln

This is just for example purposes. Should you need a full
blown formatter, there are probably dozens of safe ones on
Cpan.

my $evstr = "\$retval = sprintf ($msg, ". "@{[map {qq(\"$_\",)} @data]}" .");";

s> Shorter:
s> my $evstr = "\$retval = sprintf ($msg, @{[map {qq(\"$_\",)} @data]} );";
s> or
s> my $evstr = "\$retval = sprintf ($msg, @{[map {qq('$_',)} @data]} );";

s> if you don't want to interpolate @data's elements during eval.

That's like putting a band-aid on someone who's being electrocuted.
Yeah, it might help with the skin burns, but...

Ted

You lost me. Something wrong with this?
Whats a better way?

-sln
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top