Perl: Redefining all methods of a parent class with a single method

Viewed 71

I am writing a file manager for my Perl application. Information about each file is kept as an object. When I remove a file, I'd like to change the corresponding object's class to RemovedFile. For this class, call to any valid method of "File" would return a fatal error and a stack trace. This would be to catch cases where some stale reference to this object is kept (while it shouldn't).

I thought about two ways I could implement this:

  1. "RemovedFile" inherits from "File" and redefines all its methods with a call to fatal error. Downside to this is that if I add a new method to "File" I need to add it to "RemovedFile" as well.

  2. Adding a call to some empty method to every method of "File". "RemovedFile" would redefine this one method to report fatal error. (See code below for an example of what I mean). Downside to this is that every method of "File" would have to be bothered with calling the "remove_guard" in the beginning which IMO is not very clean.

# Inside File class:
sub any_method_of_file_class {
    $self->_removed_guard();
    #rest of code
}

sub _removed_guard {
    #do nothing
}

# Inside RemovedFile class redefine only _removed_guard:

sub _removed_guard {
    $self->{logger}->fatal_with_stack_trace();
}

I wanted to ask if there is any better way to implement this kind of behaviour in Perl? For example, could I use some tricks to first list and then dynamically redefine all methods of a parent class without specifying their exact names?

2 Answers

You can define the RemovedFile class without any relation to the original File class. In RemovedFile, use AUTOLOAD to handle any method.

If you want to redefine (override) all the methods of the parent class, don't inherit from the parent class. You can use the same interface, but you don't need the connection to some module you are going to completely ignore.

I think I'd probably have a factory method in File that returns a new object for RemovedFile:

 my $removed_file_obj = $file->remove;

That new class only knows what it needs to know about removed files. The remove can do whatever cleanup you require.

Then, when you are dealing with lists of objects, some of which may be File and some of which may be RemovedFile, filter the ones you want. This is outside of the class definitions because the class only defines the behavior of the objects and not how we employ the objects.

Here's one way to check by the object type, maybe even with the new isa feature:

 use v5.32;
 use experimental qw(isa);

 foreach my $file ( @files ) {
     # next if $file->isa( 'RemovedFile' );
     next if $file isa 'RemovedFile';
     ...
     }

But, you probably shouldn't check what something is. Check what it can do. Since you haven't inherited a bunch of methods that don't do anything, can should return false for that:

 foreach my $file ( @files ) {
     next if $file->can( 'some_method_not_in_RemovedFile' );
     ...
     }
Related