Is the use of an uninitialized variable undefined behavior? - perl

I don't know if "undefined behavior" means something in Perl but I would like to know if using not initialized variables in Perl may provoke unwanted behaviors.
Let's consider the following script:
use strict;
use warnings FATAL => 'all';
use P4;
my $P4;
sub get {
return $P4 if $P4;
# ...connection to Perforce server and initialization of $P4 with a P4 object...
return $P4;
}
sub disconnect {
$P4 = $P4->Disconnect() if $P4;
}
sub getFixes {
my $change = shift;
my $p4 = get();
return $p4->Run( "fixes", "-c", $change );
}
Here, the variable $P4, which is meant to store a P4 object after a connection to a Perforce server, is not initialized at the beginning of the script. However, whatever the function which is called first (get, disconnect or getFixes), the variable will be initialized before being used.
Is there any risk to do that? Should I explicitly initialized the $P4 variable at the beginning of the script?

Just a couple of straight-up answers to basic questions asked.
if "undefined behavior" means something in Perl
Yes, there is such a notion in Perl, and documentation warns of it (way less frequently than in C). See some examples in footnote †. On the other hand, at many places in documentation one finds a discussion ending with
... So don't do that.
It often comes up for things that would confuse the interpreter and could result in strange and possibly unpredictable behavior. These are sometimes typical "undefined behavior" even as they are not directly called as such.
The main question is of how uninitialized variables relate, per the title and
if using not initialized variables in Perl may provoke unwanted behaviors
This does not generally result in "undefined behavior" but it may of course lead to trouble and one mostly gets a warning for it. Unless the variable is legitimately getting initialized in such "use" of course. For example,
my $x;
my $z = $x + 3;
will draw a warning for the use of $x but not for $z (if warnings are on!). Note that this still succeeds as $x gets initialized to 0. (But in what is shown in the question the code will abort at that point, due to the FATAL.)
The code shown in the question seems fine in this sense, since as you say
the variable will be initialized before being used
Testing for truth against an uninitialized variable is fine since once it is declared it is equipped with the value undef, admissible (and false) in such tests.
See the first few paragraphs in Declarations in perlsyn for a summary of sorts on when one does or doesn't need a variable to be defined.
† A list of some behaviors specifically labeled as "undefined" in docs
Calling sort in scalar context
In list context, this sorts the LIST and returns the sorted list value. In scalar context, the behaviour of sort is undefined.
Length too great in truncate
The behavior is undefined if LENGTH is greater than the length of the file.
Using flags for sysopen which are incompatible (nonsensical)
The behavior of O_TRUNC with O_RDONLY is undefined.
Sending signals to a process-list with kill, where one can use negative signal or process number to send to a process group
If both the SIGNAL and the PROCESS are negative, the results are undefined. A warning may be produced in a future version.
From Auto-increment and Auto-decrement (perlop)
... modifying a variable twice in the same statement will lead to undefined behavior.
Iterating with each, tricky as it may be anyway, isn't well behaved if hash is inserted into
If you add or delete a hash's elements while iterating over it, the effect on the iterator is unspecified; for example, entries may be skipped or duplicated--so don't do that. It is always safe to delete the item most recently returned by each, ...
This draws a runtime warning (F), described in perldiag
Use of each() on hash after insertion without resetting hash iterator results in undefined behavior.
Statement modifier (perlsyn) used on my
The behaviour of a my, state, or our modified with a statement modifier conditional or loop construct (for example, my $x if ...) is undefined.
Some of these seem a little underwhelming (predictable), given what UB can mean. Thanks to ikegami for comments. A part of this list is found in this question.
Pried from docs current at the time of this posting (v5.32.1)

A variable declared with my is initialized with undef. There is no undefined behaviour here.
This is documented in perldoc persub:
If no initializer is given for a particular variable, it is created with the undefined value.
However, the curious construct my $x if $condition does have undefined behaviour. Never do that.

my initializes scalars to undef, and arrays and hashes to empty.
Your code is fine, though I would take a different approach to destruction.
Option 1: Provide destructor through wrapping
use Object::Destroyer qw( );
use P4 qw( );
my $P4;
sub get {
return $P4 ||= do {
my $p4 = P4->new();
$p4->SetClient(...);
$p4->SetPort(...);
$p4->SetPassword(...);
$p4->Connect()
or die("Failed to connect to Perforce Server" );
Object::Destroyer->new($p4, 'Disconnect')
};
}
# No disconnect sub
Option 2: Provide destructor through monkey-patching
use P4 qw( );
BEGIN {
my $old_DESTROY = P4->can('DESTROY');
my $new_DESTROY = sub {
my $self = shift;
$self->Disconnect();
$old_DESTROY->($self) if $old_DESTROY;
};
no warnings qw( redefined );
*P4::DESTROY = $new_DESTROY;
}
my $P4;
sub get {
return $P4 ||= do {
my $p4 = P4->new();
$p4->SetClient(...);
$p4->SetPort(...);
$p4->SetPassword(...);
$p4->Connect()
or die("Failed to connect to Perforce Server" );
$p4
};
}
# No disconnect sub

Related

Can someone explain this perl snippet?

for my $n (1, 2) {
sub_example();
}
sub sub_example {
my $bar = 1 if 1 == 2;
if ($bar) {
print "hahha, you see\n";
}
else {
$bar = 1;
}
}
So my question is why is $bar defined in the second loop iteration?
You're taking advantage of a strange bug (officially deprecated and slated to become a fatal error in 5.30), which involves declaring a lexical (my) variable in a statement with a statement-modifier conditional which is false.
The reason that this happens is because my $bar = 1; basically has two functions. It has a compile-time function, which is to reserve space in the lexical pad for a variable, and to associate $bar with that space; and it has a run-time function, which is to assign 1 to $bar whenever control flow reaches the my statement (a statement like my $foo; without the assignment also has these two effects, except it assigns undef at runtime).
When you govern the statement with a false conditional like my $bar = 1 if 1 == 2;, the compile-time function stays exactly the same, but the run-time function is prevented from running using the false condition, which means that whatever value was in that storage is re-used, without being assigned fresh each time the code reaches that point. This gives an effect almost, but not exactly, like using a state variable. It's a cool trick, but not recommended for any serious use, and as I've mentioned, it will be fatalized in an upcoming release of perl, which is another reason not to rely on it.
You should never use my with a statement modifier. The behaviour of such constructs is undefined (see perlsyn).
The current implementation doesn't clear the value assigned to the variable in the previous run of the subroutine, but there's no guarantee the behaviour will stay (in fact, it won't: see perldeprecation).

Error: "Cannot copy to ARRAY in scalar assignment"

The situation is that I am in a sub trying to use the caller's $a and $b, similar to what sort does. Most of the time it works, but while running unit tests I noticed in one case, inside one package, it did not work. I use caller to get the package of the caller and then set their $a and $b as shown in the following simplified demo. The problem does occur by simply calling this whatever function in the package where I discovered this.
sub whatever { # defined in main package
my $pkg = caller;
no strict 'refs';
${"${pkg}::a"} = "";
${"${pkg}::b"} = "";
}
I attempted to create a minimal package/class to reproduce the problem but the problem does not occur in this context, but I'm posting my attempt below anyway as an indication of the general context:
package WhateverClass {
sub new {
my ($class, $something, $something2) = #_;
my $this = {};
bless $this, $class;
$this->{something_} = $something;
$this->{something2_} = $something2;
return $this;
}
sub test { # bug reproduction
main::whatever();
}
}
my $obj = WhateverClass->new(1.0, 2.0);
$obj->test;
The error message is,
Error: "Cannot copy to ARRAY in scalar assignment"
And it is triggered by the exact line:
${"${pkg}::a"} = "";
Having narrowed it down to this "whatever" function, I tried putting a variety of things on the right side of that assignment, including arrayrefs, arrays, strings as shown, numbers, as well as undef. The ones that it accepts are only undef, integer values, and floating point values. It does not accept arrayrefs, hashrefs, or strings. In my case, in the original code that exposed this problem, the things being passed were object references, or blessed hashrefs, and those assignments fail as you'd expect if any hashref or arrayref assignment fails.
Even more strangely, under the Perl debugger the problem doesn't occur, but if I run normally it does.
Google searching for this turns up nothing matching this exact error and very little that is even close. So first question is what does this error message even mean? Second question is obviously how to move forward.
I'm using Perl 5.20.3 on Linux, but I also tried the latest 5.22 on a Windows machine and saw the same behavior.
I found the fix for me had to do with the fact that the package that was the only location where any problems were seen with use of this code had at one point in its lifetime prior to the problem appearing used List::MoreUtils pairwise. Some but not all of the problem behavior was reproducible in the debugger, and I tracked down where the "buggy" behavior began and it was after calling pairwise. I switched this call to use one of my own routines that does essentially the same thing and the problem is completely gone (thank God). This was quite a disturbing issue. As #ikegami noted, "buggy XS code" may be the problem, and my routine is pure Perl without any XS code.

clean way to pass argument to perl subroutine to child routine as they are without storing to variable first?

I want to pass the arguments of my routine to a subroutine as they are, possibly while adding a new argument. To give an example imagine something like this
sub log($$$){
my ($message, $log_location, $log_level) = #_;
#logs message
}
sub log_debug($$){
my ($message, $log_location) = #_;
log($message, $log_location, DEBUG_LOG_LEVEL);
}
That syntax works fine above, but requires my saving the #_ to intermediate variables to do it. I'm wondering if there is a simple clean syntax for doing so without using the intermediate variables. Something like
log(#_, DEBUG_LOG_LEVEL);
which gets an error about my "not having enough variables", but I think would otherwise work. Can this be done easily without warning?
You don't have to copy the elements of #_. You could use them directly as follows:
sub log_debug($$) {
log($_[0], $_[1], DEBUG_LOG_LEVEL);
}
Prefixing the call with & causes the prototype to be ignored, so you could also use the following:
sub log_debug($$) {
&log(#_, DEBUG_LOG_LEVEL);
}
If you eliminate the arguments (including ()), the callee will use the parent's #_ instead of creating a new one. This following is slightly more efficient than the previous solution:
sub log_debug($$) {
push #_, DEBUG_LOG_LEVEL;
&log;
}
Finally, if log obtains a stack trace, you might want to remove log_debug from the trace. This is slightly less efficient.
sub log_debug($$) {
push #_, DEBUG_LOG_LEVEL;
goto &log;
}
Note that none of four solutions I posted make a copy of the arguments.
Sure, just skip the prototypes
sub log {
my ($message, $log_location, $log_level) = #_;
#logs message
}
sub log_debug {
log(#_, DEBUG_LOG_LEVEL);
}
You can skip prototype checking by calling your subroutine with an &:
&log(#_, DEBUG_LOG_LEVEL);
According to perlsub:
Not only does the & form make the argument list optional, it also
disables any prototype checking on arguments you do provide. This is
partly for historical reasons, and partly for having a convenient way
to cheat if you know what you're doing.

How do I detect the 'strict' pragma within a module?

Normally when I build a data structure in Perl, I end up having to declare it from %leaf to %root, so I have been tinkering with a module that would allow me to build up from
$seed to $seed->trunk->branch->leaf.
It's not difficult with AUTOLOAD and new subroutines. My question for SO is how do I detect if the 'strict' pragma is in use, so that the module runs in a different mode that would require the variables to be "declared" before usage so I don't accidently assign a value to $seed->drunk when I'm using strict -- assume that the module is called branch and this is valid syntax for module usage
$seed->declare('trunk');
$seed->trunk(new branch);
$seed->trunk->declare('leaf');
$seed->trunk->leaf("value");
How do I detect if the strict pragma is in effect in the calling program from the module?
It may be that this is not possible -- in which case I'd have to use a static variable to handle module independent pragmas.
EDITED / POSTSCRIPT:
I coded out the initial version that doesn't check for 'strictness' or implement a 'declare' subroutine and realized that the autoloader would not provide a simple enough user syntax if it operated by reference, so I wrote it to check for the first parameter and assign the value passed to an element in the object's referred hash table, otherwise if there was no parameter it would return the value of the element specified.
So I am posting the code for the branch module to satisfy your curiosity. Mind you, I haven't implemented a check for strictness, yet.
package branch;
sub new
{
my $type = shift;
my $self = { };
bless $self, $type;
return $self;
}
sub DESTROY
{
my $self = shift;
%$self = undef;
}
sub AUTOLOAD
{
my $self = shift;
my $value = shift;
my $sub = $AUTOLOAD;
my ($type, $PROGRAM) = ($sub =~ /(.*)::(.*)/);
if( $value ne undef )
{
$$self{$PROGRAM} = $value;
return $value;
}
return $$self{$PROGRAM};
}
1;
Well the first thing would be, strict what? Strict has three subpragmas, with their own behaviors and bits to check. use strict 'refs' doesn't allow you to dereference strings; use strict 'vars' doesn't allow you to access global variables in an unqualified way, and use strict 'subs' disables barewords outside of a few situations. use strict equates to all three, but none of them really seems close enough to what you're asking for to be worth piggy-backing on.
So to answer your question somewhat directly: element [8] in the list returned by caller($i) returns the compile hint bits in effect for the $ith level caller. If you peek in strict.pm you can see the bits that each subpragma sets and check for them at the caller level that corresponds to the code that's actually calling your method.
But, returning to my original point, you probably shouldn't, because that's not what strict is about. You should either accept an option on your objects' constructor that decides whether they should behave strictly or not, or if you really want a lexical pragma instead of something that follows your objects around, you should write your own using the information in perlpragma as a tutorial. All perls since 5.10 support arbitrary user-defined pragmas using the %^H hints hash which is exposed as element [10] of the caller info.
You seem to be confused about the scoping of the strict pragma.
If a module uses strict, this doesn't enforce anything on the user of the module. Even if you want to extend the package, by subclassing or monkey-patching in additional methods.
use strict only applies to the file it is used within. (Or if it's used within a pair of curly braces, it only applies up until the closing brace.) So if you're extending a package, just do it within a separate file, and none of the pragmas applied in the original module will apply to your code.
That said, it's rarely a good idea to not use strict. There are occasional tasks where it might be useful to disable it in a small scope, but the problem you are describing doesn't seem to be one of them.
In particular, if you're building a deeply nested structure, only don't need to declare every level. Demonstration:
use strict;
use warnings;
use Data::Dumper;
my $root;
$root->{trunk}{branch}{leaf} = 42;
print Dumper($root);

Why shouldn't I use UNIVERSAL::isa?

According to this
http://perldoc.perl.org/UNIVERSAL.html
I shouldn't use UNIVERSAL::isa() and should instead use $obj->isa() or CLASS->isa().
This means that to find out if something is a reference in the first place and then is reference to this class I have to do
eval { $poss->isa("Class") }
and check $# and all that gumph, or else
use Scalar::Util 'blessed';
blessed $ref && $ref->isa($class);
My question is why? What's wrong with UNIVERSAL::isa called like that? It's much cleaner for things like:
my $self = shift if UNIVERSAL::isa($_[0], __PACKAGE__)
To see whether this function is being called on the object or not. And is there a nice clean alternative that doesn't get cumbersome with ampersands and potentially long lines?
The primary problem is that if you call UNIVERSAL::isa directly, you are bypassing any classes that have overloaded isa. If those classes rely on the overloaded behavior (which they probably do or else they would not have overridden it), then this is a problem. If you invoke isa directly on your blessed object, then the correct isa method will be called in either case (overloaded if it exists, UNIVERSAL:: if not).
The second problem is that UNIVERSAL::isa will only perform the test you want on a blessed reference just like every other use of isa. It has different behavior for non-blessed references and simple scalars. So your example that doesn't check whether $ref is blessed is not doing the right thing, you're ignoring an error condition and using UNIVERSAL's alternate behavior. In certain circumstances this can cause subtle errors (for example, if your variable contains the name of a class).
Consider:
use CGI;
my $a = CGI->new();
my $b = "CGI";
print UNIVERSAL::isa($a,"CGI"); # prints 1, $a is a CGI object.
print UNIVERSAL::isa($b,"CGI"); # Also prints 1!! Uh-oh!!
So, in summary, don't use UNIVERSAL::isa... Do the extra error check and invoke isa on your object directly.
See the docs for UNIVERSAL::isa and UNIVERSAL::can for why you shouldn't do it.
In a nutshell, there are important modules with a genuine need to override 'isa' (such as Test::MockObject), and if you call it as a function, you break this.
I have to say, my $self = shift if UNIVERSAL::isa($_[0], __PACKAGE__) doesn't look terribly clean to me - anti-Perl advocates would be complaining about line noise. :)
To directly answer your question, the answer is at the bottom of the page you linked to, namely that if a package defines an isa method, then calling UNIVERSAL::isa directly will not call the package isa method. This is very unintuitive behaviour from an object-orientation point of view.
The rest of this post is just more questions about why you're doing this in the first place.
In code like the above, in what cases would that specific isa test fail? i.e., if it's a method, in which case would the first argument not be the package class or an instance thereof?
I ask this because I wonder if there is a legitimate reason why you would want to test whether the first argument is an object in the first place. i.e., are you just trying to catch people saying FooBar::method instead of FooBar->method or $foobar->method? I guess Perl isn't designed for that sort of coddling, and if people mistakenly use FooBar::method they'll find out soon enough.
Your mileage may vary.
Everyone else has told you why you don't want to use UNIVERSAL::isa, because it breaks when things overload isa. If they've gone to all the habit of overloading that very special method, you certainly want to respect it. Sure, you could do this by writing:
if (eval { $foo->isa("thing") }) {
# Do thingish things
}
because eval guarantees to return false if it throws an exception, and the last value otherwise. But that looks awful, and you shouldn't need to write your code in funny ways because the language wants you to. What we really want is to write just:
if ( $foo->isa("thing") ) {
# Do thingish things
}
To do that, we'd have to make sure that $foo is always an object. But $foo could be a string, a number, a reference, an undefined value, or all sorts of weird stuff. What a shame Perl can't make everything a first class object.
Oh, wait, it can...
use autobox; # Everything is now a first class object.
use CGI; # Because I know you have it installed.
my $x = 5;
my $y = CGI->new;
print "\$x is a CGI object\n" if $x->isa('CGI'); # This isn't printed.
print "\$y is a CGI object\n" if $y->isa('CGI'); # This is!
You can grab autobox from the CPAN. You can also use it with lexical scope, so everything can be a first class object just for the files or blocks where you want to use ->isa() without all the extra headaches. It also does a lot more than what I've covered in this simple example.
Assuming your example of what you want to be able to do is within an object method, you're being unnecessarily paranoid. The first passed item will always be either a reference to an object of the appropriate class (or a subclass) or it will be the name of the class (or a subclass). It will never be a reference of any other type, unless the method has been deliberately called as a function. You can, therefore, safely just use ref to distinguish between the two cases.
if (ref $_[0]) {
my $self = shift;
# called on instance, so do instancey things
} else {
my $class = shift;
# called as a class/static method, so do classy things
}
Right. It does a wrong thing for classes that overload isa. Just use the following idiom:
if (eval { $obj->isa($class) }) {
It is easily understood and commonly accepted.
Update for 2020: Perl v5.32 has the class infix operator, isa, which handles any sort of thing on the lefthand side. If the $something is not an object, you get back false with no blowup.
use v5.32;
if( $something isa 'Animal' ) { ... }