4

Running:

$t =  3;
{
    tie $t, 'Yep';
} # Expect $t to become untied here.
print $t;

package Yep;

sub TIESCALAR {
   bless {}, 'Yep';
}

sub UNTIE {
   print "UNTIE\n";
}

sub DESTROY {
   print "DESTROY\n";
}

The output is:

Can't locate object method "FETCH" via package "Yep" at a.pl line 5.
DESTROY

The EXPECTED output is:

DESTROY
3

I want to tie variable $t only for the duration of the scope in which tie is located. Out of the scope it must behave same as before tie. So I wrap tie into the block and expect that untie will be called when the end of block is reached (like 'local' where the value is restored at the end of block, but for tied variable I expect behaviour is restored (untie $t) ). Notice the $t is not out of scope yet.

ikegami
  • 367,544
  • 15
  • 269
  • 518
Eugen Konkov
  • 22,193
  • 17
  • 108
  • 158
  • [Cross-posted on perl5porters](http://www.nntp.perl.org/group/perl.perl5.porters/2015/10/msg231557.html). Zefram's answer: 'That is intentionally not how tying behaves. Tying effects a permanent change to the object in question, in this case the scalar $t, and the effect lasts as long as the object does. It is no more lexically scoped than the effect of "$t = 4" inside the block would be.' – ThisSuitIsBlackNot Oct 05 '15 at 17:24
  • Also, as a side note, please don't completely change your question after you've received answers. You invalidate the existing answers and make things confusing for future visitors, since some answers will address your new question and some answers will address the old, completely different question. In the future, please just ask a new question. – ThisSuitIsBlackNot Oct 05 '15 at 17:27
  • I am sorry, but I do not think it is so different. I think tie/untie work in same manner like: new/delete, inc/dec, create/destroy. So at the end of file scope (when program end) I expect variable to be untied and DESTROY is called for object constructed at TIESCALAR. So instead of implicit file scope I create explicit around 'tie ...' @ThisSuitIsBlackNot – Eugen Konkov Oct 05 '15 at 21:05
  • The question is quite different: witness ikegami's two distinct answers. – ThisSuitIsBlackNot Oct 05 '15 at 21:19
  • As for your repeated assertion that `tie` should use dynamic scoping like `local`, that's just not how it works, no matter how hard you may wish it so. I don't follow your point about new/delete, inc/dec, etc. delete: `$h{foo} = 1; { delete $h{foo} } say for keys %h`; increment: `{ $i++ } say $i`; new: `package Foo; sub new { bless { foo => $_[1] }, $_[0] } package main; $foo = Foo->new(0); { $foo = Foo->new(1) } say $foo->{foo}`. None of the changes made inside the block are reverted outside of the block. Maybe you should explain exactly why you want this behavior. – ThisSuitIsBlackNot Oct 05 '15 at 21:31
  • Your comments give me the clue! thank you – Eugen Konkov Oct 06 '15 at 09:03

4 Answers4

4

Answering: Why is UNTIE not called when tied variable goes out of scope?

Because UNTIE handles when the user calls the builtin untie command. If it calls DESTROY when going out of scope, handle DESTROY.

If you need logic in both then you can

  1. Call a common cleanup sub from both

    sub UNTIE   { &_destructor; } # Perl 4 style, which passes the current
    sub DESTROY { &_destructor; } # @_ to the called procedure.
    
  2. goto common cleanup sub from both

    sub UNTIE   { goto &_destructor; } # does not return to this sub
    sub DESTROY { goto &_destructor; } # does not return to this sub
    
  3. Alias one to the other:

    *UNTIE = *DESTROY{CODE};
    
Axeman
  • 29,660
  • 2
  • 47
  • 102
  • #2 is purely worse than #1. It's slower, and it makes debugging harder by messing up the stack trace. – ikegami Oct 05 '15 at 14:25
4

Why is UNTIE not called when tied variable goes out of scope?

Asking why UNTIE isn't called when the variable goes out of scope is the same thing as asking why UNTIE isn't called whenever DESTROY is called. Well, that would be useless. What is useful is a function that's called when untie is called, and that's what UNTIE is.

If you want common code to be called when untie is called and when the object is destroyed, nothing's stopping you.

sub UNTIE   { shift->_destructor(@_) }
sub DESTROY { shift->_destructor(@_) }
ikegami
  • 367,544
  • 15
  • 269
  • 518
1

As for the completely new question,

Changes to variables aren't automatically undone when the scope in which those changes are made

my $t = 3;

{
   $t = 4;
}

print "$t\n";  # 4, not 3.

Same goes when the change is to add tie magic. You can use untie to remove the magic, but it's best if you simply use a new variable.

my $t = 3;

{
   tie my $t, 'Yep';
} # Tied variable destroyed here.

print "$t\n";  # 3.
ikegami
  • 367,544
  • 15
  • 269
  • 518
0

The example with my give me a clue. So in my case use local.

my $t = 3;

{
   tie local $t, 'Yep';
} # Tied variable destroyed here.

print "$t\n";  # 3.
Eugen Konkov
  • 22,193
  • 17
  • 108
  • 158