[Chicago-talk] theft is good

Jim Thomason jthomasoniii at yahoo.com
Tue Feb 17 14:40:04 CST 2004


So, as I implement a notification center in perl, it
occurred to me:

Are there any useful concepts or techniques that you
guys have stolen from other languages?

Surely, cool though perl is, it's not the be-all,
end-all of development. Other groups have different
paradigms, different thoughts, different constructs,
different approaches. And it's silly to ignore them
just because they're not perl. The good things can be
adapted and made perl-ish and we end up with new
techniques and approaches and more tools. More tools
are always a good thing. Golden hammers are scary.

So what, if anything, have you guys pirated from other
languages? Surely, LISP must do something neat that
we'd like. Or Ruby. Or Ada. I'd assume that someone
out there somewhere has looked at a perl problem and
said, "Hrm, this would be so much easier if I only had
(insert feature) from (insert language). Hey! I'll
just write it!"

Me? I've swiped two concepts from objective-c (well,
the cocoa foundation frameworks, specifically (well,
they also may not have originated there, but it's
where I got exposure to them)) and incorporated them
into my code. I'll be swiping more in the future, I'm
sure.

Right now I found immediate need for delegates and a
notification center.

delegates allow you to extend objects without
subclassing. This is useful for times when a
particular behavior is nonstandard and makes
subclassing excessive. It's easy to implement.

#make your class aware of it having a delegate, using
#whatever technique is appropriate for your system.
__PACKAGE__->add_attribute('delegate');

The delegate will just be another object.

Let's assume that you have some sort of mystery class
called TableMaker. The TableMaker class creates
TableMaker objects which write out data into an HTML
table. The problem is getting the data into the
TableMaker object. Ideally, you'd like it to come in
from multiple sources. Files of different formats
(XML, text, dbm, etc.), databases, web sites, user
input, whathaveyou. Sure, you can subclass the
TableMaker and override the load_data method for each
different way to do it, but you'll potentially have a
lot of subclasses. Further, unless you have an
abstract factory in your super class, you'll need to
keep changing your code around depending upon your
data source to always have the proper subclass.

Easy solution? Use a delegate. We know from above that
our TableMaker class has a "delegate" attribute. So
now we'll use it.

#in TableMaker.

sub load_data {
  my $self = shift;

  my $data = undef;

  if (defined $self->delegate) {
    $data = $self->delegate->load_data();
    $self->data($data);
  } else {
   #oops! An error, inform someone somehow.
  }

  return $data; #in case anyone wants it.
};

To use it, just set a delegate for your TableMaker.

my $tableMaker = TableMaker->new(
   'delegate' => XMLLoader->new(
                  'file' => '/tmp/file.txt'
                 )
};

Voila! Change your delegate as necessary to load from
different places. Need to load from another data
source? Then write a new delegate object to do it.

Of course, there are plenty of other delegate uses as
well.

The other thing I've swiped (the notification center)
is more complicated and did require a module. But I
also find it much much more useful. I may toss this
one up on CPAN since I don't think there's anything
that provides similar functionality.

You can get up to speed rapidly on it by reading
Apple's docs for their NSNotificationCenter class.
http://tinyurl.com/32ure

Basically, a center like this allows two objects to
communicate w/o knowing anything about each other. You
post notifications to the center, and the center doles
out the notes to anything that cares about them, or
nothing if nobody cares. A quick example may be
easiest.

#create a logging object, of some type
my $logger =
SomeLoggerPackage->new('/path/to/log/file');

#add it as an observer to our center
NotificationCenter->addObserver(
  'observer' => $logger,
  'notification' => 'weasels',
  'method' => 'log'
);

#and post a notification.
NotificationCenter->postNotification(
 'object' => $the_hen_house,
 'notification' => 'weasels',
 'args' => ["There are weasels in the hen house"]
);

Voila! $the_hen_house object posts a weasels
notification and then goes on doing whatever it was
doing before. The notification shows up in the center,
which looks to see if anything is observing such
notifications. In this case, we have our $logger
object which cares, and it'll call its log method on
the arguments. In short, the posting to the center
causes this to happen:

$logger->log("There are weasels in the hen house");

But the $the_hen_house object doesn't need to know or
worry about the fact that the logger is logging it. If
you later decide that you don't want to log, then
remove the observer (or never add it, whichever is
appropriate). If you want to do something else in
addition, then add another observer.

NotificationCenter->addObserver(
  'observer' => $shotgun  
  'notification' => 'weasels',
  'method'   => 'fire'
);

Now when the hen house posts its 'weasels'
notification, it gets logged to the log file, and the
shotgun fires. All without the hen house's needing to
know anything. It's just letting it be known that
there are weasels and leaves it up to any other
interested objects to respond appropriately.


And I wouldn't be using either of those if I didn't
know objective-C.

So what about everyone else? Any other
tips/tricks/techniques/etc that you've swiped from
another language or environment and use in perl now?

The more tools, the better. :)

-Jim...

__________________________________
Do you Yahoo!?
Yahoo! Finance: Get your refund fast by filing online.
http://taxes.yahoo.com/filing.html



More information about the Chicago-talk mailing list