can s/// return a new value, rather than modifying it's input argument?

B

Bill Keese

You can think of the s/// operator as a function taking three
arguments: pattern, replacement, and input-string. This function
modifies input-string according to pattern and replacement. But is
there any similar function which returns a new string, rather than
updating input-string?

For example, instead of doing this:

($newLetter = $oldLetter) =~ s/Mister/Mr./;

Can I do something like this?

$newLetter = ($oldLetter ~ s/Mister/Mr./) ;

This is similar to java's replace function:
newLetter = oldLetter.replace("Mister", "Mr.");

Thanks,
Bill
 
B

Bill

Bill said:
You can think of the s/// operator as a function taking three
arguments: pattern, replacement, and input-string. This function
modifies input-string according to pattern and replacement. But is
there any similar function which returns a new string, rather than
updating input-string?

For example, instead of doing this:

($newLetter = $oldLetter) =~ s/Mister/Mr./;

Can I do something like this?

$newLetter = ($oldLetter ~ s/Mister/Mr./) ;

Change your parentheses.

my $oldLetter = 'Mister Smith';
(my $newLetter = $oldLetter) =~ s/Mister/Mr./;
print "old $oldLetter, new $newLetter\n";
 
G

Gunnar Hjalmarsson

Bill said:
You can think of the s/// operator as a function taking three
arguments: pattern, replacement, and input-string. This function
modifies input-string according to pattern and replacement. But is
there any similar function which returns a new string, rather than
updating input-string?

For example, instead of doing this:

($newLetter = $oldLetter) =~ s/Mister/Mr./;

Not sure what's the problem with doing so. But you can of course write
your own function:

sub replace {
my ($str, $pat, $rpl) = @_;
$str =~ s/$pat/$rpl/;
$str
}

my $newLetter = replace($oldLetter, qr/Mister/, 'Mr.');
 
J

James Taylor

...you can of course write your own function:

sub replace {
my ($str, $pat, $rpl) = @_;
$str =~ s/$pat/$rpl/;
$str
}

my $newLetter = replace($oldLetter, qr/Mister/, 'Mr.');

What's the benefit of using the qr// quoting construct here?

Is there any way for the subroutine to detect that it has been
passed a regex instead of a plain string?
 
G

Gunnar Hjalmarsson

James said:
What's the benefit of using the qr// quoting construct here?

None that I'm aware of in this simple example, but it might be useful
to pass modifiers etc.
Is there any way for the subroutine to detect that it has been
passed a regex instead of a plain string?

Don't think so. It is a plain string, btw. In this case it is:
'(?-xism:Mister)'.
 
T

Tassilo v. Parseval

Also sprach James Taylor:
What's the benefit of using the qr// quoting construct here?

Is there any way for the subroutine to detect that it has been
passed a regex instead of a plain string?

Yes, sure:

sub replace {
my ($str, $pat, $rpl) = @_;
print "Regexp passed\n" if ref($pat) eq "Regexp";
...
}

Tassilo
 
G

Gregory Toomey

Bill said:
You can think of the s/// operator as a function taking three
arguments: pattern, replacement, and input-string. This function
modifies input-string according to pattern and replacement. But is
there any similar function which returns a new string, rather than
updating input-string?

For example, instead of doing this:

($newLetter = $oldLetter) =~ s/Mister/Mr./;

Can I do something like this?

$newLetter = ($oldLetter ~ s/Mister/Mr./) ;

This is similar to java's replace function:
newLetter = oldLetter.replace("Mister", "Mr.");

Thanks,
Bill

I think you are asking: can I treat s/// like a function??
The answer is YES, and you can use this trick with other operators too.


sub apply (&$) {
local $_ = $_[1];
$_[0]->();
$_;
}

$var2= apply {s/123/456/g; tr/a-a/A-Z/} $var;


gtoomey
 
G

Gunnar Hjalmarsson

Tassilo said:
Also sprach James Taylor:

Yes, sure:

sub replace {
my ($str, $pat, $rpl) = @_;
print "Regexp passed\n" if ref($pat) eq "Regexp";
...
}

Interesting! I was obviously wrong when saying that qr// returns a
string, even if it looks that way when you print the return value.

Still confused:
- Does qr// return a reference to a regular expression?
- Is this use of the ref() function documented anywhere?
 
M

Michele Dondi

modifies input-string according to pattern and replacement. But is
there any similar function which returns a new string, rather than
updating input-string?

For example, instead of doing this:

($newLetter = $oldLetter) =~ s/Mister/Mr./;

Can I do something like this?

$newLetter = ($oldLetter ~ s/Mister/Mr./) ;

You can do some tricks to that effect. Other than waht you've already
been suggested, just two more WTDI:

#!/usr/bin/perl

use strict;
use warnings;

my $old="foo bar baz\n";
my $new=do { local $_=$old;
s/b\w+\b/$&$&/g;
$_ };

print $old, $new;

__END__

or

#!/usr/bin/perl

use strict;
use warnings;

my $old="foo bar baz\n";
my $new=sub { local $_=shift;
s/b\w+\b/$&$&/g;
$_ }->($old);

print $old, $new;

__END__

and as usual you have a virtually unlimited number of possible
variations...


Michele
 
T

Tassilo v. Parseval

Also sprach Gunnar Hjalmarsson:
Interesting! I was obviously wrong when saying that qr// returns a
string, even if it looks that way when you print the return value.

It returns an object blessed into the package Regexp. You can print this
object because it sort of overloads stringification. I am not sure that
this is technically correct. At least it is what happens from the point
of view of the programmer.

For instance you can write this:

sub Regexp::match_against { return $_[1] =~ /$_[0]/ }
print qr/foo/->match_against("foobar");
__END__
1
Still confused:
- Does qr// return a reference to a regular expression?

Hard to say. Neither perlop nor perlre mention anywhere that the return
value of qr// behaves like an object.
- Is this use of the ref() function documented anywhere?

Probably not. It is just a consequence of the fact that qr// returns
something reference-ish.

Tassilo
 
B

Ben Morrow

Gunnar Hjalmarsson said:
None that I'm aware of in this simple example, but it might be useful
to pass modifiers etc.

It's faster. Perl doesn't need to recompile the regex in $pat at run-time.
Don't think so. It is a plain string, btw. In this case it is:
'(?-xism:Mister)'.

It's not quite a 'plain' string: it has compiled-regex magic attached
to it.

Ben
 
B

Brian McCauley

Gregory Toomey said:
sub apply (&$) {
local $_ = $_[1];
$_[0]->();
$_;
}

I first coined the name 'apply' for this function in John Lin's
classic asking of this question "Idiom: the expression of a copied &
substituted string" back in April 2001

http://groups.google.com/[email protected]

I don't like Gregory Toomey's varition on my original suggestion...

Firstly you should never say "local $_" - it has some really nasty
action-at-a-distance problems when $_ happens to be aliased to an
element of a tied aggregate. Localising of $_ should be done with
"for" or "map".

Secondly I think it makes more sense for &apply to work in a list
context too.

sub apply (&@) {
my $action = shift;
&$action for my @values = @_;
wantarray ? @values : $values[-1];
}

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 
B

Bill Keese

Thanks to everyone that replied! Yes, I wanted s/// to work like a
function. The replace() or more general apply() functions seem to do
the trick.

Why did I want this?

1) it's inelegant to make a temporary variable just to call a
function.

(my $temp = $letter) =~ s/Mister/Mr./;
myFunction($temp); # or "print $temp;"

2) The syntax
(my $temp = $letter) =~ s/Mister/Mr./;
might be difficult for non-perl users to understand. Of course, the
advantage is that it is idiomatic perl.

Bill
 
G

Gregory Toomey

Brian said:
sub apply (&@) {
my $action = shift;
&$action for my @values = @_;
wantarray ? @values : $values[-1];
}

OK Brian I acknowledge this as a work of true genius!

gtoomey
 
U

Uri Guttman

BM> Secondly I think it makes more sense for &apply to work in a list
BM> context too.

BM> sub apply (&@) {
BM> my $action = shift;
BM> &$action for my @values = @_;
BM> wantarray ? @values : $values[-1];
BM> }

why do you return the last element of @values in scalar context?
wouldn't the first be just as arbitrary? why not check for the number of
arguments passed in as well?


sub apply (&@) {
my $action = shift;
$action->() for my @values = @_;
#i like that syntax better for calling code refs

return @values if wantarray ;
return \@values if @_ > 1 ;
return $values[0] ;
}

or you could change the order some if you think the scalar mode will be
called the most often:

return $values[0] if @_ == 1 ;
return @values if wantarray ;
return \@values ;

that will return 1 value in either scalar or list context if 1 arg is
passed in.

in File::Slurp::read_file you will find 5 (count 'em 5!) return
statements in a row which has to be a record. i changed the order to
optimize the more common ways it will be called.

uri
 
B

Brian McCauley

Uri Guttman said:
BM> Secondly I think it makes more sense for &apply to work in a list
BM> context too.

BM> sub apply (&@) {
BM> my $action = shift;
BM> &$action for my @values = @_;
BM> wantarray ? @values : $values[-1];
BM> }

why do you return the last element of @values in scalar context?
wouldn't the first be just as arbitrary?

There is, as you know, no general way to infer from the behaviour of
EXPR in a list context how EXPR will behave in a scalar context.

One of the many possible behaviours is for scalar(EXPR) to be
equivalent to (EXPR)[0] and another is for it to be equivalent to
(EXPR)[-1].

Now it happens that in Perl, for EXPRs where one of the above is true,
the second one is more common. Once I have decided that I want my
apply() function to do one of the above then it makes sense to choose
the one that is more common.
why not check for the number of arguments passed in as well?

Because conceptually the function takes two arguments, the second one
being a LIST. I considered thay I should carp() (or even croak()) if
called in a scalar context with a list of length other than one. But
I decided the cost was warranted. If and when I ever get a round tuit
the XS version of apply() will do so.
$action->() for my @values = @_;
#i like that syntax better for calling code refs

As you know, because we've discussed it before, I prefer to use &{}
when I'm calling a coderef where I'm expecting the called code to
communicate with the caller via shared globals (in this case $_).

I prefer to use ->() where I'm expecting the called code to
communicate with the caller via the formal arguments and return value.
return @values if wantarray ;
return \@values if @_ > 1 ;
return $values[0] ;

I think having the return value change type based on the length of the
list is conceptually ugly and more importantly a bug waiting to happen.

Consider:

my $foo = apply { s/this/that/ } @bar;

I'm either expecting $foo to contain an arrayref or I'm not. I
certainly don't expect it to be dependant on $#bar!

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 
U

Uri Guttman

BM> sub apply (&@) {
BM> my $action = shift;
BM> &$action for my @values = @_;
BM> wantarray ? @values : $values[-1];
BM> }
BM> There is, as you know, no general way to infer from the behaviour of
BM> EXPR in a list context how EXPR will behave in a scalar context.

BM> One of the many possible behaviours is for scalar(EXPR) to be
BM> equivalent to (EXPR)[0] and another is for it to be equivalent to
BM> (EXPR)[-1].

i know that. i was asking why you chose -1 and not the more 'normal' 0?
in the typical case of a single value they do the same thing. now, it
would be silly to call it with multiple values and use only one since
the applied function works on copies that are thrown away.

BM> Because conceptually the function takes two arguments, the second one
BM> being a LIST. I considered thay I should carp() (or even croak()) if
BM> called in a scalar context with a list of length other than one. But
BM> I decided the cost was warranted. If and when I ever get a round tuit
BM> the XS version of apply() will do so.

you missed what i said. of course there is a function as the first
arg. i meant check the rest of @_ and change behavior according to
that. a classic thing that does this are accessor methods (the kind
without get/set). no args is get, one or more args is set. the $self
arg is not counted.
$action->() for my @values = @_;
return @values if wantarray ;
return \@values if @_ > 1 ;
return $values[0] ;

BM> I think having the return value change type based on the length of
BM> the list is conceptually ugly and more importantly a bug waiting
BM> to happen.

see my accessor example above. it is very common.

BM> Consider:

BM> my $foo = apply { s/this/that/ } @bar;

BM> I'm either expecting $foo to contain an arrayref or I'm not. I
BM> certainly don't expect it to be dependant on $#bar!

you could force it to be an array ref by wrapping it in [] at the cost
of an extra copy.

anyhow, i have never seemed to want this apply thing. i just work on
data as needed. for those who like to use it, it is fine. i just do
direct for/map as i need.

uri
 
B

Brian McCauley

BM> One of the many possible behaviours is for scalar(EXPR) to be
BM> equivalent to (EXPR)[0] and another is for it to be equivalent to
BM> (EXPR)[-1].

i know that. i was asking why you chose -1 and not the more 'normal'
0?

Well I answered that already (but for some reason you clipped it from
your quote).

I chose -1 because -1 is normal and 0 is not.

Here are a few EXPRs for which scalar(EXPR) is the same as (EXPR)[-1]

5,6
@a[1,2]
@a{'foo','bar'}
\(foo)

Can you list any EXPRs for which scalar(EXPR) is the same as
(EXPR)[0] and not (EXPR)[-1] ?
in the typical case of a single value they do the same thing. now, it
would be silly to call it with multiple values and use only one since
the applied function works on copies that are thrown away.

Yes indeed, as a say below, apply() could carp() (or even croak()) if
called in a scalar context with a list of length other than one in
scalar context because it is nonsensical to do so.

But then again Perl doesn't warn if you use a slice in a scalar
context. IMNSHO it should. This would make far more sense than the
frequently annoying "Scalar value @%s{%s} better written as $%s{%s}"
warning.
BM> Because conceptually the function takes two arguments, the second one
BM> being a LIST. I considered thay I should carp() (or even croak()) if
BM> called in a scalar context with a list of length other than one. But
BM> I decided the cost was warranted. If and when I ever get a round tuit
BM> the XS version of apply() will do so.

you missed what i said.

No I didn't.
of course there is a function as the first
arg. i meant check the rest of @_ and change behavior according to
that. a classic thing that does this are accessor methods (the kind
without get/set). no args is get, one or more args is set. the $self
arg is not counted.

No _you_ missed what I said. Please don't assume that every time I
disagree with you I've failed to understand what you've said. Many a
time I understand perfectly and I still disagree.
return @values if wantarray ;
return \@values if @_ > 1 ;
return $values[0] ;

BM> I think having the return value change type based on the length of
BM> the list is conceptually ugly and more importantly a bug waiting
BM> to happen.

see my accessor example above. it is very common.

No, that's compeltely different. An accessor conceptually takes zero
or one scalar arguments. If methods could have prototypes the
accessor's would be (;$). apply() has the prototype (&@) so it's
arguments are a function and a LIST. The length of that list can
meaningfully be 0,1 or more but it's still conceptually a list in all
cases.
BM> Consider:

BM> my $foo = apply { s/this/that/ } @bar;

BM> I'm either expecting $foo to contain an arrayref or I'm not. I
BM> certainly don't expect it to be dependant on $#bar!

you could force it to be an array ref by wrapping it in [] at the cost
of an extra copy.

Yes indeed so there is no gain having apply return an array ref since
whenever you wanted an array ref you'd always have to put in the []
just in case $#bar==0.
anyhow, i have never seemed to want this apply thing.

Diabetic? :)

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 
R

Randal L. Schwartz

Brian> Here are a few EXPRs for which scalar(EXPR) is the same as (EXPR)[-1]

Brian> 5,6
Brian> @a[1,2]
Brian> @a{'foo','bar'}
Brian> \(foo)

Brian> Can you list any EXPRs for which scalar(EXPR) is the same as
Brian> (EXPR)[0] and not (EXPR)[-1] ?

getpwuid($uid)

Brian> But then again Perl doesn't warn if you use a slice in a scalar
Brian> context. IMNSHO it should. This would make far more sense than the
Brian> frequently annoying "Scalar value @%s{%s} better written as $%s{%s}"
Brian> warning.

No, because then I couldn't do this:

my $result = 3 + (/(\d\d\d)/)[0];

And yes, there have been times where I needed the first return
from a list in a scalar context just like that, in real coding.
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top