use UNIVERSAL::require 'fatal'

Ovid on 2006-08-14T18:32:20

Due to seeing some code which doesn't check to see if $module->require succeeded when using UNIVERSAL::require, I've submitted a patch which lets you change this:

use UNIVERSAL::require;
$module1->require or die $@;
$module2->use     or die $@;

To this:

use UNIVERSAL::require 'fatal';
$module1->require;
$module2->use;

Here's hoping I didn't miss anything funky.

Apparently the second example used to be the default behavior. Why it was changed I don't know. However, I've heard people didn't want it changed back because it would break their code, so I think my patch is completely backwards compatible.


Simplicity please?

jjore on 2006-08-14T19:36:30

Am I just getting to be a fuddy duddy or something? I'd much rather see a simple eval("use $module") than even more magic UNIVERSAL things.

This just doesn't look like the kind of thing that benefits by adding sugar.

Re:Simplicity please?

Ovid on 2006-08-14T19:51:35

Regardless of whether or not you like it, the fact remains that tons of folks are actually using this module so if you can make it easier to use, that's a plus. Also, think of the work involved in making eval automatically die. In this case, I think the UNIVERSAL::require code is actually simpler.

Re:Simplicity please?

jjore on 2006-08-14T20:03:14

eval "use $module";
die $@ if $@;

That's hard? I gotta say, I'm really leery of adding more methods to UNIVERSAL::. There has to be a good reason and I kind of think UNIVERSAL::require might be a bad done. Maybe no one should have ever used that. ->require is at best, a class method and not something you'd want to be valid on an object. ->require is at best... maybe something that falls within the scope of something like Class::MOP.

Re:Simplicity please?

Ovid on 2006-08-14T20:20:55

Agreed, it should be that simple, but frankly, if I'm working on a rotten code base with this ...

open FH, 'somefile.txt';

... the I want this ...

use Fatal qw< :void open close >;

... or at least this ...

use Fatal qw< open close >;

And frankly, this isn't really that bad. Yes, it would be far better if people explicitly checked the return calls. On the other hand, if done properly, these are exceptional events that should rarely occur. Thus, the occasional problem with having a less than perfect error message is mitigated by the fact that at least I have an error message. If I work on code which uses UNIVERSAL::require, I would at least like to make it easier to throw a fatal exception on failure.

Previous Behaviour

Smylers on 2006-08-15T03:13:53

Apparently the second example used to be the default behavior. Why it was changed I don't know.

It appears that even the author is puzzled as to why he did that.

However, I've heard people didn't want it changed back because it would break their code,

Indeed, the proposal got many complaints that this would break backwards compatibility, so the author decided not to go ahead (after accepting a syntax improvement that made things not quite so bad).

so I think my patch is completely backwards compatible.

Unfortunately not, for reasons previously discussed (twice): UNIVERSAL is universal.

It occurred to me that having the method croak when invoked in void context might work: this would still be backwards incompatible, but not for anybody who's currently checking the return value and doing something appropriate with it. Code which is already invoking it in void context is broken anyway (quite possibly because the author was expecting errors to be fatal) and this behaviour change would probably be an improvement.

The main disadvantage I can see of doing this is that if you get into the habit of calling it without checking the return value then it becomes too easy to unthinkingly (or even unknowingly) do so somewhere that isn't actually void context, such as in the final line of a subroutine.

Perhaps just having a warning when invoked in void context would be better: the interface would still be always to check the return value, but at least you would often get warned if you forget (or hadn't yet realized).