Warnings are the new test failures 3
Have you ever tried to run Rails, Rspec, Rake or, for that matter almost any Ruby library or application that you’ve ever heard of with the -w flag? How about running Rails with taint checking on?
They aren’t exactly pleasant experiences.
Meanwhile, over in Perl land, it’s a very rare module indeed that isn’t at least clean under -w and, where appropriate, taint friendly. It would be a very irresponsible Perl Monger indeed who wrote a web framework that didn’t assume it was going to be running under the -T flag. Warnings and taint checking are annoyances, and sometimes they’re flat out wrong, but more of the time they’re useful. Which is why, in Perl, you’ll sometimes see blocks of code like:
{
no warnings;
# Code that does stuff which would trigger a warning
}If the author is being particularly careful, she will specify which warnings to suppress – after all, there’s no need to turn off all the warnings if all you’re intending to do is redefine a method. So the prudent Perl programmer would write:
{
no warnings 'redefine';
# Code that redefines an existing method
}However, there are often ways of achieving your aim even with all the warnings on.
If modules that don’t have use warnings are rare on CPAN, modules that don’t have use strict will get the unwary programmer laughed at in the street. There are modules that simply won’t work under use strict, but they tend to have no strict, either wrapped around the narrowest scope that won’t work under strict, or proudly displayed up front. The presence of a no strict implies to the interested reader that the programmer knows (or thinks he knows) what he’s doing. Writing code that does even the most implausible metaprogramming things without raising errors from strict or spamming STDERR with warnings is a matter of professional pride. Writing straightforward code that stays silent is the absolute baseline for Perl programming professionalism in my book.
Meanwhile, here in Rubyworld, there’s no equivalent of strict and it’s actively hard to start coding with warnings turned on because important frameworks like rspec and rails aren’t -w clean. In Perl, this isn’t a problem, use warnings turns warnings on lexically. Your code might well call all sorts of noisy code elsewhere but, unless you’re running with -w as well, you’ll only see the warnings for your code. If you set $VERBOSE, you’ll get all the warnings. Warnings in the log file should be like red Fs in your test output – a sign that all is not as good as it could be in your code. Sure you could just ignore the ones you know are harmless, then you’re in danger of losing the real problems in the noise.
As a gesture of goodwill, here’s alias_method_chain written so it should raise no warnings except when the ‘without’ method already exists.
def alias_method_chain(target, feature)
aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
yield(aliased_target, punctuation) if block_given?
with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation", "#{aliased_target}_without_#{feature}#{punctuation}"
alias_method without_method, target
remove_method target # Warning begone!
alias_method target, with_method
case
when public_method_defined?(without_method)
public target
when protected_method_defined?(without_method)
protected target
when private_method_defined?(without_method)
private_target
end
end
There are some that say warnings should be compile failures (or the equivalent, in dynamic languages)!
I think the cpan installer also runs tests while rubygems doesn’t, and well, there is CPANTESTER. The Perl community is ahead in many things :)
Anyway, considering that ruby specs rely on stuff like foo.should == bar, which would always give a warning, I guess it’s pretty normal that they don’t work with -w.
But IIRC ruby already runs with warnings half-turned on, since $VERBOSE is set to nil while it should be explicitly set to false to avoid all warnings.
As for block-local warning disableing.. well it can be done in through $VERBOSE (not thread-safe) with blocks, and was actually done.. err.. you can look up “chainsaw infanticide maneuver” to find out a.. mh.. funny tale about it.
Hmm… yes, but even if rspec eliminated everything but the
useless use of == in a void contextwarnings, it would be a good thing. Sadly, the lack of a$SIG{__WARN__}equivalent means that you can’t doActually, even if you did have
SIG[__WARN__]to play with, it wouldn’t help because ruby’scallerjust returns an array of strings and there’s no way of getting at their associated stack frames and bindings.The Chainsaw Infanticide incident occurred because the only way to temporarily alter the behaviour was through dynamic scoping (altering the thing for the duration of the block), rather than through lexical scoping (altering the thing for the extent of the block). Dynamic scoping buys you many of the cool things associated with spooky action at a distance, but buys you even more of the bad things associated with it. Lexically scoped behaviour alteration mitigates most of the bad stuff.
In these days of YARV and Rubinius, I wonder how hard it would be to arrange things so that caller returned strings with singleton
bindingaccessors hanging off them…