Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Re: Why use warnings? -w

by davido (Cardinal)
on Feb 22, 2018 at 18:03 UTC ( [id://1209776]=note: print w/replies, xml ) Need Help??


in reply to Why use warnings? -w

I wanted to follow up despite having already posted in this thread, so that I can address some specific questions you ask more directly:

WHAT EXACTLY HAPPENS IF I START USING UNINITIALIZED VARIABLES IN PERL?

Perl's data types are polymorphic, and its operators are generally monomorphic. This contrasts with languages like C++ where operators are polymorphic and datatypes are monomorphic (though with carefully crafted parametric templates you can get away with treating data as generic, which isn't the same as polymorphic but often feels the same).

Observe the following:

use strict; use warnings; use Devel::Peek; no warnings 'uninitialized'; my $c; is_defined('Beginning state: $c is ', $c); Dump($c); print "\n$c\n"; is_defined('State after printing: $c is ', $c); Dump($c); print "\n", (0 + $c), "\n"; is_defined('State after integer operation: $c is ', $c); Dump($c); $c = 0 + $c; is_defined("\nState after assignment: \$c is ", $c); Dump($c); $c = undef; is_defined("\nState after assigning undef: \$c is ", $c); Dump($c); sub is_defined { my ($msg, $value) = @_; print $msg, (defined $value ? '' : 'not '), "defined.\n"; }

This produces the following output:

Beginning state: $c is not defined. SV = NULL(0x0) at 0x1f5cec0 REFCNT = 1 FLAGS = () State after printing: $c is not defined. SV = PV(0x1f3de10) at 0x1f5cec0 REFCNT = 1 FLAGS = () PV = 0 0 State after integer operation: $c is not defined. SV = PVNV(0x1f3c0d0) at 0x1f5cec0 REFCNT = 1 FLAGS = () IV = 0 NV = 0 PV = 0 State after assignment: $c is defined. SV = PVNV(0x1f3c0d0) at 0x1f5cec0 REFCNT = 1 FLAGS = (NOK,pNOK) IV = 0 NV = 0 PV = 0 State after assigning undef: $c is not defined. SV = PVNV(0x1a0f0d0) at 0x1a2fec0 REFCNT = 1 FLAGS = () IV = 0 NV = 0 PV = 0

The meaning of this is a little opaque because it's exposing Perl's internals, but I'll try to explain:

Beginning state: We have declared $c but have not assigned it a value. We can easily detect that it is not defined. And when we Dump it using Devel::Peek, we can see that the structure represented by the variable $c, located at 0x1f5cec0, contains a null pointer for its payload. This is one of the ways that 'not defined' manifests internally.

Next we include $c in a print statement. But more importantly, we interpolate it into a string. This would generate an undefined value warning if we had that warning enabled, but we explicitly disabled it. String interpolation is provided by the qq{...} quote like operator (or "..."). This monomorphic operator needs its operand to be a sting, so Perl's polymorphic scalar type morphs into a string. And we can see that this impacted the underlying struct. We still are told that $c is not defined, but we also see that the struct has gained a PV (a pointer value), which is a pointer to a string. The payload is represented by PV(0x192ae10).

Next we include $c in an integer mathematical operation: 0 + $c. In this case $c isn't being assigned a value, it's just being treated as a number. And in the Dump() output we can see that the structure has morphed again. Now the payload isn't just a PV(...), but a PVNV(...), or Pointer Value / Numeric Value payload structure. Additionally, whereas before we had a PV = 0 field (a 0 pointer to the actual empty string), we now have a PV, IV, and NV field (all of them with =0 because no value has been assigned). IV stands for Integer Value.

Next we assign an integer to $c by doing this: $c = $c + 0. In this case the undefined value is promoted to its numeric representation, which is 0, so $c = 0 + 0. This would also trigger a warning, but we have suppressed the warning for now. And now if we dump the internals we see that the NOK and pNOK flags are set. This means several things, but most important now is that we are known to Perl to be defined for numeric and stringification purposes.

Finally, we assign undef to $c. You might think this gets us back to our beginning state, but it doesn't. It retains the previous payload structure, but its contents are cleared, and the "I'm defined as a..." flags (NOK, pNOK) are revoked.

In many ways this is an oversimplification, but the points I'm trying to get at are that performing operations on undefined values do alter the internal structure of the value in various ways, and as we've seen, it is pretty easy for an undefined value to get promoted to an empty string or a number behind the scenes while remaining undefined outwardly.

So what happens if you start using uninitialized variables? Not much. It's fine if you do it correctly. It's error prone if you do it incorrectly.

ARE MY PERL SCRIPTS GOING TO RUN SLIGHTLY FASTER IF I DON'T USE STRICT AND WARNINGS?

Not really. A script containing only use strict and use warnings, and nothing else loads and compiles about 1/1000th of a second slower. The use of lexical variables as opposed to package globals is not significantly different from a performance standpoint either. Not enough to ever care about. It might be within the margin of error even trying to detect a difference.

What else happens if I quit using the "warnings" and "strict"?

The larger and more complex your script becomes, the harder it will become to spot typos, bad assumptions, and other bugs. And if you also stop using lexical variables it will become harder and harder to deal with spooky action at a distance that coincides with the use of globals. Also by not using lexical variables you don't get to benefit from the cool things that lexical scoping provides. Your code remains stuck forever in an unmaintainable state that suffers from not leveraging Perl's capabilities effectively.

if I refer to A in my function, then when I type "A = 5" it becomes a global variable. But if I initialize it as "var A = 5" then it becomes a temporary variable that exists only within the scope of that function. Is Perl treating variables the same way?

The semantics are similar in some ways. Variables that are not declared is not the same as variables that are not defined. You might be conflating those two principles. But let's look at what happens when a variable is not declared: When you say $abc = 5, the variable springs into existence as a package global. If you are in package main, then its fully qualified name is $main::abc. This variable exists throughout the program; all modules can access it by using its fully qualified name, or by importing it into their own namespace. It is a global variable accessed within its own package on a "first name basis", and from other packages on a "full name" basis.

When you say my $abc, you are creating a lexical variable. Its scope is constrained to the life cycle of the lexical block in which it lives. Life cycle is important here; A subroutine's life cycle is from when it starts running until when it stops; the variable gets created, used, and then torn down. The next time the subroutine is called, there is no recollection of previous runs of the same subroutine from the perspective of its internal lexical variables. However, the life cycle of an outer-scope enclosing block may be greater. This provides the powerful tools such as generating closures, and is useful in recursion / reentrance, and so on. If you avoid using lexical variables, you are not using Perl to its most effective capacity, and your scripts will suffer from becoming more unmaintainable. But on the other hand, you can write unmaintainable code even using the best tools any language has to offer.


Dave

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1209776]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (5)
As of 2024-04-23 16:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found