Re: "use strict" not too strict
by hardburn (Abbot) on Jul 15, 2003 at 13:31 UTC
|
Because there are more ways of creating a subroutine than just declaring it. Look up the documentation for AUTOLOAD, for starters.
In other words, it's a feature, not a bug. Or rather, it is a bug, but a particularly nice one.
---- I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
-- Schemer
Note: All code is untested, unless otherwise stated
| [reply] |
Re: "use strict" not too strict
by BrowserUk (Patriarch) on Jul 15, 2003 at 13:36 UTC
|
Whilst your cow orker is correct that C wouldn't let you do that. It is also true that C won't let you create subs at runtime or autoload subs at runtime. That's not strictly true with dynamic libraries, but then C can't check whether they will be available to be autoloaded at runtime either, so that mirrors the situation in Perl.
This point is that any system that allows late binding of subroutines cannot check for their availability until runtime. The benefits of late binding are sufficiently worth while, that foregoing the benefit of static compile-time cross-checking is worth it.
If you really want full compile time checking, you could always copy the source of all the modules you use in each script directly into the script itself, and comment out the use Module::Name; lines. Each script would become enormous and maintainence would become a nightmare as you would need to edit every script that used a module every time that module was ungraded.
The choice is yours:)
Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
| [reply] [d/l] |
Re: "use strict" not too strict
by edan (Curate) on Jul 15, 2003 at 13:34 UTC
|
Well, I'm sure someone else can explain better and more technically correct, but I imagine it must have to do with the fact that you can define subroutines in perl at runtime, via things like 'do', 'require', 'eval', so perl can't check at compile-time whether a certain function-call will be defined or not when it is called... says me: "C wouldn't let you do that!" (i.e. it's a feature!)
-- 3dan
| [reply] |
(jeffa) Re: "use strict" not too strict
by jeffa (Bishop) on Jul 15, 2003 at 13:49 UTC
|
A trivial work around is to create a script like so:
my $file = shift or die "USAGE: $0 [file]\n";
open CODE, $file or die "can't read $file: $!";
my $code = do {local $/;<CODE>};
eval $code;
warn $@ if $@;
I haven't tested the robustness of this (nor am i going to
as i feel using Test suites is the better solution), but
this will work with your small example. And tell your
cow-orker that C won't let you do a lot of stuff that Perl
will! :P
jeffa
L-LL-L--L-LL-L--L-LL-L--
-R--R-RR-R--R-RR-R--R-RR
B--B--B--B--B--B--B--B--
H---H---H---H---H---H---
(the triplet paradiddle with high-hat)
| [reply] [d/l] |
|
|
if (0)
{
undefined_sub(); # no error even at runtime
}
else
{
undefined_sub2(); # error here
}
--Bob Niederman, http://bob-n.com | [reply] [d/l] |
Re: "use strict" not too strict
by demerphq (Chancellor) on Jul 15, 2003 at 16:10 UTC
|
On top of the other points made here I thinks its worth pointing out that subs are essentially package variables that our() doesnt care about (it turns out there are quite a few of them *Globs are exempt from strict as are Fully::Qualified::Items and the punctuation and magic vars). And in fact the magic involved in your example (that of exporting subs) exploits this fact. Consider this
use strict;
*foo=sub{print "foo"};
foo();
Which is in fact very close to what that use Module qw(fubar); actually does behind the scenes. When perl sees use Module qw(fubar); it doesnt think to itself "they want to alias Module::fubar() to main::fubar()" or any such declaration. Instead perl just thinks "oh, they want to pass an argument to that funny looking subroutine that happens to be a file full of subroutines, including one called import() which is in fact where I shall pass those arguments" and once the arguments are passed to import(), what import() does with them is entirely up to it. As it happens normally the result is that a line like
*"${pack}::${name}"=\&fubar;
Which is just an assignment that happens to set up the symbol table in such a way that it results in the appearance of the subroutine being "exported", which of course it isnt, it stays right where it is, and just pretends to be in both packages (if it was in fact a closure it would still be bound to the context inside the other module.)
Youll find that a lot of stuff in perl that has to do with package variables doesnt play quite as you might expect with strict, filehandles, formats etc.
---
demerphq
<Elian> And I do take a kind of perverse pleasure in having an OO assembly language...
| [reply] [d/l] [select] |
Re: "use strict" not too strict
by chip (Curate) on Jul 15, 2003 at 16:56 UTC
|
Actually, C would let you do that. It might warn you if you have your compiler options set high, but it would allow it. The shell, also, allows you to call programs without first declaring which ones you're going to call ... even though at runtime they may not be found. And that tradition is probably why Perl also allows you to call subroutines without first declaring them.
-- Chip Salzenberg, Free-Floating Agent of Chaos | [reply] |
Re: "use strict" not too strict
by tye (Sage) on Jul 15, 2003 at 22:56 UTC
|
I didn't see this mentioned yet, so I apologize if I just missed it...
You can program in a Perl style that detects mispelled subroutine names at compile-time. This requires that you pre-declare all of your subroutines1 and then never use parens when you call subroutines.
This, of course, doesn't work for method names. Compile-time checking of method names is nearly antithetical to Perl 5's OO system. (:
1 Well, you could probably instead topologically sort your subroutines, but I wouldn't recommend it.
- tye
| [reply] |
Re: "use strict" not too strict
by Mur (Pilgrim) on Jul 17, 2003 at 15:36 UTC
|
I'd just like to follow up my own post and the discussions with these observations:
Yeah, I'm quite aware of do,
require,
AUTOLOAD,
*foo tricks, etc.
I was hoping that someone might have come up with a trick that would allow an "even more strict" mode whereby you could get a warning emitted when this situation occurred.
For example, it seems like you might be able to code an END block that made a pass through your symbol table if-and-only-if you were running under "-c". I've got some time on my hands; perhaps I'll putter around in this direction myself.
| -- |
| Jeff Boes |
| Database Engineer |
| Nexcerpt, Inc. |
|
|
|
...Nexcerpt...Connecting People With Expertise
|
| [reply] [d/l] [select] |
|
|
Having puttered, I share:
#!/usr/bin/perl -w
use strict;
use English;
use vars qw($boo);
$a = foo() if 0;
sub bar {}
END {
no strict 'refs';
my $table = '::';
SYMBOL:
for my $sym (sort {lc($a) cmp lc($b)} keys %{$table}) {
next if $sym =~ /::$/ or $sym =~ /^[A-Z0-9]/;
my $name = $table . $sym;
next if $name =~ /^::\W/;
foreach my $thing qw(ARRAY HASH IO) {
if (defined *{$name}{$thing}) {
next SYMBOL;
}
}
print "Look at this!\n";
unless (defined *{$name}{CODE}) {
warn "Possible undefined routine '$sym'";
}
}
}
The problem is that *{$name}{CODE} is as expected, undef for symbol foo, and not undef for symbol bar, but it is also undef for symbol boo.
That is, there's no way to distinguish at the symbol table level between an undefined subprogram name, and a scalar, because both will have
defined(*foo{SCALAR}) && !defined(*foo{CODE})
Hmph.
| -- |
| Jeff Boes |
| Database Engineer |
| Nexcerpt, Inc. |
|
|
|
...Nexcerpt...Connecting People With Expertise
|
| [reply] [d/l] [select] |
|
|
I think this is a fantastic idea! I suspect that there is a way to distinguish these cases if someone dives a little deaper into the internals.
I'd never thought of this idea, but upon hearing it, it is such a good idea that I'd be a bit surprised if someone hasn't already tried this and perhaps succeeded (or figured out exactly why you can't do it).
Anyway, I'm very interested in seeing this tool become available. Please consider posting this as a new root node, especially if you don't get any useful responses in the next while.
Thanks much. I'm looking forward to being able to do:
perl -MDevel::ShowUndefSubs -c myScript
- tye | [reply] [d/l] |
|
|
When I test it, it does not seem that END blocks run under -c. However a CHECK block will - and the line, return unless $^C; will properly make it only run if you are running under -c.
Also it is a horrible hack, but you can test for scalars that have been declared with vars by evaling a piece of code which switches to that package and tries to access that variable. You can also test if the variable itself has a value. This doesn't, unfortunately, catch variables initialized with our. (Well I don't like our so I don't consider it that unfortunate...) However it catches vars, and it catches the common case of modules that initialize @ISA, etc while declaring them with our. (You also clear out a couple of global variables in main:: which are used by Perl internally.)
If you turn this into a module then I would think carefully about how you want to control what will be checked for errors, allowing someone to readily decide that certain packages and functions are known to be OK, or only certain ones should be checked. After all the maximum utility will happen when you can check your code, see some errors, and then OK them as you figure out that they really are OK...
| [reply] [d/l] |
|
|
| [reply] |
|
|
|
|
| A reply falls below the community's threshold of quality. You may see it by logging in. |