You quite accurately described the situation. -w includes warnings around the world (in all modules, unless they specifically disable them lexically). use warnings behaves lexically without affecting what happens in other modules.
Saying this, I do not see in it what is better. It really is a question of what kind of behavior you want. We would not say that foreach better than while without knowing the context of the statement. If you want warning behavior to be global, do it. If you want to enable warnings in a way that does not affect external modules, do this.
Warnings, in my opinion, are a development and debugging tool. I try to always program with 'on' warnings (in my own code). Regardless of whether I am deploying production code with warnings enabled, this is a completely different story. There are many factors that contribute to deciding whether to include warnings in production code. Naturally, the goal is programming without warning. Therefore, if warnings are included in the production code, and one slips, this should not happen if we have completed our work. But if someone slips through, will this information be useful to someone or not? And will the utility outweigh the added noise and potential risks of disclosing program information to unknown end users?
Regarding the topic of writing code without warning: Yes, that should always be the goal. However, there are many warnings. my @list = qw/ Just another Perl hacker, /; will cause a warning. This warning is intended to help me understand that I may have made a mistake (inserting a comma in qw // list). But, as many know, this phrase ends with a comma. A more important question is whether I really intended to make a list of words, not a single line. So let's say that I need a list of words, and one word legitimately needs a comma at the end of the word. In this case, the warning is not serious. I have two options. One, say my ( @list ) = ( 'Just', 'another', 'Perl', 'hacker,' ); , or two, say my ( @list ) = do{ no warnings 'qw'; qw/Just another Perl hacker,/; }; my ( @list ) = do{ no warnings 'qw'; qw/Just another Perl hacker,/; }; . They print a lot, and in this far-fetched example, it's probably best to just bite the bullet and use the first option. But this does not mean that the second option is a mistake, and there can be many less far-fetched examples of where a warning is undesirable.
Now let's look at a situation where it might be useful to trigger a warning in another module: you tore your hair for why you are not getting the expected results from the XYZ module. You can transfer your code using print statements, you could reset your data structure, you could plunge into the Perl debugger ... but what is wrong with the inclusion of warnings around the world, if you see something for only one run you do, creates a problem at a distance, silent failure in the module? Obviously, a reliable writing module is right for you if you feed it garbage. But should / should .... it is up to the author of the module. As for you , you can raise something to the warning that might have been quiet before. Given that this is such an easy debugging step, it might be worth a try before going through the code with the debugger.
You have already found this, but for other perllexwarn readers the difference between -w, using warnings and $ ^ W. is discussed.