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 ]

pdcawley (485)

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

Journal of pdcawley (485)

Wednesday March 06, 2002
08:16 AM

Things we can learn from Smalltalk

[ #3320 ]

Okay, if you're not interested in Object Orientation, move right along the bus...

I've been reading a good deal of stuff about Smalltalk recently, including a collection of Kent Beck's columns for the Smalltalk Report and there's some really good stuff in there. Kent's really big on intention revealing code. He argues that, by careful choice of names allied to sensible decomposition of 'large' methods, you end up with code that is, to all intents and purposes, self documenting.

Here's an example of this, written in Smalltalk. (The essentials, for understanding: ^ means 'return the value of the following expression'. @ is a method of Number that takes another Number and returns a Point.)

    ^(self textWidth + self leftBorder + self rightBorder + self margin) @ (self textHeight + self topBorder + self bottomBorder + self margin)

Even if you understand Smalltalk syntax, this isn't exactly a model of clarity. One option is to introduce some temporary variables to explain what's going on:

    | x y |
    x := self textWidth + self leftBorder + self rightBorder + self margin.
    y := self textHeight + self topBorder + self bottomBorder + self margin.
    ^x @ y

And there's not denying that it's much clearer. But the best way of doing it is to apply Beck's Composed Method pattern:

    ^self width @ self height

    ^self textWidth + self leftBorder + self rightBorder + self margin

    ^self textHeight + self topBorder + self bottomBorder + self margin

Now let's look at that same composed method done in Perl.

sub extent {
    my $self = shift;
    [$self->width, $self->height];

sub width {
    my $self = shift;
    $self->text_width + $self->left_border + $self->right_border + $self->margin

sub height {
    my $self = shift;
    $self->text_height + $self->top_border + $self->bottom_border + $self->margin

I confess that, looking at the perl rendition of this, I start to see why people think it's ugly, that repeated my $self = shift line at the top of each and every method definition is visual cruft. In some sense it's there for Perl's benefit and not for the programmer. If you've read Tufte you may have come across the idea of data ink. In the Smalltalk example, almost every character is data ink. In the perl example, 17 chars of every method are 'wasted' with repetition.

Maybe that's why even relatively well factored Perl OO systems have fewer, larger methods than a Smalltalk system that does the same thing.

So, I'm seriously considering writing myself a source filter that will allow me to write:

method extent {
    return [$self->width, $self->height];

or maybe even

method reduce ($initial_value, $a_coderef, @list) {
      $initial_value = $a_coderef->($initial_value, $_) for @list;
      return $initial_value

I think this is going to be relatively simple to write; I'm not after anything fancy in terms of argument list parsing or anything. The problem is, of course, that doing it right involves having to parse perl, but I'm hoping that Text::Balanced will be good enough.

Oh, for a perl version of Scheme's define-syntax; I'm keeping my fingers crossed for Perl 6...

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.
  • Minor nit - you don't *need* to use shift if you don't want to; e.g.

    sub extent{ [$_[0]->width;$_[0]->height] }

    Not as pretty perhaps, but then if you want pretty I'd recommend Ruby over Smalltalk. Another problem I have with Smalltalk is that there are too many versions and most aren't free.

    Here at work I've heard that the Smalltalk developers are stuck with a 10 year old version of the language because someone, now long gone, overloaded some of the base classes a long time ago. No one knows

    • Erm. I think you may be missing the point here. $_[0] is a very, very long way from being an intention revealing variable name.

      And I'm not seriously considering moving to Smalltalk, I'm just trying to learn lessons from the experience of top class Smalltalkers. (Something which is obviously going on in the Ruby world)
      • Its a nasty hack, and it does use the deparser (once again). Under strict your original code will barf. No real way around that. I know it could be done with a source filter, but I don't like source filters, so its done with deparse instead.

        package Attribute::Method;
        use strict;
        use warnings::register;
        use Attribute::Handlers;

        sub UNIVERSAL::method : ATTR(CODE) {
            my ($package, $symbol, $referent, $attr, $data) = @_;
            my $b = B::Deparse->new();
            my $code = $b->c
        • /me points to CPAN!

          Please upload that. It's awesome!
        • Nice hack. But I'm afraid the caveats are too many and various for me... Closure issues, deparse inaccuracies, not necessarily working desperately well for classes that get loaded at runtime, that sort of thing.

          Source filters definitely slow startup, but you can amortize that with long lived processes and if you wanted speed, why are you programming in perl and, more especially, why are you doing it with perl OO?

          Repeatedly recompiling the code looks scary... doesn't this work just as well:

          sub UNIVERSAL
          • yup thats better.

            Like I said, it was a quick hack in reaction to your post about wanting to be able to do it.

            It can be done.

            You have to know the caveats.

            It saves ink.

            You shouldn't be doing anything too clever in methods anyway, if they are small enough (I've been reading the same book Piers :-)

            Simple methods should deparse ok (esp. with modern perls [read: blead]). However, if you are performing some sort of magic then its always going to be complicated, no matter what language you're writing code in
            • It's a jolly good book isn't it? Kent Beck is a very wise man (and SmallTalk Best Practice Patterns is far and away the best patterns book (that isn't be Alexander et al) I've ever read; the patterns actually hang together as a pattern language)).

              I take your point though. The real killer for me is that, last time I played with it, Attributes didn't work that well with runtime loading of classes (which can be remarkably useful...)