Think about Loose Coupling | |
PerlMonks |
Re: Why use warnings? -wby davido (Cardinal) |
on Feb 22, 2018 at 18:03 UTC ( [id://1209776]=note: print w/replies, xml ) | Need Help?? |
I wanted to follow up despite having already posted in this thread, so that I can address some specific questions you ask more directly:
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:
This produces the following output:
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.
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.
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.
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
In Section
Seekers of Perl Wisdom
|
|