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

localised tied scalar referenced elsewhere has strange effects #11763

Open
p5pRT opened this issue Nov 21, 2011 · 6 comments
Open

localised tied scalar referenced elsewhere has strange effects #11763

p5pRT opened this issue Nov 21, 2011 · 6 comments

Comments

@p5pRT
Copy link

p5pRT commented Nov 21, 2011

Migrated from rt.perl.org#104118 (status was 'open')

Searchable as RT104118$

@p5pRT
Copy link
Author

p5pRT commented Nov 21, 2011

From @cpansprout

This is based on rt.cpan.org #53064.

sub TIESCALAR{bless[], $_[0]}
sub FETCH { warn fetching; $_[0][0] }
sub STORE { warn "storing $_[1]"; $_[0][0] = $_[1] }
tie $b, "";
*a = \$b;
$b = "one";
{
  local $b = "two";
  {
  my $x = "$a";
# my $x = $a;
  }
}
warn "\$b is now $b";

That script prints​:

storing one at - line 3.
fetching at - line 2.
storing at - line 3.
storing two at - line 3.
storing one at - line 3.
fetching at - line 2.
$b is now one at - line 14.

If you comment out the my $x = "$a" line and uncomment the line below it, you get​:

storing one at - line 3.
fetching at - line 2.
storing at - line 3.
storing two at - line 3.
fetching at - line 2.
storing two at - line 3.
fetching at - line 2.
$b is now two at - line 14.

So apparently the "$a" is skipping get-magic.

In any case, ‘$b is now one’ seems like the correct output to me.

The hard part is figuring out how it is supposed to work. When you write ‘local $foo’ on a regular scalar, the *foo{SCALAR} slot is temporarily replaced with another scalar. If you have a reference to the original $foo elsewhere, you can modify it even during the localisation. The modified value of $foo is what is visible after the localisation goes out of scope.

Localised tied scalars are a different creature. The scalar is replaced with a new scalar, like an untied variable, but then the new scalar is tied to the very same object. The old scalar has its private flags copied to the public flags, so that a simple SvSETMAGIC will restore the previous value. But that implementation detail leaks out as through a sieve when a reference to the original scalar exists elsewhere. That is why "$a" is skipping FETCH.

Since the new tied variable is tied to the same object, conceptually it could be considered the same scalar, just with a localised *value*. Most people probably think of it that way. If we make the implementation actually work that way (copy the value to a new scalar and put that on the save stack; assign the value of that temporary scalar back to the tied variable on scope exit), it will at least be self-consistent.

Is that a good idea?


Flags​:
  category=core
  severity=low


Site configuration information for perl 5.15.4​:

Configured by sprout at Wed Nov 2 09​:06​:14 PDT 2011.

Summary of my perl5 (revision 5 version 15 subversion 4) configuration​:
  Snapshot of​: f364061
  Platform​:
  osname=darwin, osvers=10.5.0, archname=darwin-thread-multi-2level
  uname='darwin pint.local 10.5.0 darwin kernel version 10.5.0​: fri nov 5 23​:20​:39 pdt 2010; root​:xnu-1504.9.17~1release_i386 i386 '
  config_args='-de -Doptimize=-g -Dusedevel -Duseithreads -Dmad'
  hint=recommended, useposix=true, d_sigaction=define
  useithreads=define, usemultiplicity=define
  useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
  use64bitint=undef, use64bitall=undef, uselongdouble=undef
  usemymalloc=n, bincompat5005=undef
  Compiler​:
  cc='cc', ccflags ='-fno-common -DPERL_DARWIN -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include',
  optimize='-g',
  cppflags='-fno-common -DPERL_DARWIN -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
  ccversion='', gccversion='4.2.1 (Apple Inc. build 5664)', gccosandvers=''
  intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
  d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
  ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
  alignbytes=8, prototype=define
  Linker and Libraries​:
  ld='env MACOSX_DEPLOYMENT_TARGET=10.3 cc', ldflags =' -fstack-protector -L/usr/local/lib'
  libpth=/usr/local/lib /usr/lib
  libs=-ldbm -ldl -lm -lutil -lc
  perllibs=-ldl -lm -lutil -lc
  libc=, so=dylib, useshrplib=false, libperl=libperl.a
  gnulibc_version=''
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs, dlext=bundle, d_dlsymun=undef, ccdlflags=' '
  cccdlflags=' ', lddlflags=' -bundle -undefined dynamic_lookup -L/usr/local/lib -fstack-protector'

Locally applied patches​:
 


@​INC for perl 5.15.4​:
  /usr/local/lib/perl5/site_perl/5.15.4/darwin-thread-multi-2level
  /usr/local/lib/perl5/site_perl/5.15.4
  /usr/local/lib/perl5/5.15.4/darwin-thread-multi-2level
  /usr/local/lib/perl5/5.15.4
  /usr/local/lib/perl5/site_perl
  .


Environment for perl 5.15.4​:
  DYLD_LIBRARY_PATH (unset)
  HOME=/Users/sprout
  LANG=en_US.UTF-8
  LANGUAGE (unset)
  LD_LIBRARY_PATH (unset)
  LOGDIR (unset)
  PATH=/usr/bin​:/bin​:/usr/sbin​:/sbin​:/usr/local/bin​:/usr/X11/bin​:/usr/local/bin
  PERL_BADLANG (unset)
  SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Sep 17, 2012

From @rjbs

* Father Chrysostomos <perlbug-followup@​perl.org> [2011-11-20T19​:37​:23]

The hard part is figuring out how it is supposed to work. When you write
‘local $foo’ on a regular scalar, the *foo{SCALAR} slot is temporarily
replaced with another scalar. If you have a reference to the original $foo
elsewhere, you can modify it even during the localisation. The modified
value of $foo is what is visible after the localisation goes out of scope.

Localised tied scalars are a different creature. The scalar is replaced with
a new scalar, like an untied variable, but then the new scalar is tied to the
very same object. The old scalar has its private flags copied to the public
flags, so that a simple SvSETMAGIC will restore the previous value. But that
implementation detail leaks out as through a sieve when a reference to the
original scalar exists elsewhere. That is why "$a" is skipping FETCH.

Not only are they different from untied scalars, but also from tied arrays and
hashes.

Tied arrays and hashes cease to be tied after localization, after some work by
Dave M. and discussion here​:

  http​://www.xray.mpe.mpg.de/cgi-bin/w3glimpse2html/perl5-porters/2010-04/msg00561.html

In fact, tied scalars were also no longer tied after local, after that thread,
but then arose another thread​:

  http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2010-05/msg00627.html

David Golden notes that this change broke File​::chdir and Dave Mitchell says
he'll revert it unless there is some argument. There is no contribution to the
thread whatsoever (other than me noting that I don't really use File​::chdir
anymore; I'd already switched to the no-localization File​::push). The
scalar-untying is reverted in 89adf4e.

It's a tough nut. The current behavior stinks, and breaking stuff stinks, and
so does inconsistency between tied scalars and tied arrays. If I had my
druthers, I'd not have the tie survive localization, but I think this may be
a difficult behavior to sell the deprecation of.

--
rjbs

@p5pRT
Copy link
Author

p5pRT commented Sep 17, 2012

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

@p5pRT
Copy link
Author

p5pRT commented Sep 18, 2012

From @xdg

On Mon, Sep 17, 2012 at 6​:56 PM, Ricardo Signes
<perl.p5p@​rjbs.manxome.org> wrote​:

David Golden notes that this change broke File​::chdir and Dave Mitchell says
he'll revert it unless there is some argument. There is no contribution to the
thread whatsoever (other than me noting that I don't really use File​::chdir
anymore; I'd already switched to the no-localization File​::push). The
scalar-untying is reverted in 89adf4e.

It's a tough nut. The current behavior stinks, and breaking stuff stinks, and
so does inconsistency between tied scalars and tied arrays. If I had my
druthers, I'd not have the tie survive localization, but I think this may be
a difficult behavior to sell the deprecation of.

I can only repeat my comments at the time​:
http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2010-05/msg00679.html

tl;dr​: I'm happy for it to be consistent even if that breaks stuff.

More generally, I find tie() to be a huge PITA and it's on my
fix-it-with-a-Delorean list shortly after version objects.

David

--
David Golden <xdg@​xdg.me>
Take back your inbox! → http​://www.bunchmail.com/
Twitter/IRC​: @​xdg

@p5pRT
Copy link
Author

p5pRT commented Sep 9, 2013

From @jkeenan

On Mon Sep 17 17​:42​:54 2012, xdg@​xdg.me wrote​:

More generally, I find tie() to be a huge PITA and it's on my
fix-it-with-a-Delorean list shortly after version objects.

"fix-it-with-a-Delorean" stumps me ... as well as DDG, Google and Bing!

Example​: https://duckduckgo.com/?q=fix-it-with-a-Delorean
(as of writing)

@p5pRT
Copy link
Author

p5pRT commented Sep 10, 2013

From @b2gills

On Mon, Sep 9, 2013 at 6​:23 PM, James E Keenan via RT
<perlbug-followup@​perl.org> wrote​:

On Mon Sep 17 17​:42​:54 2012, xdg@​xdg.me wrote​:

More generally, I find tie() to be a huge PITA and it's on my
fix-it-with-a-Delorean list shortly after version objects.

"fix-it-with-a-Delorean" stumps me ... as well as DDG, Google and Bing!

Example​: https://duckduckgo.com/?q=fix-it-with-a-Delorean
(as of writing)

"Fix it with a Delorean" is obviously a "Back to the future reference.

You could also say "fix it with a/the TARDIS"

Basically it means going into the past to prevent the mistake from
ever happening

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

2 participants