Slash Boxes
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Ovid (2709)

  (email not shown publicly)
AOL IM: ovidperl (Add Buddy, Send Message)

Stuff with the Perl Foundation. A couple of patches in the Perl core. A few CPAN modules. That about sums it up.

Journal of Ovid (2709)

Monday March 30, 2009
05:19 PM

Programmatic Enforcement Of Liskov Substitution Principle

[ #38729 ]

So you write your Employee class and some idiotic programmer writes the Employee::Volunteer subclass and it returns undef for the salary, but that violates the Liskov Substitution Principle. Languages like Perl make it hard to stop this because the subclass method calls the superclass method and can then munge it any way they want and you can't force them to respect Liskov.

Languages like Beta, however, can make this easier because its classes are patterns and a subclass is a subpattern and the patterns call the subpatterns and can guarantee Liskov by effectively reversing the direction in which methods are called via inheritance. Superclass methods call subclass methods instead of the other way around.

So I made this work in Perl.

#!/usr/bin/env perl -l

use strict;
use warnings;

    package Employee;
    use Acme::Liskov;
    use Scalar::Util 'looks_like_number';

    sub new {
        my ( $pattern, $payrate ) = @_;
        die unless looks_like_number($payrate);
        bless { payrate => $payrate } => $pattern;

    sub salary {
        my $pattern = shift;
        if ( $pattern->is_augmented ) {
            my $salary = $pattern->inner;
            warn $@ if $@;
            die "not a number ($salary)" unless looks_like_number($salary);
            return $salary;
        return $pattern->{payrate};

    package Employee::Hourly;
    use base 'Employee';

    sub salary {
        my $subpattern = shift;
        return $subpattern->{payrate} * 40;
    package Employee::Volunteer;
    use base 'Employee';

    sub salary {
        my $subpattern = shift;
        return undef;

my $hourly = Employee::Hourly->new(5);

# prints 200
print $hourly->salary;

my $volunteer = Employee::Volunteer->new(4);

# blows up because it violates liskov
print $volunteer->salary;

The code is a massive hack (and not on the CPAN) and terribly fragile and uses some really, really nasty tricks. If you're tempted by this technique, use augment and inner from Moose.

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
More | Login | Reply
Loading... please wait.
  • my $subpattern = shift; return $pattern->{payrate} * 40;
  • The Liskov Substitution Principal is academic nonsense. Do we need to have the Pathname debate again?

    What I really need to do is write an article on why PhD's should never be trusted.

    • Your Turing Medal is in the post

    • I agree that treating it as an absolute rule is nonsense. But the basic principle - that you should be able to expect that objects of a subclass can be safely used in place of objects of a class - is sound. Furthermore in complex OO code it is common to have subclasses accidentally override methods of parent classes that they did not know about. And these cases area almost always real bugs.

      Therefore the Liskov Substitution Principle is a rule of thumb to be aware of, and there is value in catching accide

    • I can only assume you're referring to your response to my O'Reilly Liskov write-up []. I didn't respond to you then, but since you've mentioned this twice, I feel compelled to respond: you've picked a most unfortunate counter-argument. I have a lot of respect for you and I'm sorry to be so blunt, but but consider what you wrote:

      Is a Path a kind of String? Yes. Can I choose to implement a Path class as a subclass of String. If we follow the LSP then the answer to the second question is no and I must delegate all string-like methods...

      A Path is a kind of String? By no stretch of the imagination is a path a type of string. A path represents a place on a disk. A directory structure is a tree and a path could be c

      • I should point out that in the real world, hierarchical representations don't always work and that's part of the reason why Liskov can seem problematic. It's one of the many limitations of OO which causes people to misunderstand many fundamentals. That's why I'm so bullish on roles. I suspect they can help lead the way out of the OO mess we're in.

  • isn't this the problem that dynamic or duck typing solves!

    where you declare a method you don't say what type you want to go in. the documentation though would have the attributes needed from the object to perform the task or work asked to it by the method

    Ocaml, I believe have a way to declare the attributes the objects needs to have regardless of his class or type, so i think they are half way between static and dynamic sub-classing in my opinion should be only used as a purely technical method to sh
    • Duck typing is a separate issue. The issue here is something like this:

      while ( my $thing = $foo->next ) {
          $total += $thing->value;

      You want value to always return something suitable for addition. In Perl, it's awfully tough to make this "just work". As Ben Tilly points out, this shouldn't be a global "you must always ..." debate, but the general principle is sound.

      • okay, I am not sure why making sure that value always returns something suitable for addition is a big deal.

        first of all, you should not try to modify value directly, you should ask $think to modify value for you

        second if $thing know how to perform addition on value, $thing will comply

        there are so many ways to know if $thing can perform addition on value

        1. ask $thing if he is of a certain type
        2. ask $thing if one of his ancestors is of a certain type
        3. according to your liskov, ask $thing if one of his deri

        • The principle is that if an OO class supports a given internal and external API, then any subclasses should support that API. If the parent class promises that a given method returns something that can be added, then subclasses should do likewise. If the parent class makes errors available through a particular mechanism, subclasses should do likewise. And so on.

          In short one should be able to use an object blessed into the subclass instead of an object blessed into the parent class and nothing should brea

          • The principle is that if an OO class supports a given internal and external API, then any subclasses should support that API.

            Nitpick: the principle talks about subtypes, not subclasses. This is an important distinction, as subtyping relationships do not require inheritance. (I see that someone has proposed merging the LSP page into the Inheritance page on Wikipedia. That disappoints but does not surprise me.)