Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Successfull match $_[0] =~ /foo(.+)/ overrides $_[0] if function called as foo($1) #12599

Closed
p5pRT opened this issue Nov 19, 2012 · 11 comments
Closed

Comments

@p5pRT
Copy link

p5pRT commented Nov 19, 2012

Migrated from rt.perl.org#115834 (status was 'rejected')

Searchable as RT115834$

@p5pRT
Copy link
Author

p5pRT commented Nov 19, 2012

From sp@smartspb.net

Created by sp@smartspb.net

This is a bug report for perl from sp@​smartspb.net,
generated with the help of perlbug 1.39 running under perl 5.16.1.

-----------------------------------------------------------------
Successfull match $_[0] =~ /foo(.+)/ inside subroutine
overrides $_[0] if subroutine called as foo($1).

###### script ###### sp@​uskr​:~/3 (1570) cat u.pl
use strict; use warnings; use feature qw(​:all);

sub foo {
  say ' before =~ $_[0] is ', "'$_[0]'";
  $_[0] =~ /foo(.+)/;
  say ' after =~ $_[0] is ', "'$_[0]'", ' and $1 is ', "'$1'";
}

# ok

say 'call foo("foo123");';
foo('foo123');

# at least strange

say 'call foo($1);';
'barfoo123' =~ /(foo.+)/ && foo($1);

###### output ###### sp@​uskr​:~/3 (1571) perl u.pl

call foo("foo123");
  before =~ $_[0] is 'foo123'
  after =~ $_[0] is 'foo123' and $1 is '123'
call foo($1);
  before =~ $_[0] is 'foo123'
  after =~ $_[0] is '123' and $1 is '123'

sp@​uskr​:~/3 (1572)

###### summary ######

I'm not sure is that bug or feature.
I could not find something describing such things in docs.

Perl Info

Flags:
    category=core
    severity=low

Site configuration information for perl 5.16.1:

Configured by sp at Thu Oct 11 12:45:42 MSK 2012.

Summary of my perl5 (revision 5 version 16 subversion 1) configuration:
   
  Platform:
    osname=freebsd, osvers=9.0-release, archname=amd64-freebsd
    uname='freebsd uskr 9.0-release freebsd 9.0-release #0: tue jan 3 07:46:30 utc 2012 root@farrell.cse.buffalo.edu:usrobjusrsrcsysgeneric amd64 '
    config_args='-de -Dprefix=/site/perl5/perls/perl-5.16.1 -Aeval:scriptdir=/site/perl5/perls/perl-5.16.1/bin'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=undef, usemultiplicity=undef
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=define, use64bitall=define, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-DHAS_FPSETMASK -DHAS_FLOATINGPOINT_H -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include',
    optimize='-O',
    cppflags='-DHAS_FPSETMASK -DHAS_FLOATINGPOINT_H -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
    ccversion='', gccversion='4.2.1 20070831 patched [FreeBSD]', gccosandvers=''
    intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='cc', ldflags ='-Wl,-E  -fstack-protector -L/usr/local/lib'
    libpth=/usr/lib /usr/local/lib
    libs=-lm -lcrypt -lutil -lc
    perllibs=-lm -lcrypt -lutil -lc
    libc=, so=so, useshrplib=false, libperl=libperl.a
    gnulibc_version=''
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags=' '
    cccdlflags='-DPIC -fPIC', lddlflags='-shared  -L/usr/local/lib -fstack-protector'

Locally applied patches:
    


@INC for perl 5.16.1:
    /site/perl5/perls/perl-5.16.1/lib/site_perl/5.16.1/amd64-freebsd
    /site/perl5/perls/perl-5.16.1/lib/site_perl/5.16.1
    /site/perl5/perls/perl-5.16.1/lib/5.16.1/amd64-freebsd
    /site/perl5/perls/perl-5.16.1/lib/5.16.1
    .


Environment for perl 5.16.1:
    HOME=/home/sp
    LANG=ru_RU.UTF-8
    LANGUAGE (unset)
    LC_ALL=ru_RU.UTF-8
    LC_COLLATE=ru_RU.UTF-8
    LC_CTYPE=ru_RU.UTF-8
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/site/perl5/bin:/site/perl5/perls/perl-5.16.1/bin:/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin:/usr/local/sbin
    PERLBREW_BASHRC_VERSION=0.52
    PERLBREW_HOME=/home/sp/.perlbrew
    PERLBREW_MANPATH=/site/perl5/perls/perl-5.16.1/man
    PERLBREW_PATH=/site/perl5/bin:/site/perl5/perls/perl-5.16.1/bin
    PERLBREW_PERL=perl-5.16.1
    PERLBREW_ROOT=/site/perl5
    PERLBREW_VERSION=0.52
    PERL_BADLANG (unset)
    SHELL=/usr/local/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Nov 20, 2012

From @mauke

On 19.11.2012 18​:17, sp@​smartspb.net (via RT) wrote​:

Successfull match $_[0] =~ /foo(.+)/ inside subroutine
overrides $_[0] if subroutine called as foo($1).

###### script ###### sp@​uskr​:~/3 (1570) cat u.pl
use strict; use warnings; use feature qw(​:all);

sub foo {
say ' before =~ $_[0] is ', "'$_[0]'";
$_[0] =~ /foo(.+)/;
say ' after =~ $_[0] is ', "'$_[0]'", ' and $1 is ', "'$1'";
}

# ok

say 'call foo("foo123");';
foo('foo123');

# at least strange

say 'call foo($1);';
'barfoo123' =~ /(foo.+)/ && foo($1);

###### output ###### sp@​uskr​:~/3 (1571) perl u.pl

call foo("foo123");
before =~ $_[0] is 'foo123'
after =~ $_[0] is 'foo123' and $1 is '123'
call foo($1);
before =~ $_[0] is 'foo123'
after =~ $_[0] is '123' and $1 is '123'

sp@​uskr​:~/3 (1572)

###### summary ######

I'm not sure is that bug or feature.
I could not find something describing such things in docs.

This is not a bug. Quoting perldoc perlsub​:

Any arguments passed in show up in the array @​_ . Therefore, if you
called a function with two arguments, those would be stored in $_[0] and
$_[1] . The array @​_ is a local array, but its elements are aliases for
the actual scalar parameters. In particular, if an element $_[0] is
updated, the corresponding argument is updated (or an error occurs if it
is not updatable). If an argument is an array or hash element which did
not exist when the function was called, that element is created only
when (and if) it is modified or a reference to it is taken. (Some
earlier versions of Perl created the element whether or not the element
was assigned to.) Assigning to the whole array @​_ removes that aliasing,
and does not update any arguments.

--
Lukas Mai <l.mai@​web.de>

@p5pRT
Copy link
Author

p5pRT commented Nov 20, 2012

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Nov 21, 2012

From @druud62

On 2012-11-20 22​:57, Lukas Mai wrote​:

On 19.11.2012 18​:17, sp@​smartspb.net (via RT) wrote​:

Successfull match $_[0] =~ /foo(.+)/ inside subroutine
overrides $_[0] if subroutine called as foo($1).

###### script ###### sp@​uskr​:~/3 (1570) cat u.pl
use strict; use warnings; use feature qw(​:all);

sub foo {
say ' before =~ $_[0] is ', "'$_[0]'";
$_[0] =~ /foo(.+)/;
say ' after =~ $_[0] is ', "'$_[0]'", ' and $1 is ', "'$1'";
}

# ok

say 'call foo("foo123");';
foo('foo123');

# at least strange

say 'call foo($1);';
'barfoo123' =~ /(foo.+)/ && foo($1);

###### output ###### sp@​uskr​:~/3 (1571) perl u.pl

call foo("foo123");
before =~ $_[0] is 'foo123'
after =~ $_[0] is 'foo123' and $1 is '123'
call foo($1);
before =~ $_[0] is 'foo123'
after =~ $_[0] is '123' and $1 is '123'

sp@​uskr​:~/3 (1572)

###### summary ######

I'm not sure is that bug or feature.
I could not find something describing such things in docs.

This is not a bug. Quoting perldoc perlsub​:

Any arguments passed in show up in the array @​_ . Therefore, if you
called a function with two arguments, those would be stored in $_[0] and
$_[1] . The array @​_ is a local array, but its elements are aliases for
the actual scalar parameters. In particular, if an element $_[0] is
updated, the corresponding argument is updated (or an error occurs if it
is not updatable). If an argument is an array or hash element which did
not exist when the function was called, that element is created only
when (and if) it is modified or a reference to it is taken. (Some
earlier versions of Perl created the element whether or not the element
was assigned to.) Assigning to the whole array @​_ removes that aliasing,
and does not update any arguments.

Workaround​: local $1. (at the start of the sub)

Do we need a feature that auto-localizes the numbered capture variables
for subs?

--
Ruud

@p5pRT
Copy link
Author

p5pRT commented Nov 21, 2012

From @doy

On Wed, Nov 21, 2012 at 01​:20​:19AM +0100, Dr.Ruud wrote​:

On 2012-11-20 22​:57, Lukas Mai wrote​:

On 19.11.2012 18​:17, sp@​smartspb.net (via RT) wrote​:

Successfull match $_[0] =~ /foo(.+)/ inside subroutine
overrides $_[0] if subroutine called as foo($1).

###### script ###### sp@​uskr​:~/3 (1570) cat u.pl
use strict; use warnings; use feature qw(​:all);

sub foo {
say ' before =~ $_[0] is ', "'$_[0]'";
$_[0] =~ /foo(.+)/;
say ' after =~ $_[0] is ', "'$_[0]'", ' and $1 is ', "'$1'";
}

# ok

say 'call foo("foo123");';
foo('foo123');

# at least strange

say 'call foo($1);';
'barfoo123' =~ /(foo.+)/ && foo($1);

###### output ###### sp@​uskr​:~/3 (1571) perl u.pl

call foo("foo123");
before =~ $_[0] is 'foo123'
after =~ $_[0] is 'foo123' and $1 is '123'
call foo($1);
before =~ $_[0] is 'foo123'
after =~ $_[0] is '123' and $1 is '123'

sp@​uskr​:~/3 (1572)

###### summary ######

I'm not sure is that bug or feature.
I could not find something describing such things in docs.

This is not a bug. Quoting perldoc perlsub​:

Any arguments passed in show up in the array @​_ . Therefore, if you
called a function with two arguments, those would be stored in $_[0] and
$_[1] . The array @​_ is a local array, but its elements are aliases for
the actual scalar parameters. In particular, if an element $_[0] is
updated, the corresponding argument is updated (or an error occurs if it
is not updatable). If an argument is an array or hash element which did
not exist when the function was called, that element is created only
when (and if) it is modified or a reference to it is taken. (Some
earlier versions of Perl created the element whether or not the element
was assigned to.) Assigning to the whole array @​_ removes that aliasing,
and does not update any arguments.

Workaround​: local $1. (at the start of the sub)

Do we need a feature that auto-localizes the numbered capture
variables for subs?

No. The behavior here is the same behavior as

  my $a;
  sub foo {
  say $_[0];
  $a = "bar";
  say $_[0];
  }
  $a = "foo";
  foo($a);

which prints

  foo
  bar

It has nothing to do with capture variables, it happens for any variable
at all, because it is caused by the aliasing, not anything about the
variable itself.

-doy

@p5pRT
Copy link
Author

p5pRT commented Nov 21, 2012

From @epa

This is an issue which comes up perenially, see

http​://thread.gmane.org/gmane.comp.lang.perl.perl5.porters/1607

for an earlier 'bug' report.

I do feel that the current behaviour is confusing, if every time a new
programmer hits a seeming bug it requires a detailed explanation from
one of the perl5-porters about why it's meant to work like that. If
it's really unchangeable then calling foo($1) should issue a warning.

@p5pRT
Copy link
Author

p5pRT commented Nov 21, 2012

From @epa

On Tue Nov 20 16​:26​:18 2012, doy@​tozt.net wrote​:

The behavior here is the same behavior as

I believe it's not the same behaviour as the example you gave.
Expanding the code with one more final 'say'​:

  my $a;
  sub foo {
  say $_[0];
  $a = "bar";
  say $_[0];
  }
  $a = "foo";
  foo($a);
  say $a;

This prints foo bar bar. But the analogous code using $1

  sub foo {
  say $_[0];
  'bar' =~ /(bar)/;
  say $_[0];
  }
  'foo' =~ /(foo)/;
  foo($1);
  say $1;

prints foo bar foo. So while in the case of a global variable you set
the value seen by the caller - which makes sense - here $1 is aliased
enough to cause weird effects inside the subroutine, yet somehow local
enough for these effects to disappear when the subroutine exits. This
halfway house is what causes the confusion IMHO.

@p5pRT
Copy link
Author

p5pRT commented Nov 25, 2012

From @doy

On Wed, Nov 21, 2012 at 03​:55​:43AM -0800, Ed Avis via RT wrote​:

On Tue Nov 20 16​:26​:18 2012, doy@​tozt.net wrote​:

The behavior here is the same behavior as

I believe it's not the same behaviour as the example you gave.
Expanding the code with one more final 'say'​:

my $a;
sub foo \{
    say $\_\[0\];
    $a = "bar";
    say $\_\[0\];
\}
$a = "foo";
foo\($a\);
say $a;

This prints foo bar bar. But the analogous code using $1

sub foo \{
    say $\_\[0\];
    'bar' =~ /\(bar\)/;
    say $\_\[0\];
\}
'foo' =~ /\(foo\)/;
foo\($1\);
say $1;

prints foo bar foo. So while in the case of a global variable you set
the value seen by the caller - which makes sense - here $1 is aliased
enough to cause weird effects inside the subroutine, yet somehow local
enough for these effects to disappear when the subroutine exits. This
halfway house is what causes the confusion IMHO.

This is just a side effect of how $1 works in general - any assignments
to capture variables (via a successful match) are implicitly localized​:

  "foo" =~ /(.*)/;
  warn $1;
  {
  "bar" =~ /(.*)/;
  warn $1;
  }
  warn $1;

also outputs

  foo
  bar
  foo

The current behavior is the only thing that actually makes sense, given
the combination of behaviors in this example and the previous one I
gave. I do agree that it's fairly confusing, but I really don't know
what a better solution to this could possibly be.

-doy

@p5pRT
Copy link
Author

p5pRT commented Nov 26, 2012

From @epa

Jesse Luehrs <doy <at> tozt.net> writes​:

This is just a side effect of how $1 works in general - any assignments
to capture variables (via a successful match) are implicitly localized​:

The current behavior is the only thing that actually makes sense, given
the combination of behaviors in this example and the previous one I
gave. I do agree that it's fairly confusing, but I really don't know
what a better solution to this could possibly be.

I suggest that if we are stuck with the current behaviour, there should be a
warning on calls like foo($1).

--
Ed Avis <eda@​waniasset.com>

@p5pRT
Copy link
Author

p5pRT commented Dec 15, 2017

From zefram@fysh.org

With no bug here, this ticket should be closed.

-zefram

@p5pRT p5pRT closed this as completed Dec 15, 2017
@p5pRT
Copy link
Author

p5pRT commented Dec 15, 2017

@iabyn - Status changed from 'open' to 'rejected'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant