November 2002 Archives

This week on Perl 6 (11/17-11/23, 2002)

And some rough beast, its hour come 'round at last slouches toward...

And then the scansion goes to pot and I can't make a joke fit. Shame.

Anyhoo, it's time for another episode of the continuing saga of Perl 6 development. When I say 'saga' I don't mean a long, long poem of alliterative lines, but a bright, breezy and brisk tale of the bods in the lists. Well, one week mayb, when we've been quiet...

We start, as usual with the internals list.

C#/Parrot Status

Rhys Weatherley, who has been absent from the internals list lo these many days popped up again to ask about:

  • Object/class support
  • Fixed-size integers and/or conversion opcodes
  • Embedding of binary extension sections

He noted that "Not Done Yet" was an acceptable answer. Which is good, because, as Leopold Tötsch pointed out, none of them were done yet. Leo also reckoned that a start would be to implement fixed size integers and conversion ops, and asked for details of what was wanted. Iacob Alin wondered if the various types would be PMCs (answer: Only those types which don't easily map to native types.) Florian Weimer wondered about trapping integer arithmetic. Dan says these will be handled using Parrots standard exception handling mechanism (which doesn't actually exist yet, but signs in the wind suggest we might be getting a Halt and Catch Fire op to raise an exception).

http://groups.google.com/groups

Parrot 0.0.9 status

According to Steve Fink: "The basic status is that lots of people, many of them coincidentally named Leopold Tötsch, have been fixing zillions of things and implementing a number of new features. Nearly everything needed for 0.0.9 has happened, and a lot else besides."

See his post for details of what's still to be done.

One of the most important items was that the tinderbox (a fleet of machines that constantly make, test and remake the latest parrot builds) was a beautiful shade of orange and red, which led to discussion of what was going on (since most people's home boxen seem to be making and testing okay...) Various remedies and patches were tried, but I believe the tinderbox is still mostly the wrong colour.

http://groups.google.com/groups

http://groups.google.com/groups

Unified core.jit

Leopold Tötsch posted an RFC in which he proposed writing a universal core.jit which provides the basic JIT framework and which delegates the generation of native ops to processor specific implementations. Daniel Grunblatt liked the basic idea, but thought there might be a case for creating cisc.jit and risc.jit to avoid piles of #ifdefs. Daniel, Leo and Nicholas Clark then spent a few posts thrashing out issues to do with parameter naming and other more or less arcane things.

http://groups.google.com/groups

Native Function calls

Dan announced that he'd redone the native function call interface and had added a new op, bnc, which stands for `build native call'. His post has the details of how it all works (and how to use it). Well, that's what he said at first, but apparently it's not true. What he's actually done is altered the dlfunc opcode to behave like bnc he described. (It's a shame you can't hit s/bnc/dlfunc/ in your mailer and have the world alter every single copy of the mail you just sent. It would have been useful for some of my previous summaries.)

Brent Dax wondered if this was going to be the new XS or if there was more coming. Answer: Sort of.

Leo Tötsch didn't like nci.c's string functions, and wondered too about places where you'd need to pass a pointer to the parrot interpreter. Dan doesn't like the string functions either, noting that the code is "evil, crufty [and] embarrassing", but that it is at least "well encapsulated, so it can be ripped out, shot, and replaced with something elegant and fast at some point in the future." As for parrot interpreter pointers, Dan reckons that any code that needs to go so far should install real extension sub PMCs.

Gopal V worried about the type safety (it's an obsession of his apparently) or rather the complete lack of it, in this interface. Dan, in a quote of the week post said yup, of course it's totally type unsafe and he liked it that way, before confessing that he was getting that `XML feeling. (You know the one--"It seemed like a good idea until I thought about it")' and started backpedalling. Gopal V made a few suggestions, and that's about where we left it.

http://groups.google.com/groups

http://groups.google.com/groups -- the correction

Leopold Tötsch, still the patch monster

Leo's contributions this week include:

  • Patches to the JIT which give a 370% speedup in mops_p.pasm
  • Patched strings to try and fix a GC issue.
  • More patches to the JIT to tidy things up

    This patch set also added i386 support for JITted floating point, which apparently makes mandel.pasm at least 10 times faster.

And that's not counting his contributions in other threads. Once again, I wonder where he finds the time.

Other patches this week from other keyboards that Leo's:

  • Op restarts

    Jason Gloudon's patch adds a new control flow flag to op.h to mark which ops can cause interpreter restarts. This information can apparently be used to improved performance in JITted code by removing the need for unnecessary checks.

  • Function <=> Data Pointer casts in nci.h

    Josh Wilmes's patch to try and correct warnings on some compilers (and 'outright breakage on tcc'). Steve Fink seemed to like it, and produced an updated version and Dan suggested that they don't worry about it too much right now as he was in the process of redoing nci.c anyway.

  • Befunge now supports PerlArray's push/pop
    Jerome Quelin is one of the "let's implement a bunch of languages on Parrot" crew, and his pet language is Befunge. If you don't know about Befunge, you're lucky, but if you don't want to stay lucky, Google will probably be depressingly informative. Anyhow, Jerome has now rewritten his Befunge interpreter to use PerlArray's push and pop rather than his older, hand crafted Parrot assembler routines. Dan committed the patch `with the appropriate amount of fear'.
  • The return of Leon Brocard

    As regular listeners will know, I try to mention Leon Brocard at least once a week. This has been tricky of late because Leon had been on holiday. And when he returned he didn't actually say that much.

    This week, he rectified that and offered a couple of patches, and a minor dilemma. The first simply improves a set of error messages, making it easier to track a couple or three problems down. However, his second patch is a little trickier.

    The thing is, Leon has implemented another programming language for Parrot. He'd posted it to the list some time ago (before my time as a summarizer I think), but it'd got out of sync with the state of the avian, so this time he offered it as a patch with its own subdirectory of languages. "So? What's the problem?" I hear you ask. The problem is the name of this language, which some people may find offensive. In a postscript to the patch, Leon suggests that a bit of creative misspelling may be in order, so I'll go that route:

    Last week, Leon Brocard posted a patch implementing a brianfuck interpreter.

    There, that was easy wasn't it?

Coo, what a remarkably long section with no associated links.

Meanwhile, on perl6-language

The `Unifying invocant and topic naming syntax' thread rumbled on. Adam Lopresto wondered what was wrong with sub bar(;$foo is given) {...}. Damian wasn't sure and reiterated his suggestion of sub foo (;$foo = $def_foo) is given($def_foo) {...}, but Larry really didn't like that (and he's not alone -- Ed.) Larry spun off a few other suggestions, one of which Damian shot down quite handily, and one of which, after couple of modifications, he quite liked. Brent Dax wondered what was wrong with just using $CALLER::_ and having done with it, which led to some muttering that the CALLER should really be a namespace of last resort for people doing bad and/or clever things and that using it just to import the caller's topic seemed like overkill. And on it went for a total of 47 posts this week. Highlights include: Damian's discussion of why it makes sense to pass the topic into a function without it appearing on the argument list illustrated with an example from Class::Contract; Andy Wardley's almost universally disliked suggestion of using $__, $___, ... to access callers' topics up the call chain; Allison Randal's handy restating of the details of what was being discussed; Andy Wardley also brought up the Law of Demeter and got ignored for his pains.

I have the feeling we haven't seen the last of this yet, things still aren't quite resolved.

http://groups.google.com/groups

http://groups.google.com/groups

http://groups.google.com/groups

http://groups.google.com/groups -- Allison's summary

http://groups.google.com/groups -- Law of Demeter

The string concatenation operator

The mammoth operator thread continues on it's merry way with a slightly morphed subject (It's now called the `string concatenation operator' thread, but it can't fool me). I think it might be slowing down though; there were only 31 posts in the thread this week.

Anyhow, Martin D Kealey opened proceedings for the week, talking about parallel processing. (And people wonder why I find this thread hard to summarize -- the subject line is almost always inaccurate, and it always seems to be going off on tangents), and the benefits of functional and applicative programming languages when compilers need to notice possible parallelism. Simon Cozens talked about typing of values (not variables), and reckoned that with reasonably strongly typed values there seemed to be no reason why + shouldn't be used for string concatenation. However, Larry reckons that not using + to concatenate strings was one of the things he got right in Perl 1. He also had some interesting things to say about the Principle of Least Astonishment.

Dan talked about threading (remember, this thread is about the string concatenation operator), which led into a discussion of the various ways of handling threading. Matt Diephouse wondered how to pass a junction to a function. It turns out to be easy; sub foo ($param is junction) {...}. But not that easy. The subthread that ensued ended up talking about what happens when some members in junction cause exceptions to be thrown when others don't, and I'm still not sure what's going on.

I don't suppose someone would like to write an article on junctions along the same lines as Allison's 'Topics' article? Or is it still way too early to do that?

http://groups.google.com/groups

http://groups.google.com/groups

http://groups.google.com/groups

Continuations

The misnamed coroutines thread continued, discussing the use of coroutines as iterators in while and for loops, which then morphed into a discussion of <<. You see, <<...>> is the ASCII synonym for «...», which is, in turn a (the?) new way of saying qw/.../ (and for vectorizing an op). Ken Fox worried that using << in this way would mean you couldn't use it for introducing a HERE doc, but Damian assured him that it wasn't a problem because " (and presumably ') would be illegal as the very first character of a <<...>> delimited list. This worried Paul Johnson slightly who paged Simon Cozens (Champion of Regularity! Smiter of the Unexpected!) who didn't show up.

Austin Hastings asked if we couldn't rename coroutine next to be bork (standing for "Break OR Kontinue" or "Brain On Raw Krack", you decide) just so he could write

   my $cheffy = $recipe.iterator;
   $cheffy.bork.bork.bork;

Damian appeared to take him seriously (well, not about the bork thing, but the post wasn't just about the silliness).

All of which eventually led to Damian's rather sensible proposal on the semantics of <...>, which is well worth a read. The rest of the thread was spent with people asking for a few clarifications.

Quote of the Thread:

   Damian: "Think Of It As Evolution In Action"
   Austin: This coming from someone whose national bird is
       the platypus

Hey, it made me laugh.

http://groups.google.com/groups

http://groups.google.com/groups

http://groups.google.com/groups

http://groups.google.com/groups -- semantics of <...>

Superpositions and Laziness

Piers Cawley failed to change the subject line as he asked about runtime class creation. He wanted to know if one could do:

    class {
        push @ISA, $parent_class;
        ...
    }

Damian sincerely hoped not. Frankly, so does Piers, what he really wants is a nice interface to Class:

    Class.new( isa => $class ) {
        method { ... }
        method { ... }
    }

But so far everybody has ignored that post...

http://groups.google.com/groups

Dynamic scoping (take 2)

Ralph Mellor posted a summary of his understanding of dynamic scoping with temp and let and went on to propose a system of implicit argument passing, intended to get 'round the perceived problem of threading and dynamic scope not playing well together. Larry pointed out that Ralph seemed to have a misapprehension about Perl threads where, unless a variable is explicitly marked as shared between threads then dynamically scoped variables work just fine. Larry went on to discuss some rather splendid extensions of the currying concept:

   use Dog.assuming(tail => "cut short", ears => "cut_long")
   my $little_dog = Dog.where_oh_where();

Which is rather cute.

http://groups.google.com/groups

http://groups.google.com/groups

Meanwhile, on the documentation list

The Documentation list continued its mission to explain, spending the week working on Numeric Literals, producing a 5th summary of what is known.

http://groups.google.com/groups

In brief

Last week, Brent Dax stated that we'd have to write Perl6 in Perl 'because otherwise we can't have the self modifying grammars'. Which caused Simon Cozens to wonder why he'd been spending so much time writing self modifying parsers in C.

Joseph F. Ryan has been writing tests for numeric and string literals and keeping them in sync with discussions on perl6-documentation. Thanks Joseph.

David Robins wondered when the long double bug would be fixed. Nobody quite knows, but Dan is working on it, once he gets a compiler back up on his long double machine.

Who's Who in Perl 6?

Who are you?
Nicholas Clark
What do you do for/with Perl 6?
Lurk. Sadly I usually generate more e-mail than code. I sometimes dabble in fixing compiler warnings, the ARM JIT, and anything else that seems interesting to me. It's a good thing I'm not expected to do anything important, as parrot would never get finished if were.
Where are you coming from?
Well, porting Perl5 to RISC OS, then getting gradually sucked into being a core Perl5 porter. I keep seeing things that look fun to implement which no-one else seems to want to do, so I try to implement them myself.
When do you think Perl 6 will be released?
Before perl 5.10 However, I doubt Perl 6 will be ready by 1st April next year :-(

I believe that the parrot engine will become substantially useful by the middle of next year. However, I expect that the Perl 6 language design will not be complete by then, let alone implemented, let alone implemented optimally. So I suspect that the first real users of the parrot engine will be "other" languages. It's a shame that many of the major dynamic languages which could be implemented on top of parrot don't have anywhere near the level of regression tests that Perl does, as I'm told that this lack of tests makes it much harder to go about writing a re-implementation. I blame Schwern for making it too easy for Perl people to write tests :-)

Why are you doing this?
The perl5 internals are a complete mess. It's like Jenga - to get the perl5 tower taller and do something new you select a block somewhere in the middle, with trepidation pull it out slowly, and then carefully balance it somewhere new, hoping the whole edifice won't collapse as a result. The only long term solution to the perl5 internals is a complete re-write, and far too many corner cases of perl5 (as well as all of XS) actually depend on how bits of the internals work, so an internals only re-write isn't going to be possible without some changes at the language level. And as the language itself has to change, then it might as well progress too.
You have 5 words. Describe yourself.
incorrigible pragmatic noisy pedantic perfectionist
Do you have anything to declare?
I've probably just contradicted myself. It wouldn't be the first time. On, and I can't code anywhere near as fast as I can talk. Sorry.

Acknowledgements

Proofreading was once again provided by Aspell and myself. I really should start writing this thing on Mondays again, then I'd have time to get it properly proofread by other human beings. Ah well. Next week.

I've been getting some interesting mail recently about Perl 6 and what it's doing from people who aren't active on the mailing lists, to the extent that I'm thinking of adding a `letters to the editor' section (assuming I ever find the time). Is this a good idea? Am I even madder than you thought I was? What day is this? Are you the nurse? Only they tell me I'm not supposed to talk to strangers...

Ahem.

Here's the chorus once more:

If you didn't like the summary, what are you doing still reading it? If you did like it, please consider one or both of the following options:

The fee paid for publication of these summaries on perl.com is paid directly to the Perl Foundation.

Class::DBI

Several articles on Perl.com, including the recent Phrasebook Design Pattern, have discussed the problems faced when writing Perl code that interacts with a database. Terrence Brannon's DBIx::Recordset article attempted to show how code dealing with databases can be made simpler, and more maintainable. In this article, I will try to show how Class::DBI can make this easier still.

Class::DBI prizes laziness and simplicity. Its goal is to make simple database interactions trivial, while leaving the hard ones possible. For many simple applications, it replaces the need for writing SQL entirely. On the other hand, it doesn't force you to build complex data structures to specify a complex query; if you really need the power or expressiveness of raw SQL, then it gets out of your way and lets you drop back to that.

The easiest way to see Class::DBI in action is to build a simple application with it. In this article, I'll build a tool for performing analysis on my telephone bill.

Data::BT::PhoneBill (available from CPAN), provides a simple interface to a phone bill downloaded from the BT Web site. So, armed with this module, and a few recent phonebills, let's store these details in a database, and see how to extract useful information from them.

Class::DBI works on the basis that each table in your database has a corresponding class. Although each class could set up its own connection information, it's a better idea to encapsulate that connection in one class, and have all the others inherit from that. So, we set up our database, and create the base class for our application:


  package My::PhoneBill::DBI;

  use base 'Class::DBI';

  __PACKAGE__->set_db('Main', 'dbi:mysql:phonebill', 'u/n', 'p/w');

  1;

We simply inherit from Class::DBI and use the 'set_db' method to set up the connection information for our database. That's all we need in this class for now, so next we set up our table for storing the phone call information:


  CREATE TABLE call (
    callid      MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
    number      VARCHAR(20) NOT NULL,
    destination VARCHAR(255) NOT NULL,
    calldate    DATE NOT NULL,
    calltime    TIME NOT NULL,
    type        VARCHAR(50) NOT NULL,
    duration    SMALLINT UNSIGNED NOT NULL,
    cost        FLOAT(8,1)
  );

For this, we set up a corresponding class:


  package My::PhoneBill::Call;

  use base 'My::PhoneBill::DBI';

  __PACKAGE__->table('call');
  __PACKAGE__->columns(All   => 
    qw/callid number destination calldate calltime type duration cost/);

  1;

We inherit our connection information from our base class, and then specify what table we're dealing with, and what its columns are. Now we have enough to populate the table.

So, we create a simple, "populate_phone_bill" script:


  #!/usr/bin/perl

  use Data::BT::PhoneBill;
  use My::PhoneBill::Call;

  my $file = shift or die "Need a phone bill file";
  my $bill = Data::BT::PhoneBill->new($file) or die "Can't parse bill";

  while (my $call = $bill->next_call) {
    My::PhoneBill::Call->create({
      number      => $call->number,
      calldate    => $call->date,
      calltime    => $call->time,
      destination => $call->destination,
      duration    => $call->duration,
      type        => $call->type,
      cost        => $call->cost,
    });
  }

The create() call runs the SQL to INSERT the row for each call. As we're using Class::DBI, and have defined our primary key column to be AUTO_INCREMENT, we don't need to specify a value for that column. On databases that support sequences, we could also inform Class::DBI what sequence should be used to provide the primary key.

Now that we have a table populated with calls, we can begin to run queries against it. Let's write a simple script that reports on all the calls to a specified number:


  #!/usr/bin/perl
  
  use My::PhoneBill::Call;
  
  my $number = shift or die "Usage: $0 <number>";
  
  my @calls = My::PhoneBill::Call->search(number => $number);
  my $total_cost = 0;
  
  foreach my $call (@calls) {
    $total_cost += $call->cost;
    printf "%s %s - %d secs, %.1f pence\n",
      $call->calldate, $call->calltime, $call->duration, $call->cost;
  }
  printf "Total: %d calls, %d pence\n", scalar @calls, $total_cost;

Here we can see that Class::DBI provides a 'search' method for us to use. We supply a hash of column/value pairs, and we get back all the records that matched. Each result is an instance of the Call class, and each has an accessor method corresponding to each column. (It's also a mutator method, so we can update that record, but we're only reporting at this stage).

So, if we want to see how often we're calling the Speaking Clock, then we run


  > perl calls_to 123
  2002-09-17 11:06:00 - 5 secs, 8.5 pence
  2002-10-19 21:20:00 - 8 secs, 8.5 pence
  Total: 2 calls, 17 pence

Similarly, if we want to see all the calls on a given date, then we could have a 'calls_on' script:


  #!/usr/bin/perl
  
  use My::PhoneBill::Call;
  
  my $date = shift or die "Usage: $0 <date>";
  
  my @calls = My::PhoneBill::Call->search(calldate => $date);
  my $total_cost = 0;
  
  foreach my $call (@calls) {
    $total_cost += $call->cost;
    printf "%s) %s - %d secs, %.1f pence\n",
      $call->calltime, $call->number, $call->duration, $call->cost;
  }
  printf "Total: %d calls, %d pence\n", scalar @calls, $total_cost;

Running it gives:


  > perl calls_on 2002-10-19
  ...
  18:36:00) 028 9024 4222 - 41 secs, 4.2 pence
  21:20:00) 123 - 8 secs, 8.5 pence
  ...
  Total: 7 calls, 92 pence

As promised, we've written a database application without writing any SQL. OK, so we haven't really done anything very complicated yet, but even for this simplistic use Class::DBI makes our life much easier.

Building a Phone Book

I used to have a good memory for phone numbers. But Nokia, Ericsson, et al, have conspired against me. By giving my cell phone a built-in address book, they ensured that the part of my brain responsible for remembering 10 or 11 digit numbers would gradually atrophy. Now, when I look at the output of 'calls_on', I have no idea who "028 9024 4222" represents. So, let's build an address book that can store this information, and then change our reports to use it.

The first thing we should do is arrange our information a little better. We'll take the number and destination columns, and move them to a "recipient" table, to which we'll add a name column. "Destination" doesn't make as much sense when associated with the number, rather than the call, so we'll rename it to "location".


  CREATE TABLE recipient (
    recipid  MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
    number   VARCHAR(20) NOT NULL,
    location VARCHAR(255) NOT NULL,
    name     VARCHAR(255),
    KEY (number)
  );

And then we create the relevant class for this table:


  package My::PhoneBill::Recipient;
  
  use base 'My::PhoneBill::DBI';
  
  __PACKAGE__->table('recipient');
  __PACKAGE__->columns(All => qw/recipid number location name/);

  1;

We also need to modify the Call table:


  CREATE TABLE call (
    callid    MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
 *  recipient MEDIUMINT UNSIGNED NOT NULL,
    calldate  DATE NOT NULL,
    calltime  TIME NOT NULL,
    type      VARCHAR(50) NOT NULL,
    duration  SMALLINT UNSIGNED NOT NULL,
    cost      FLOAT(8,1),
 *  KEY (recipient)
  );

and its associated class:


  package My::PhoneBill::Call;
  
  use base 'My::PhoneBill::DBI';
  
  __PACKAGE__->table('call');
  __PACKAGE__->columns(All   =>
 *  qw/callid recipient calldate calltime type duration cost/);
  
  1;

Then we can modify our script that populates the database:


  #!/usr/bin/perl

  use Data::BT::PhoneBill;
  use My::PhoneBill::Call;
 *use My::PhoneBill::Recipient;

  my $file = shift or die "Need a phone bill file";
  my $bill = Data::BT::PhoneBill->new($file) or die "Can't parse bill";

 *while (my $call = $bill->next_call) {
 *  my $recipient = My::PhoneBill::Recipient->find_or_create({
 *    number      => $call->number,
 *    location    => $call->destination,
 *  });
 *  My::PhoneBill::Call->create({
 *    recipient   => $recipient->id,
      calldate    => $call->date,
      calltime    => $call->time,
      duration    => $call->duration,
      type        => $call->type,
      cost        => $call->cost,
    });
  }

This time we need to create the Recipient first, so we can link to it from the Call. But we don't want to create a new Recipient for each call - if we've ever rang this person before, there'll already be an entry in the recipient table: so we use find_or_create to give us back the existing entry if it's there, or else create a new one.

With the table repopulated we can return to our reporting scripts.

Our calls_on script now fails as we can can't ask a call for its 'number'. So, we change it to:


  #!/usr/bin/perl
  
  use My::PhoneBill::Call;
  
  my $date = shift or die "Usage: $0 <date>";
  
  my @calls = My::PhoneBill::Call->search(calldate => $date);
  my $total_cost = 0;
  
  foreach my $call (@calls) {
    $total_cost += $call->cost;
    printf "%s) %s - %d secs, %.1f pence\n",
 *    $call->calltime, $call->recipient, $call->duration, $call->cost;
  }
  printf "Total: %d calls, %d pence\n", scalar @calls, $total_cost;

However, running it doesn't really give us what we want:


  > perl calls_on 2002-10-19
  ...
  18:36:00) 67 - 41 secs, 4.2 pence
  21:20:00) 47 - 8 secs, 8.5 pence
  ...
  Total: 7 calls, 92 pence

Instead of getting the phone number, we now get the ID from the recipient table, which is just an auto-incrementing value.

To turn this into a sensible value, we add the following line to the Call class:


  __PACKAGE__->has_a(recipient => 'My::PhoneBill::Recipient');

This tells it that the recipient method doesn't just return a simple value, but that that value should be automatically turned into an instance of the Recipient class.

Of course, calls_on still won't be correct:


  > perl calls_on 2002-10-19
  ...
  18:36:00) My::PhoneBill::Recipient=HASH(0x835b6b8) - 41 secs, 4.2 pence
  21:20:00) My::PhoneBill::Recipient=HASH(0x835a210) - 8 secs, 8.5 pence
  ...
  Total: 7 calls, 92 pence

But now all it takes is a small tweak to the script:


    printf "%s) %s - %d secs, %.1f pence\n",
      $call->calltime, $call->recipient->number, $call->duration, $call->cost;

And now everything is working perfectly again:


  > perl calls_on 2002-10-19
  ...
  18:36:00) 028 9024 4222 - 41 secs, 4.2 pence
  21:20:00) 123 - 8 secs, 8.5 pence
  ...
  Total: 7 calls, 92 pence

The calls_to script is slightly trickier, as the initial search is now on the recipient rather than the call.

So, we change the initial search to:


  my ($recipient) = My::PhoneBill::Recipient->search(number => $number)
    or die "No calls to $number\n";

Then we need to get all the calls to that recipient. For this, we need to inform Recipient of the relationship with calls. Unlike the has_a we just set up in the Call class, the recipient table doesn't store any value concerned with the call table that could be inflated on demand. Instead we need to add a has_many declaration to Recipient:


  __PACKAGE__->has_many(calls => 'My::PhoneBill::Call');

This creates a new method calls for each Recipient object, returning a list of Call objects whose recipient method is our primary key.

So, having found our recipient in the calls_to script, we can simply ask:


  my @calls = $recipient->calls;

And now the script works just as before:


  #!/usr/bin/perl
  
  use My::PhoneBill::Recipient;
  
  my $number = shift or die "Usage: $0 <number>";
  
  my ($recipient) = My::PhoneBill::Recipient->search(number => $number)
    or die "No calls to $number\n";
  my @calls = $recipient->calls;
  
  my $total_cost = 0;
  
  foreach my $call (@calls) {
    $total_cost += $call->cost;
    printf "%s %s - %d secs, %.1f pence\n",
      $call->calldate, $call->calltime, $call->duration, $call->cost;
  }
  printf "Total: %d calls, %d pence\n", scalar @calls, $total_cost;

And now we can get the old results again:


  > perl calls_to 123
  2002-09-17 11:06:00 - 5 secs, 8.5 pence
  2002-10-19 21:20:00 - 8 secs, 8.5 pence
  Total: 2 calls, 17 pence

Next we need a script to give a name to a number in our address book:


  #!/usr/bin/perl
  
  use My::PhoneBill::Recipient;
  
  my($number, $name) = @ARGV;
  die "Usage $0 <number> <name>\n" unless $number and $name;
  
  my $recip = My::PhoneBill::Recipient->find_or_create({number => $number});
  my $old_name = $recip->name;
  $recip->name($name);
  $recip->commit;
  
  if ($old_name) {
    print "OK. $number changed from $old_name to $name\n";
  } else {
    print "OK. $number is $name\n";
  }

This lets us associate a number to a name:


  > perl add_phone_number 123 "Speaking Clock"
  OK. 123 is Speaking Clock

And now with a tiny change to our calls_on script we can output the name where known:


    printf "%s) %s - %d secs, %.1f pence\n",
      $call->calltime, $call->recipient->name || $call->recipient->number,
      $call->duration, $call->cost;

  > perl calls_on 2002-10-19
  ...
  18:36:00) 028 9024 4222 - 41 secs, 4.2 pence
  21:20:00) Speaking Clock - 8 secs, 8.5 pence
  ...
  Total: 7 calls, 92 pence

To allow the calls_to script to work if we give it either a name or a number, we can use:


  my $recipient = My::PhoneBill::Recipient->search(name => $number)
               || My::PhoneBill::Recipient->search(number => $number)
               || die "No calls to $number\n";

However, as we've called search in scalar context, rather than the normal list context, we get back an interator rather than an individual Recipient object. As one name may map to multiple numbers, we need to iterate over each of these in turn:


    my @calls;
    while (my $recip = $recipient->next) {
      push @calls, $recip->calls;
    }

(Printing individual totals for each number is left as an exercise for the reader.)


  > perl calls_to "Speaking Clock"
  2002-09-17 11:06:00 - 5 secs, 8.5 pence
  2002-10-19 21:20:00 - 8 secs, 8.5 pence
  Total: 2 calls, 17 pence

Working With Other Modules

Sometimes the information we store in the database can be used to work with non-Class::DBI modules. For example, if we wanted to format the dates of our calls differently, we might like to turn them into Date::Simple objects. Again, Class::DBI makes this easy.

In the Call class, we again use has_a to declare this relationship:


  __PACKAGE__->has_a(recipient => 'My::PhoneBill::Recipient');
 *__PACKAGE__->has_a(calldate  => 'Date::Simple');

Now, when we fetch the calldate it is automatically inflated to a Date::Simple object. So, we can change the output of calls_to to print the date in a nicer format:


  printf "%s %s - %d secs, %.1f pence\n",
    $call->calldate->format("%d %b"), $call->calltime,
    $call->duration, $call->cost;
 
  > perl calls_to "Speaking Clock"
  17 Sep 11:06:00 - 5 secs, 8.5 pence
  19 Oct 21:20:00 - 8 secs, 8.5 pence
  Total: 2 calls, 17 pence

Class::DBI assumes that any non-Class::DBI class is inflated through a new method, and can be deflated through stringification. As both of these are true for Date::Simple, we didn't need to do anything more. If this is not the case - for example, if you wanted to use Time::Piece instead of Date::Simple - you need to tell Class::DBI how to do the inflating and deflating as the value goes in and comes out of the database.


  __PACKAGE__->has_a(calldate => 'Time::Piece',
    inflate => sub { Time::Piece->strptime(shift, "%Y-%m-%d") },
    deflate => 'ymd'
  );

Deflating a Time::Piece object back to an ISO date string suitable for MySQL is quite simple: you can just call its ymd() method. Thus we can specify this as a string. Inflating is more difficult, as it requires a two argument call to strptime(). Thus we need to specify this as a subroutine reference. When inflating, this is called with the value from the database as its one and only argument. Thus, we can pass that to Time::Piece's strptime method, specifying the format to instantiate from.

Using Time::Piece instead of Date::Time requires one further change to to our output script:


  printf "%s %s - %d secs, %.1f pence\n",
 *  $call->calldate->strftime("%d %b"), $call->calltime,
    $call->duration, $call->cost;

MOST CALLED NUMBERS

BT provide a service that allows you to save money on 10 numbers of your choice. So it would be useful if we were able to find out which numbers we spend the most money calling. We'll assume that any number we've only ever called once isn't worth adding to our list, as it was probably a one-off call. Thus we want the 10 numbers with the highest spend that have had more than one call.

As we said earlier, Class::DBI doesn't attempt to provide a syntax to express any arbitrary SQL, so there's no way of asking directly for this information. Instead, we'll try a simple approach.

Firstly we'll add a method to the Recipient class to tell us the total we've spent on calls to that number:


  use List::Util 'sum';

  sub total_spend {
    my $self = shift;
    return sum map $_->cost, $self->calls;
  }

Then we can create a top_ten script:


  #!/usr/bin/perl
  
  use My::PhoneBill::Recipient;
  
  my @recipients = My::PhoneBill::Recipient->retrieve_all;
  my @regulars = grep $_->calls > 1, @recipients;
  my @sorted = sort { $b->total_spend <=> $a->total_spend } @regulars;
  
  foreach my $recip (@sorted[0 .. 9]) {
    printf "%s - %d calls = %d pence\n",
      $recip->name || $recip->number,
      scalar $recip->calls,
      $recip->total_spend;
  }

This is very slow, however, once you have more than a few hundred calls stored in your database. This is mainly because we're sorting based on a method call. Replacing the sort above with a Schwartzian Transform speeds everything up significantly:


  my @sorted = map $_->[0],
    sort { $b->[1] <=> $a->[1] }
    map [ $_, $_->total_spend ], @regulars;

Now, until the database gets significantly bigger, this is probably fast enough - especially as you probably won't be running the script very often.

However, if this isn't enough, then we can always drop back to SQL. Of course, when we need to optimize for speed, we usually lose something else - in this case, portability. In this example, we're using MySQL, so I would add the relevant MySQL-specific query to Recipient.pm:


  __PACKAGE__->set_sql(top_ten => qq{
    SELECT recipient.recipid,
           SUM(call.cost) AS spend,
           COUNT(call.callid) AS calls
      FROM recipient, call
     WHERE recipient.recipid = call.recipient
     GROUP BY recipient.recipid
    HAVING calls > 1
     ORDER BY spend DESC
     LIMIT 10
  });

Then we can set up a method that returns the relevant objects for these:


  sub top_ten {
    my $class = shift;
    my $sth = $class->sql_top_ten;
       $sth->execute;
    return $class->sth_to_objects($sth);
  }

Any SQL set up using set_sql can be retrieved as a readily prepared DBI statement handle by prepending its name with sql_ - thus we fetch back this top_ten using my $sth = $class->sql_top_ten;

Although we could happily execute this and then call any of the traditional DBI commands (fetchrow_array etc.), we can also take a shortcut. As one of the columns being returned from our query is the primary key of the Recipient, we can simply feed the results into the underlying method in Class::DBI that allows searches to return a list of objects, sth_to_objects.

So, our script becomes simply:


  foreach my $recip (My::PhoneBill::Recipient->top_ten) {
    printf "%s - %d calls = %d pence\n",
      $recip->name || $recip->number,
      scalar $recip->calls,
      $recip->total_spend;
  }

As we have seen, Class::DBI makes it possible to perform many of the common database tasks completely trivially - without writing a single line of SQL. But, when you really need it, it's fairly easy to write the SQL that you need and execute it.

This week on Perl 6 (11/10-11/17, 2002)

"Oh! my ears and whiskers, I'm late!"

It's 0650, it's 20021120 and I've only just started writing the summary. Call me lazy, call me a shirker, call me anything you damn well please, just don't interrupt me while I'm writing this.

Yup, it's past time for another peek into the lives of those strange beings we call the Perl 6 development community, starting off, as usual, with the perl6-internals crew.

Quick Roadmap

Dan returned unscathed from this year's Lightweight Languages workshop and presented a short roadmap for the next few miles. Dan reckons that if we hit all those milestones, then we'll have a complete imperative core -- which will be nice.

http://groups.google.com/groups

Branch Dump

Michael Collins stuck his head above the parapet to report that using branch provoked a core dump on his Linux setup. It turned out to be a problem with his code. Dan debugged his code and offered a reasonably full explanation of how parrot's branch actually works (and why you should really use labels in hand written assembler.) Gopal V worried that allowing branches to non-instructions was unsafe and wondered whether, at least, a parrot -fverify switch might be in order. Dan agreed, but his reasoning was somewhat different.

Elsewhere in the thread, Dan tells us that he wants safe interpreters to be as safe as a locked down VMS system, but he's unsure as to whether we'll reach that gaol. (Mmm ... nice typo there Piers, leave it)

http://groups.google.com/groups

http://groups.google.com/groups

Parrot BASIC 2

Clinton A. Pierce announced his complete rewrite of BASIC for Parrot, this time modeling his implementation on QuickBASIC. Here's a list of the new features, lifted from Clint's announcement:

  • Compiled directly to Parrot Assembly
  • Interpreted
  • Richer syntax than Parrot BASIC 1.0, which was based on GW-BASIC
  • Much, much faster than Parrot BASIC 1.0
  • Support for user-defined types
  • Support for variable scopes (but apparently, QuickBASIC scoping is 'bizarre')

Nobody said anything -- I think they were rendered speechless. However, I'd like to take the opportunity to use this platform to say "Yay Clint!". This is superb news. OK, so supporting BASIC wasn't exactly Parrot's initial goal, but it's great to see that a single hacker can implement such a complete language using Parrot.

http://groups.google.com/groups

scope and functions in languages/scheme

Not to be outdone by Clint's BASIC implementation, Jürgen Bömmels has taken advantage of Jon Sillito's lexical scopes patch to add functions to scheme (before it was just scheme syntax, now it has some claim to being really scheme like). Bravo Jürgen!

http://groups.google.com/groups

Leo Tötsch is the Patch Monster

This week, Leo has been mostly:

  • Fixing JIT to make it restartable
  • Fixing JIT to make it play well with Perl 6
  • Fixing JIT so you can see what's going on when you use gdb.

And generally seeming to pop up with useful contributions in almost every thread. Where does he find the time?

Bootstrapping Perl 6

Marius Nita asked about the Perl 6 compiler, wondering what language it'd be written in, Perl or C? Markus Laire thought it'd eventually get written in Perl 6 or Parrot 'or something else which runs on parrot.' Gopal V worried about the bootstrapping problem and asked that the Perl 6 compiler be written in something other than Perl 6 in an attempt to avoid a 'dependency hellhole'. Brent Dax pointed out that we're pretty much obliged to write Perl 6 in Perl in order to get the self modifying parser behaviour and noted that we'd ship it as bytecode. Nicholas Clark pointed out that, strictly, you can't build perl5 from scratch without an installation of perl5, but the p5porters get 'round the problem by shipping the generated headers as part of the perl5 tarball.

Dan points out that the goal is for Parrot to require a C compiler and a platform shell or Make tool (either should do). Nicholas Clark attempted to kick off a variant of Monty Python's 'Yorkshiremen' skit ("Make tool? Luxury! We 'ad to make do wi' a console and switches!" "You were lucky! We used to 'ave to mek waves in' t'mercury delay line wi' us tongues!"), reckoning that it should be possible to get by with just a C compiler and asked that we 'archive this message and hold it against me when the time comes, and you're looking for someone to prove it by making it work'.

http://groups.google.com/groups

http://groups.google.com/groups -- Archive this message

Quick note on JIT bits

Dan announced that he was about to 'do exceptions' and wanted to give a heads up to everyone who does Odd Things (principally the JITterbugs). The rule appears to be 'Don't monkey with the system stack'. Leopold Tötsch wondered if that was actually the issue Dan thought it was, but came up with a bunch of other issues to do with register allocation, both at the parrot level and the processor level. And then it all got too much for my brain to cope with.

http://groups.google.com/groups

Perl 6 test organization

Over in perl6-documentation, they're about to start producing Perl 6 language tests, so chromatic posted Brent Dax's suggestion about how tests should be organized into sub directories. General response was favourable (the current languages/perl6 tests are somewhat disorganized.)

http://groups.google.com/groups

Meanwhile, in perl6-language

The language list was relatively quiet this week. The Operator thread seems to have reached a cæsura, but most of the current threads seem to have spun off from issues raised in that monster.

Unifying invocant and topic naming syntax

Discussion of ralph's proposals for changing the function declaration syntax continued. Damian doesn't like the proposed changes, and has been explaining to ralph why not. Nicholas Clark worries that a function being able to access its caller's topic is 'an unrestricted licence to commit action at a distance' (he says that like it's a bad thing). Andrew Wilson pointed out that, unless you could access the caller's topic you wouldn't be able to prototype things like print (and if you can't get a prototype for something then you can't fully override it). Damian added that it's also what Perl 5 does (except Perl 5 does it without having the decency to declare anything)

http://groups.google.com/groups

Superpositions and Laziness

I'm not entirely sure why a thread titled 'Superpositions and Laziness' should contain discussion of whether one should have a 'pure' property or a 'cached' one. Or both.

Meanwhile, in the 'laziness' side of the thread, Piers Cawley saw fit to post a huge chunk of uncommented code which was described by Larry as 'opaque, and not in a good way'. On rereading, I didn't think it was that bad.

Larry also introduced the possibility of breaking the operator: method of declaring operators up into prefix:, infix:, postfix: and circumfix:.

http://groups.google.com/groups

http://groups.google.com/groups

http://groups.google.com/groups

FMTWYENTK about :=

Last week, arcadi declined to expand 'FMTWYENTK about :='. This week we discovered that it stands for 'Far More Than What You Ever Needed To Know' (It was the 'what' that foxed me).

This week Damian supplied answers/clarifications. Next week, I'm hoping for a lovely, consolidated document.

http://groups.google.com/groups

http://homepages.tcp.co.uk/~nicholson/alice.html -- Always worth a read

Continuations

Given the subject of the last link, I find it entirely appropriate that the thread about coroutines and yield should be called 'Continuations', but I freely admit to an odd sense of humour.

It turns out that there are several different views as to what coroutines should do, a few of the alternatives were discussed. Damian thinks that the actual semantics chosen will probably have a good deal to do with how Perl 6 iterators work. Luke Palmer, whose name should live in infamy for this, declared that he was starting to like coroutines because 'the elegantify stuff.'

http://groups.google.com/groups

http://groups.google.com/groups -- Dan's expectations

http://groups.google.com/groups -- Damian's initially preferred coroutines

http://groups.google.com/groups -- 'Pythonic' coroutines

More Junctions (or, When junctions collapse)

Luke Palmer wondered about collapsing junctions. When a function collapses a junction, does the junction collapse everywhere, or would one have to make an explicit 'observation' to precipitate collapse? Damian offered a reasonably complete discussion of the various possibilities.

I offer the following without comment:

 When a junction hits a function and collapses down to one
 will it propagate the changes through the runtime? Oh, what fun!

http://groups.google.com/groups

http://groups.google.com/groups

Control Structures I, II and III

Timothy S. Nelson's suggested new control structures got discussed this week. The general feeling seemed to be that what was proposed didn't really offer much that was desperately useful over and above the current control structures.

http://groups.google.com/groups

http://groups.google.com/groups

http://groups.google.com/groups

String concatenation operator

Andy Wardley wondered whether we couldn't overload + to work as both numeric addition and string concatenation. Answer: No.

Richard Proctor wondered if we couldn't get away with doing string concatenation by juxtaposition ( "string " "foo" evaluates to "string foo".) Answer: No.

Larry had wise words the on subject of juxtapositional operators.

http://groups.google.com/groups

http://groups.google.com/groups

Meanwhile, Over in perl6-documentation

I'm still at something of a loss as to how to summarize this group effectively. Essentially the goal of the perl6-documentation list is to thrash out, in detail, the complete behaviour of Perl 6 and to produce tests and documentation which amount to a detailed spec. Their current project is 'literal values', and the work is ongoing.

There's been some debate as to documentation format of choice (current thinking is 'POD with knobs'). Michael Lazzaro who, if he hasn't officially been named documentation pumpking is doing a damn good job as de facto 'Bey of the docs' has posted a working outline for Section 1 of the docs. Garrett Goebel appealed for some docs on writing good tests for languages, which kicked off some debate about how tests should communicate with the test harness. Angel Faus put up a first cut at the 'literal values' subsection, and got a good amount of feedback. Dave Storrs took on the 'glossary chap' role, and posted a taster.

Dave is also the coordinator for 'Contributor License Forms', which are rather important. Before you donate any docs to the Perl 6 Documentation project you must fill in the form assigning the license to the Perl 6 project. Dave's post has the details.

Can you tell it was getting late when I wrote this section?

http://groups.google.com/groups -- Section 1 outline

http://groups.google.com/groups

http://groups.google.com/groups -- Literals, take 1

http://groups.google.com/groups -- Literals, take 2

http://groups.google.com/groups -- Numeric literals, take 1

http://groups.google.com/groups -- Glossary

http://groups.google.com/groups -- Contributor license forms

In Brief

Clinton A Pierce had problems building under Win32 -- I'm not entirely sure the issue was resolved.

Jerome Quelin, backed up by Leon Brocard (Yay! I was wondering how I was going to mention him this week) used his Befunge interpreter to find bugs in PerlArray and string_append.

Daniel Grunblatt (or a better than reasonable facsimile) is back. This made Leopold Tötsch and Steve Fink happy. And we like it when they're happy. Welcome back Daniel.

The 'very complete lexical scopes' patch finally got applied this week.

Tim Bunce pointed us at CCured, which looks interesting: http://manju.cs.berkeley.edu/ccured/index.html

Jonathan Sillito offered a patch to turn Parrot subs into closures.

Arcadi wondered whether sigils were user extensible. Answer: Yes, but not necessarily easily.

Who's Who in Perl 6?

Who are you?
Leopold Tötsch. I'm an independent software developer, living in Austria (this is the country near Liechtenstein w/o kangaroos).
What do you do for/with Perl 6?
I'm digging around in Parrot's core, closing holes and pushing new ideas (or old ideas, which were already discussed before my time ;-).
Where are you coming from?
I started working with computers in the late '70s (e.g. a hard disc driver for a 10 Meg disc under CP/M 3). Via 8080/Z80 assembler, Pascal, C, Perl 5 I finally arrived at Perl 6 development, where I made this run under 5.005.03. While submitting patches toward Perl 6, I realized that IMCC caused a lot of test failures, so I rewrote IMCC substantially and added the Parrot engine. Running PBC inside IMCC demanded a bunch of patches to the Parrot core, so here I am.
When do you think Perl 6 will be released?
Sept. 16, 2004.
Why are you doing this?
For fun, really a lot of.
You have five words. Describe yourself.
Parrot for a faster live.
Do you have anything to declare?
No customs here.

Acknowledgements, requests and the usual muttering

This summary was brought to you, late from the comforts of GNER's First Class carriages, and from Mary Branscombe and Simon Bisson's most excellent (if somewhat hard to stand up from) sofa. Distractions were provided by the Kiseido Go Server, XMAME, Mary & Simon's DVD collection and a visit from Black Dog. Normal service will hopefully be resumed next week.

Proofreading was once again down to Aspell and myself. We make a much better team than we did.

A couple of months ago, I said of Leo Tötsch that 'he turned 44 on the 16th of September 2002, so not only does he contribute really useful code, he makes Dan and I feel younger. Can this man do no wrong?' I seems he can't, he's even found time to contribute his answers for the summary questionnaire. Thanks, Leo. Once more, if you participate in the lists and you've not sent me a set of answers, then I'd be really grateful if you'd send your answers to: mailto:5Ws@bofh.org.uk, current names I'm targeting include Larry, chromatic, Steve Fink, Clint Pierce, Daves Whipp & Storrs (Hmm... Now there's a name for a legal practice, 'Pierce, Whipp & Fink') and anyone else named in a summary who hasn't sent me answers. As I used to say in my USENET days aTdHvAaNnKcSe.

Now, I hope you're in good voice as we all join in the chorus:

If you didn't like this summary, then what are you doing still reading it? If you did like it, please consider one or both of the following options:

The fee paid for publication of these summaries on perl.com is paid directly to the Perl Foundation.

Managing Bulk DNS Zones with Perl

A History of Forward and Reverse DNS

When an Internet server receives an incoming connection from a client, it may take a precaution of verifying the identity of the client. Some protocols simply trust the client to provide proper credentials to their identification (like SMTP). More complex protocols use a key exchange or a shared secret to communicate. Other protocols rely on the process of verifying the hostname of the client.

To do this, a server would take the IP address of the client, and perform a reverse DNS lookup to get the PTR records. Then, it would request the A record of the hostname returned from the PTR query. If the hostname matched the IP address in both queries, then the host was considered to be trusted.

As a means of host authentication, it was a half-hearted process at best. It relied heavily on external DNS servers, and it could easily be circumvented if false records were returned to the DNS resolvers that sent the queries. As such, it was only suitable for public Internet services like anonymous FTP or Web servers.

Another problem with this process was that it meant you would need to have matching forward and reverse DNS entries for all of your client hosts. Without the records, your logon could be delayed, or it could be refused altogether.

This became a burdeon for ISPs with large dial-up pools, or organizations with large LANs. Dozens, if not hundreds of IP addresses suddenly needed to have two DNS entries. DNS zones that originally contained 20 host records grew to hundreds of host records.

For example, let's say we work in a large university environment. We have been given the 192.168.76.0/22 and 10.10.0.0/16 network blocks. Before any of these IP addresses are useful, we need to create forward and reverse DNS entries for them.

The network engineer writes a simple Perl script that will populate the zonefile with entries. The output from the script is then put in the domain "ips.university.edu".


$fmt="%s\tIN\tA%s\n";
foreach $block ("192.168.76.","192.168.77.","192.168.78.","192.168.79.")
{
	$host=$block;
	$host=~s/\./-/g;
	for ($n=0;$n<=255;$n++)
	{
		printf($fmt,$host.$n,$block.$n);
	}
}

As a result of a script such as this, you'd find out that you have a host record for your IP that looks like this.


192-168-76-93.ips.university.edu

It sure isn't pretty, but it gets the job done.

As far as the DNS server is concerned, there is nothing wrong with this record. Some experienced network engineers will probably point out a couple of causes for concern.

1. The record size is big. For each A record, we're using anywhere from eight to 15 characters to represent a 32-bit integer.

2. The repeated "192-168-" pattern is wasteful. We could remove it from the entry, so 76-54.ips.university.edu points to 192.168.76.54, but that leads to a conflict when we create a DNS entry for 10.10.76.54?

We can correct that by creating seperate subdomains for both networks.


76-54.n1.ips.university.edu.	IN	A	192.168.76.54
76-54.n2.ips.university.edu.	IN	A	10.10.76.54

Using separate subdomains, we've reduced the size of the record. The XXX-XXX.nX portion can be anywhere from six to 10 characters. But we can still do a little more work to make it smaller.

The solution is to create a script that more accurately looks at the network block, and creates DNS entries based only on the host portion of the IP address in a block.

IP addresses and Net::Netmask

IPv4 addresses are 32-bit integers. The IP address 192.168.76.55 can be represented in several ways:

Dottted Quad Notation 192.168.76.55
Base 10 integer 3232255031
Hexadecimal c0a84c37
Binary 11000000101010000100110000110111

For future mathematicians out there, dotted quad notation is really base-256 notation.

Network masks are also 32-bit integers. The 192.168.76.0/22 network number represents the following netmask:


11111111111111111111110000000000

For any IP address within this block, the first 22 bits represent the network, the remaining 10 bits represent the host within the network. If we were to split the network and host values of the IP address 192.168.76.55, then we find:


Network Host
Host IP 1100000010101000010011 0000110111
Netmask 1111111111111111111111 0000000000
Base 10 3156499 55
Base 16 302a13 37

For the IP address 192.168.76.5, the host portion of the IP address is five.


Network Host
Host IP 1100000010101000010011 1100000010101000010011
Netmask 1111111111111111111111 0000000000
Base 10 3156499 5
Base 16 c0a84c37 5

For the IP address 192.168.77.87, the host portion of the IP address is 343.


Network Host
Host IP 1100000010101000010011 0101010111
Netmask 1111111111111111111111 0000000000
Base 10 3156499 343
Base 16 c0a84c37 157

In order to get the host information about our address block, we will be using the Net::Netmask Perl module.

The Net::Netmask module was written to disseminate information about network blocks. By giving it an IP address and a netmask, it can tell you the network address, the broadcast address, of a given network. It can also tell us which IP address corresponds to which host number.


use Net::Netmask;

$block=Net::Netmask->new("192.168.76.0/22");

print("Network can hold ",$block->size()," IP addresses\n");
print("Host 5   is IP ",$block->nth(5),"\n");
print("Host 343 is IP ",$block->nth(343),"\n");

The output of the program is:


Network can hold 1024 IP addresses
Host 5   is IP 192.168.76.5
Host 343 is IP 192.168.77.87

The nth() method returns the IP address corresponding to the host number.

The Updated Script

This new script accomplishes the same thing as the old script, but this time we use Net::Netmask to keep track of IPs in the block.


use Net::Netmask;

$network="192.168.76.0/22";
$fmt="%s\tIN\tA\t%s\n";

$block=Net::Netmask->new($network);
$size=$block->size()-2;
$index=1;
while ($index <= $size)
{
	$host=sprintf("h%x",$index);
	printf($fmt,$host,$block->nth($index));
}

Which produces the following zonefile.


h1      IN      A       192.168.76.1
h2      IN      A       192.168.76.2
h3      IN      A       192.168.76.3
h4      IN      A       192.168.76.4
....
h35     IN      A       192.168.76.53
h36     IN      A       192.168.76.54
h37     IN      A       192.168.76.55
h38     IN      A       192.168.76.56
h39     IN      A       192.168.76.57
h3a     IN      A       192.168.76.58
....
h3fb    IN      A       192.168.79.251
h3fc    IN      A       192.168.79.252
h3fd    IN      A       192.168.79.253
h3fe    IN      A       192.168.79.254

A couple of points to make.

1. In the host record itself, we choose to represent $index in hexadecimal. This gives us a little more use out of the ASCII character set. We save one character on integers between 99 and 255.

2. A prefix of "h" (for host) is used on every record, so we don't have records that are just an integer. For example, a record like "1.n1.ips.university.edu" can be a problem depending on your resolver search settings. If you try to run "ping 1" from a command prompt, then it's unclear whether you meant the host record "1," or the actual IP address "0.0.0.1".

3. The above script doesn't produce records for the network address or the broadcast address. It is left for the DNS administrator to create them or just ignore them.

Using the example 192.168.76.0/22 network, the zonefile created by the second script is roughly 70 percent of the size of the zonefile created by the first script.

Creating the Reverse DNS

We can use Net::Netmask to create the reverse DNS as well, but the process is a little tricker.

Reverse DNS zones are delegated on the octet boundaries of the IP address, so it usually means that a zonefile will cover a full /24 network. If your network is larger than a /24, then you'll need to create multiple zonefiles. If your network is smaller, then your data will probably be inserted to a zonefile that already exists for the other hosts in the network.

Note: While it is possible for DNS reverse zones to be delegated for networks smaller than a /24, the discussion of setting up the CNAME or NS records for those situations is outside the scope of this article.

This makes the creation of reverse DNS a little tricky. When you created the forward DNS, all of your data ended up in one zonefile. For the reverse DNS, the data could be in one or more zonefiles depending on the size of the network.

The Net::Netmask module has a feature that makes it a little easier to work this out. The inaddr() function returns data on the reverse DNS zones that the current netblock would occupy. For each /24 block your network covers, it returns the reverse DNS zone name, the starting IP address, and the ending IP address of the block.

So if we were looking at the 192.178.76.0/22 network, the inaddr() function would return:


76.168.192.in-addr.arpa
0
255
77.168.192.in-addr.arpa.
0
255
78.178.192.in-addr.arpa
0
255
79.178.192.in-addr.arpa
0
255

However, if we were looking at the 192.168.76.0/26 network, the inaddr() function would return:


76.178.192.in-addr.arpa
0
63

Using this function, we can create a baseline program that at least tells us which zones we would need to create reverse DNS for.


$block=Net::Netmask->new("192.168.76.0/22");

(@data)=$block->inaddr();
while (($zone,$start,$end)=splice(@data,0,3))
{
	print("; Reverse zone: $zone\n");
	for ($loop=$start;$loop<=$end;$loop++)
	{
		# Create the individual entries
	}
}

The outside loop runs once for every possible /24 network we will be filling with PTR records. The inner loop begins an iteration from the starting IP address and the ending IP address.

If you remember, the nth() method of Net::Netmask returns an IP address based on a host number. The match() method is the exact opposite; it returns a host number based on an IP address.


use Net::Netmask;

$block=Net::Netmask->new("192.168.76.0/22");

print("IP 192.168.76.5  is Host ",$block->match("192.168.76.5"),"\n");
print("IP 192.168.77.87 is Host ",$block->match("192.168.77.87"),"\n");

IP 192.168.76.5  is Host 5
IP 192.168.77.87 is Host 343

In order to get the host number, we would need to provide the match() function with a full IP address. This is the part where we have to do a little string cheating.


$block=Net::Netmask->new("192.168.76.0/22");

sub flip
{
my ($zone)=shift;
my ($network,@rz,@ipc);
(@rz)=split(/\./,$zone);
(@ipc)=reverse(splice(@rz,0,3));
$network=join(".",@ipc);
return $network;
}

$domain=".n1.ips.university.edu.";
$fmt="%s\tIN\tPTR\t%s\n";
(@data)=$block->inaddr();

while (($zone,$start,$end)=splice(@data,0,3))
{
        print("; Reverse zone: $zone\n");
	$network=flip($zone);
        for ($loop=$start;$loop<=$end;$loop++)
        {
		# Create the invidivual entries
		$ip="$network.$loop";
		$order=$block->match($ip);
		$host=sprintf("h%x%s",$order,$domain);
		printf($fmt,$loop,$host);
        }
}

The confusing part is probably the flip() subroutine. All that does is take a reverse DNS zone name (like 76.168.192.in-addr.arpa), and returns the quads in forward form (192.168.76). We use this string as a prefix to combine with $loop so we have a valid IP address for the match() method.

The program run gives us:


;Reverse Zone: 76.168.192.in-addr.arpa

1       IN      PTR     h1.n1.ips.university.edu.
2       IN      PTR     h2.n1.ips.university.edu.
3       IN      PTR     h3.n1.ips.university.edu.
4       IN      PTR     h4.n1.ips.university.edu.
5       IN      PTR     h5.n1.ips.university.edu.
6       IN      PTR     h6.n1.ips.university.edu
....
53      IN      PTR     h35.n1.ips.university.edu.
54      IN      PTR     h36.n1.ips.university.edu.
55      IN      PTR     h37.n1.ips.university.edu.
56      IN      PTR     h38.n1.ips.university.edu.
57      IN      PTR     h39.n1.ips.university.edu.
58      IN      PTR     h3a.n1.ips.university.edu.
;Reverse Zone: 79.168.192.in-addr.arpa

0       IN      PTR     h300.n1.ips.university.edu.
1       IN      PTR     h301.n1.ips.university.edu.
2       IN      PTR     h302.n1.ips.university.edu.
3       IN      PTR     h303.n1.ips.university.edu.
4       IN      PTR     h304.n1.ips.university.edu.

Other Tricks

We used hexadecimal numbers in the host records to save space in the zonefile, and to make the record a little more obscure to the casual observer. To make it a even more obscure, try using a subroutine that will create base32 numbers (0-9,a-v), or base36 (0-9,a-z) numbers.

To make it easier to identify the size of the network, create two A records for the zone itself, and populate it with the starting IP address, and the ending IP address.


;
; Forward DNS for 192.168.96.0/21 network
$ORIGIN n3.ips.university.edu.

	IN	NS	ns1.university.edu.
	IN	NS	ns2.university.edu.

	IN	A	192.168.96.0
	IN	A	192.168.103.255

h1	IN	A	192.168.96.1
h2	IN	A	192.168.96.2

Net::Netmask has two functions, base() and broadcast(), which can be used to obtain these values.

Conclusion

Your DNS records need to match in order to satisfy forward/reverse host authentication. It doesn't matter what the values are, just as long as they agree. It seems like a large hassel, especially when you consider that the practice of forward/reverse host authentication is considered highly untrustworthy by security administrators. Some hostmasters would say that the process is a waste of time. Keep in mind that there will always be one or two users that will demand that their desktop system be given forward and reverse DNS entries.

It's easy to automate the process of creating the zonefiles. Once the data is put in place, it almost never needs to be updated. I've seen a lot of DNS entries out there that simply replicate the IP address. Check the logs of a popular Web server and see for yourself.

Unfortunately, it's unlikely that these records will change in the future, unless the network allocation actually changes to another entity. In the meantime, the code examples above can be used to easily create new zones for future network allocations.

This week on Perl 6 (11/03-11/10, 2002)

Far off in distant Newark, a figure muttering something about 'Leon Brocard' shambles across a railway bridge and makes its way into a waiting room. Time passes. After a while, a train arrives and the figure shambles on board, takes its seat, pulls a laptop from its bag and starts to type. This is what it types: '=head1 The Perl 6 Summary for the week ending 20021110'.

Yes, it's time for another update on the japes and tomfoolery from the world of Perl 6. We start, as usual, with perl6-internals.

The Myth of Fingerprints

At the end of the previous week, Gregor posted an outline of his proposal for fixing the fingerprinting issue with dynamic loading. (The fingerprinting issue is that 'old' .pbc files may break big time when run on newer Parrots. Ideally, we'd like Parrot to refuse to run such files before bad things happen. It's proposed that this be done by adding 'fingerprints' to .pbc to allow for identification by Parrot.) Leopold Tötsch wasn't at all sure about Gregor's approach, pointing out that it would have massive speed implications, and lo, the thread got dragged off in the direction of a discussion of optimizing Parrot for speed. How did that happen then?

http://groups.google.com/groups

on_exit not portable

Andy Dougherty pointed out that Solaris doesn't have on_exit, which is used by Parrot to clean up after itself, and suggested that interpreter.c be reworked to use atexit. However, SunOS has on_exit but doesn't have atexit. It's a quandary. Josh Wilmes suggested implementing Parrot_on_exit() and Parrot_exit() in platform.c and half promised a patch (unless somebody beat him to it.) Leo Tötsch and Nicholas Clark both said, essentially "Nice idea, go do it."

Dan chimed in, pointing out that the current on_exit behavior seemed to be there as a workaround for bugs in exceptions, and that fixing those was probably the better idea. Leo turned off the 'on_exit' stuff, just as Josh was sending a patch implementing the Parrot_* functions. I think that, as we now stand, we're back to doing exit cleanup, but using the portable Parrot_* functions.

http://groups.google.com/groups

http://groups.google.com/groups

Should Memory be Washed?

Peter Gibbs was unsure of the guarantees given by Parrot_allocate and friends regarding the contents of the memory supplied. Apparently, some code appears to assume that it will get pre-washed memory, while other code does its own cleaning. Which is right? Leo Tötsch reckons that the current behavior (memory is zeroed at allocation time) should be guaranteed. Dan wasn't so sure that this was a good idea if we go for a 'malloc like' scheme and thought that it could be argued that it was a bug for any code to assume that the memory it got was zeroed.

The eventual consensus was that the basic allocator should not guarantee zeroed memory, but that there should be a set of allocator functions that do return zeroed memory. Leo checked in a patch to that effect.

Then they started talking about performance.

http://groups.google.com/groups

string_set Is Back

Leopold Tötsch has added a 'string_set' function that allows strings to be recycled instead of having to create new strings every time. This can lead to substantial speed gains when used appropriately. This led to a discussion on when it was appropriate to use non destructive assignment and when to use a destructive set. Somewhat to my surprise, nobody has yet suggested the lispish set is nondestructive, set! is destructive split, allowing the Parrot coder to choose. Looks like I just suggested it here.

http://groups.google.com/groups

Meanwhile, Over in perl6-language

Amazingly, the main topic of conversation this week wasn't the dreaded operator thread ...

Unifying Invocant and Topic-Naming Syntax

Allison Randal has written an article about Perl 6 topics for perl.com. 'Ralph' read this and didn't appear to like it very much, particularly the sub foo ($bar) is given($baz) { ... } syntax that sets $baz to the value of the caller's topic. (If you're not sure what I'm talking about, then now would be a good time to read Allison's article. Topics are great, you'll like them.) Ralph wanted to do sub foo ($baz : $bar is topic) { ... }, and supplied several further, terser and terser declaration forms, method f ($self : $c : $a*, $b) {...} anyone?

Allison thought Ralph was barking up the wrong tree, and explained the thinking behind the topic related syntax and pointed out that Ralph appeared to be conflating two 'independent but interacting features' with his proposal, but Ralph didn't give up that easily. Eventually, after comments from Damian and Allison he let the subject lie.

http://www.perl.com/pub/a/2002/10/30/topic.html

http://groups.google.com/groups

UTF-8 and Unicode FAQ

Actually, I lied about the operator thread subsiding. It fragmented. But at least now the various fragments got their own subjects. In this particular subthread, the whole 'Unicode operators in core' thing got discussed. There appears to be two camps. The first camp maintains that Unicode operators in the core means Perl will start looking dangerously like APL and will need a space cadet keyboard to use. The second camp's argument for Unicode operators appears to be 'Yeah, and your point was? We only want to use « and », and isn't it about time the world got with the Unicode program?'

Me? I'm on the fence. I can see the reasoning behind wanting Unicode operators, but I'm not entirely sure I like them (the 'email encoding' problem is my major bugbear...)

http://groups.google.com/groups

http://groups.google.com/groups -- A decent summation from Michael Lazzaro

Supercomma!

At one point in the UTF-8 and Unicode thread, Larry wondered whether he could raid Unicode for a better character than ; for separating parallel for loop streams. Michael Lazzaro responded with a couple of suggestions for different supercommas which would have different meanings. I couldn't tell you what the symbols are, my mailer rendered 'em as Latin-1 digraphs, neither of which looked much like a comma.

Larry then confessed that he was thinking of changing the declaration of parallel for loops from:


  for @a ; @b ; @c -> $a ; $b ; $c {...}

to something like:


  for parallel(@a, @b, @c) -> $a, $b, $c {...}

Which has the advantage of not messing with the block signature at all, which Larry reckons should make Simon Cozens happier. Damian pointed out that doing things this way would probably mean we'd get a bunch of useful functions for iterating over arrays (and then implemented one such function). Others followed, implementing various other useful functions before Damian capped them all with a nicely generalized zip implementation.

Buddha Buck endeared himself to the summarizer with his summary of for loop possibilities. Buddha also included a rather pretty implementation of for as a recursive function, though Damian reckoned he'd not quite got the signature right.

http://groups.google.com/groups

http://groups.google.com/groups

http://groups.google.com/groups

http://groups.google.com/groups

The Interminable Operator Thread

'Smylers' is my hero of the week for a message he posted summarizing the various (12) options for changing the look of operators, with particular reference to vectorization. Options range from 'as we were' to the 'guillemot' option, which involves seabirds and a pathological inability to spell 'guillemet.'

http://groups.google.com/groups

FMTWYENTK about :=

Bravely declining to expand the acronym in his subject, arcardi posted a summary of his current understanding of the behavior of :=, the binding operator, and peppered the post with questions. None of which were answered this week.

http://groups.google.com/groups

Junctions and Laziness

Junctions are what we're calling superpositions this week. Piers Cawley had another crack (the operative word I think, on rereading) at his non deterministic search algorithm using junctions and a subclass of Function. Damian, of course, came up with a better possible syntax for lazy functions:


    sub some_func(Num $n) is lazy returns Num {
      return $n ** $n;
    }

Billy Naylor wondered if a similar notation could be used for memoize:


    sub fib(Num $n) is memo returns Num {
      given $n {
        when 0    { 0 }
        when 1    { 1 }
        otherwise { fib($n-1) + $fib($n-2) }
      }
    }

and Damian pointed out that this was covered in Apocalypse 2, but the name of the property was yet to be decided. Which led to discussion of appropriate names.

http://groups.google.com/groups

Primitive vs. Object Types

David Whipp was worried about the use of primitive types. He pointed out that "whenever a value passes through a primitive type, it loses all its run-time properties; and [junctions] will collapse. I worry that this could cause obscure bugs". He also worried that the similarity of names (Int for an object vs. int for a primitive) would make such problems harder to spot, and violated Larry's maxim that 'Similar things should look different.' He proposed that, in order to use primitive types, a module author should first do something like use primitives qw(int), and that maybe names like int should be changed to names like _prim_int32.

Dan wasn't entirely sure that David's basic assumption about properties/junctions was accurate, but Michael Lazzaro pointed out that this had been strongly implied by things Larry and Damian had said, though Michael later dug up a reference to Apocalypse 2 which was ambiguous about runtime properties on primitive types. Dan started making 'worried' noises about supporting primitive types and Larry, while still keeping things fluid about what will actually happen, explained more of his thoughts about them.

Garrett Goebel wondered about the difference between 'attribute' and 'property' in Perl 6. I assume everyone would like to know this. The short answer goes something like: 'attribute' is the Perl 6 term for an instance variable, a 'property' can be thought of as a 'yellow sticky note attached to an arbitrary object.' Dan has a better explanation which doesn't avoid using a trademarked term.

http://groups.google.com/groups

http://groups.google.com/groups

http://groups.google.com/groups -- Dan's attributes/properties explanation

perl6-documentation was born

On Wednesday, Michael Lazzaro (who has been doing some sterling documentation work, check out his 'introduction to variables and values' docs, linked below) proposed that now was the time to start documenting (and finalizing) the detailed design of what we know about Perl 6 so far. He is concerned that for all the discussion on the language list, most of the decisions don't appear to be being documented, nor reflected back in updated Apocalypses and other documentation.

He proposed, therefore, that perl6-language 'focus on fleshing out every last detail implied by Apocalypses 2-N, in that order' and hoped that we could 'migrate perl6-language into a list that finalizes aspects of the design, documents them, and revises them as needed'.

Allison Randal wasn't initially convinced that this was necessarily a good idea. She worried that Larry (the Official Last Word on Perl 6) would be snowed under by an RFCesque tide of new documentation, and that reviewing such a tide would make him lose focus.

At this point, Michael threw the Virtual Coffee Mug.

After a further period of discussion, Dan pointed out that the key was to 'Just Do It' (a phrase normally pronounced with four words), so we created the perl6-documentation mailing list and your summarizer got a bunch more work.

The thread is long. I've summarized the main line (badly) and now provide some links to key posts, but if you want more detail I suggest you follow the first link and read the thread. For those that like drama and high emotion, the virtual CM chucking post is Michael's response to Allison's reply. I'm not going to link directly to it; trust me, context is better.

http://cog.cognitivity.com/perl6/val.html -- vars and values intro

http://groups.google.com/groups

http://groups.google.com/groups -- Dan talks sense

http://groups.google.com/groups -- So does Simon Cozens

http://groups.google.com/groups -- The tests should be the spec

Meanwhile, in perl-documentation

The new baby got off to a flying start as Michael Lazzaro laid down his goals for the project. Early discussion centered on the overall structure of the intended documentation; what formats it should be written in; the requirements for concrete, executable Perl 6 test cases and the importance of fluidity. Michael repeatedly stressed that it was vital that the documentation list retain focus; his goal is that the entire list should work on one thing at a time.

http://groups.google.com/groups

Roll Call

Michael asked for a quick roll call of who was interested in the documentation project. As an added bonus, he asked that even the lurkers put their hands up if they were interested. Surprisingly, some of them decloaked and did so.

http://groups.google.com/groups

Project Goals?

Michael formally kicked off the discussion with the question "How can this documentation project best help with the overall goal of producing a finished Perl 6?" Answers on a piece of data to the list, do not attempt to write on both sides of the data at once.

http://groups.google.com/groups

Project Start: Section 1

Late Friday, Michael kicked off discussion of the first section, most of the discussion took place during the following week, which is when I'll summarize it.

http://groups.google.com/groups

In Brief

Leo Tötsch and Brent Dax have been working on ways of making Parrot GC go faster by improving the performance of the 'destroy' phase.

Andy Dougherty sent in a patch to ensure that the languages/perl6 build will work without bison. Andy found and fixed a compiler-specific bug introduced by someone using C++ style comments.

Richard Proctor suggested that miniparrot should be called 'budgie'.

Leo Tötsch showed off some numbers for the life generations/sec test. JIT is looking very quick indeed, it's only about 25 percent slower than a native C implementation.

Dan's back from Seattle and digging through his mail backlog.

Leo Tötsch has been thinking about regexes/patterns/rules and thinks that we should reintroduce a regex state object, making regexes reentrant once more.

Who's who in Perl 6?

Who are you?
Simon Glover
What do you do for/with Perl 6?
Write tests, stomp on compiler warnings, fix bugs (occasionally)...

Basically, I try to help with some of the tedious but necessary stuff in order to free other people to concentrate on design & implementation.

Where are you coming from?
About this time last year, I started to get a bit frustrated at what appeared to me to be the slow pace of Parrot development, when I suddenly thought: 'You know, if you gave them a hand, they'd finish sooner'. So I did (and we haven't... yet. Of course, I've now got a better understanding of why this takes a long time).

I'd also like to add that I'm proof that you don't have to be a C coder in order to be useful on a project like this...

When do you think Perl 6 will be released?
Depends what you mean by Perl 6 -- after all, we already have a subset of it up and running on Parrot. Seriously, I think we'll have something that's genuinely usable and useful well before the end of 2003, even if there are still a few loose ends to tie up.
Why are you doing this?
I like Perl - it matches the way I think. The problem is, Perl is too slow for many of the things that I'd like to use it for, and too hard to extend. Parrot should fix both of these problems.

Also, it's nice to see one of my favourite features of F90 finally make it into Perl :-)

You have 5 words. Describe yourself.
Mild-mannered English computational astrophysicist.
Do you have anything to declare?
All the C I know I learnt from Parrot. (Well, OK, K&R helped too, but it's amazing how much you can learn from reading other people's code).

Acknowledgements, requests and general banter

This summary was again brought to you from the 0625 Newark on Trent to Kings Cross and the 1720 Kings Cross to Newark on Trent trains. It was fuelled by copious amounts of GNER coffee and, one one occasion, a bacon and tomato toasted sandwich. I'd like to extend my thanks and best wishes to Avril Hill, who's been bringing me morning tea for months now, but who's about to escape the train and start working on Leeds station.

Proofreading services were supplied by aspell and myself. Blame aspell if it's really terrible.

I'm running short of questionnaire answers. If you've ever been mentioned in a Perl 6 Summary, or if you haven't (yet), please consider answering the questions Simon just answered and sending them to mailto:5Ws@bofh.org.uk. Thanks.

Now, if we all join in with the chorus:

If you didn't like this summary, what are you doing still reading it? If you did like it, please consider one or both of the following options:

The fee paid for publication of these summaries on perl.com is paid directly to the Perl Foundation.

Object Oriented Exception Handling in Perl

The main goal of this article is to discuss in detail about exception handling in Perl and how to implement it using Error.pm. On our way, we'll be touching upon the advantages of using exception-handling over traditional error-handling mechanisms, exception handling with eval {}, problems with eval {} and the functionalities available in Fatal.pm. But by and large, our focus we'll be on using Error.pm for exception handling.

What Is an Exception ?

An exception can be defined as an event that occurs during the execution of a program that deviates it from the normal execution path. Different types of errors can cause exceptions. They can range from serious errors such as running out of virtual memory to simple programming errors such as trying to read from an empty stack or opening an invalid file for reading.

An exception usually carries with it three important pieces of information:

  1. The type of exception - determined by the class of the exception object
  2. Where the exception occurred - the stack trace
  3. Context information - error message and other state information

An exception handler is a piece of code used to gracefully deal with the exception. In the rest of article, the terms exception handler and catch block will be used interchangeably.

By choosing exceptions to manage errors, applications benefit a lot over traditional error-handling mechanisms. All the advantages of using exception handling are discussed in detail in the next section.

Advantages of Using Exception Handling

Object-oriented exception handling allows you to separate error-handling code from the normal code. As a result, the code is less complex, more readable and, at times, more efficient. The code is more efficient because the normal execution path doesn't have to check for errors. As a result, valuable CPU cycles are saved.

Another important advantage of OO exception handling is the ability to propagate errors up the call stack. This happens automatically without you, the programmer, explicitly checking for return values and returning them to the caller. Moreover, passing return values up the call stack is error prone, and with every hop there is a tendency to lose vital bits of information.

Most of the time, the point at which an error occurs is rarely the best place to handle it. So, the error needs to be propagated up the call stack. But by the time the error reaches the place where it can be handled suitably, a lot of the error context is lost. This is a common problem with traditional error-handling mechanisms (i.e. checking for return values and propagating them to the caller). Exceptions come to the rescue by allowing contextual information to be captured at the point where the error occurs and propagate it to a point where it can be effectively used/handled.

For instance, if you have a function processFile() that is the fourth method in a series of method calls made by your application. And also func1() is the only method interested in the errors that occur within processFile(). With a traditional error-handling mechanism, you would do the following to propagate the error code up the call stack until the error finally reaches func1().

  sub func3
  {
    my $retval = processFile($FILE);
    if (!$retval) { return $retval; }
    else {
      ....
    }
  }

  sub func2
  {
    my $retval = func3();
    if (!$retval) { return $retval; }
    else {
      ....
    }
  }

  sub func1 
  {
    my $retval = func2();
    if (!$retval) { return $retval; }
    else {
      ....
    }
  }

  sub processFile
  {
    my $file = shift;
    if (!open(FH, $file)) { return -1; }
    else {
      # Process the file
      return 1;
    }
  }

With OO exception handling, all you need to do is wrap the function call to func2() within the try block and handle the exceptions thrown from that block with an appropriate exception handler (catch block). The equivalent code with exception handling is shown below.

   sub func1
   {
     try {
       func2();
     }
     catch IOException with {
       # Exception handling code here
     };  
   }

   sub func2 { func3(); ... }
   sub func3 { processFile($FILE); ... }

   sub processFile
   {
     my $file = shift;
     if (!open(FH, $file)) { 
       throw IOException("Error opening file <$file> - $!");
     }
     else {
       # Process the file
       return 1;
     }     
   }

Since func1() is the only function to possess a catch block, the exception that was thrown in the processFile() function is propagated all the way up to func1(), where it would be appropriately dealt with, by the catch block. The difference in the bloat factor and code obfuscation level between these two error handling techniques is obvious.

Finally, exceptions can be used to group related errors. By doing this, you will be able to handle related exceptions using a single exception handler. The inheritance hierarchy of the exception classes can be used to logically group exceptions. Thus, an exception handler can catch exceptions of the class specified by its parameter, or can catch exceptions of any of its subclass.

Let's Do It in Perl

Perl's Built-In Exception Handling Mechanism

Perl has a built-in exception handling mechanism, a.k.a the eval {} block. It is implemented by wrapping the code that needs to be executed around an eval block and the $@ variable is checked to see if an exception occurred. The typical syntax is:

  eval {
    ...
  };
  if ($@) {
    errorHandler($@);
  }

Within the eval block, if there is a syntax error or runtime error, or a die statement is executed, then an undefined value is returned by eval, and $@ is set to the error message. If there was no error, then $@ is guaranteed to be a null string.

What's wrong with this? Since the error message store in $@ is a simple scalar, checking the type of error that has occurred is error prone. Also, $@ doesn't tell us where the exception occurred. To overcome these issues, exception objects were incorporated in Perl 5.005.

From Perl 5.005 onward, you can do this:

  eval {
    open(FILE, $file) || 
      die MyFileException->new("Unable to open file - $file");
  };

  if ($@) {
    # now $@ contains the exception object of type MyFileException
    print $@->getErrorMessage();  
	# where getErrorMessage() is a method in MyFileException class
  }

The exception class (MyFileException) can be built with as much functionality as desired. For example, you can get the calling context by using caller() in constructer of the exception class (typically MyFileException::new()).

It is also possible to test specific exception types as shown below:

  eval {
    ....
  };

  if ($@) {
    if ($@->isa('MyFileException')) {  # Specific exception handler
      ....
    }
    else { # Generic exception handler
      ....
    }
  }

If the exception object implements stringification, by overloading the string operations, then the stringified version of the object would be available whenever $@ is used in string context. By constructing the overloading method appropriately, the value of $@ in string context can be tailored as desired.

  package MyException;

  use overload ('""' => 'stringify');
  ...
  ...
  sub stringify
  {
    my ($self) = @_;
    my $class = ref($self) || $self;

    return "$class Exception: " . $self->errMsg() . " at " . 
                                  $self->lineNo() . " in " . 
								  $self->file();
    # Assuming that errMsg(), lineNo() & file() are methods 
	# in the exception class
    # to store & return error message, line number and source 
	# file respectively.
  }

When overloading the string operator '"', the overloading method (stringify() in our case) is expected to return a string representing the stringified form of the object. The stringify() method can return various context/state information about the exception object, as part of the string.

Problems with eval

The following are some of the issues in using the eval {} construct:

  • Similar looking syntactic constructs can mean different things, based on the context.
  • eval blocks can be used for both, building dynamic code snippets as well as for exception handling
  • No builtin provision for cleanup handler a.k.a finally block
  • Stack trace if required, needs to maintained by writing custom code
  • Aesthetically unappealing (Although this is very subjective)

Error.pm to the Rescue

The Error.pm module implements OO exception handling. It mimics the try/catch/throw syntax available in other OO languages like Java and C++ (to name a few). It is also devoid of all the problems that are inherent when using eval. Since it's a pure perl module, it runs on almost all platforms where Perl runs.

Use'ing Error.pm

The module provides two interfaces:

  1. Procedural interface for exception handling (exception handling constructs)
  2. Base class for other exception classes

The module exports various functions to perform exception handling. They will be exported if the :try tag is used in the use statement.

A typical invocation would look like this:

  use Error qw(:try);

  try {
    some code;
    code that might thrown an exception;
    more code;
    return;
  }
  catch Error with {
    my $ex = shift;   # Get hold of the exception object
    handle the exception;
  }
  finally {
    cleanup code;
  };  # <-- Remember the semicolon

Don't forget to include the trailing semicolon (;) after the closing brace. For those of you who want to know why: All these functions accept a code reference as their first parameter. For example, in the try block the code that follows try is passed in as a code reference (anonymous function) to the function try().

try Block

An exception handler is constructed by enclosing the statements that are likely to throw an exception within a try block. If an exception occurs within the try block, then it is handled by the appropriate exception handler (catch block), associated with the try block. If no exceptions are thrown, then try will return the result of block.

The syntax is: try BLOCK EXCEPTION_HANDLERS

A try block should have at least one (or more) catch block(s) or one finally block.

Catch Block

The try block associates the scope of its associated exception handlers. You associate exception handlers with a try block by providing one or more catch blocks directly after the try block:

  try {
    ....
  }
  catch IOException with {
    ....
  }
  catch MathException with {
    ....
  };

The syntax is: catch CLASS with BLOCK

This enables all errors that satisfy the condition $ex->isa(CLASS) to be handled by evaluating BLOCK.

The BLOCK receives two parameters. The first is the exception being thrown and the second is a scalar reference. If this scalar reference is set on return from the catch block, then the try block continues as if there was no exception.

If the scalar referenced by the second parameter is not set, and no exceptions are thrown (within the catch block), then the current try block will return with the result from the catch block.

In order to propagate an exception, the catch block can choose to rethrow the exception by calling $ex->throw()

Order of Catch Blocks Matter

The order of exception handlers is important. It's all the more critical if you have handlers at different levels in the inheritance hierarchy. Exception handlers that are built to handle exception types that are furthermost from the root of the hierarchy (Error) should be placed first in the list of catch blocks.

An exception handler designed to handle a specific type of object may be pre-empted by another handler whose exception type is a superclass of that type. This happens if the exception handler for that exception type appears earlier in the list of exception handlers.

For example:

  try {
    my $result = $self->divide($value, 0);  
	# divide() throws DivideByZeroException
    return $result;  
  }
  catch MathException with {
    my $ex = shift;
    print "Error: Caught MathException occurred\n";
    return;
  }
  catch DivideByZeroException with {
    my $ex = shift;
    print "Error: Caught DivideByZeroException\n";
    return 0;
  };

Assuming the Inheritance hierarchy:

  MathException is-a Error                 
       [ @MathException::ISA = qw(Error) ]
  DivideByZeroException is-a MathException 
       [ @DivideByZeroException::ISA = qw(MathException) ]

In the above code listing, the DivideByZeroException is caught by the first catch block instead of the second. That is because DivideByZeroException is a subclass of MathException. In other words, $ex->isa('MathException') returns true. Hence, the exception is handled by the code within the first catch block. Reversing the order of the catch blocks would ensure that the exception is caught by the correct exception handler.

Finally Block

The final step in setting up an exception handler is providing a mechanism for cleaning up before control is passed to different part of the program. This can be achieved by enclosing the cleanup logic within the finally block. Code in the finally block is executed irrespective of what happens within the try block. Typical use of the finally block is to close files or in general to release any system resource.

If no exceptions are thrown, then none of the code in the catch block(s) gets executed. But the code in the finally block is always executed.

If an exception is thrown, then code in the appropriate catch block is executed. Once the execution of that code is complete, the finally block is executed.

  try {
    my $file = join('.', '/tmp/tempfile', $$);

    my $fh = new FileHandle($file, 'w');
    throw IOException("Unable to open file - $!") if (!$fh);

    # some code that might throw an exception
    return;
  }
  catch Error with {
    my $ex = shift;
    # Exception handling code
  }
  finally {
    close($fh) if ($fh);    # Close the temporary file
    unlink($file);          # Delete the temporary file
  };

In the above code listing, a temporary file is created in the try block and the block also has some code that can potentially throw an exception. Irrespective of whether the try block succeeds, the temporary file has to be closed and deleted from the file system. This is accomplished by closing and deleting the file in the finally block.

Remember, only one finally block is allowed per try block.

Throw Statement

throw() creates a new "Error" object and throws an exception. This exception would be caught by a surrounding try block, if there is one. Otherwise the program will exit.

throw() can also be called on an existing exception to rethrow it. The code listing below illustrates how to rethrow an exception:

  try {
    $self->openFile();
    $self->processFile();
    $self->closeFile();
  }
  catch IOException with {
    my $ex = shift;
    if (!$self->raiseException()) {
      warn("IOException occurred - " . $ex->getMessage());
      return;
    }
    else { 
      $ex->throw(); # Re-throwing exception
    }
  };

Building Your Own Exception Class

Setting the value of the $Error::Debug package variable to true, enables the capturing of stack trace for later retrieval using the stacktrace() method. (In case you are not familiar, stacktrace is a list of all the methods executed in sequence that lead to the exception).

The code snippet below creates the exception classes MathException, DivideByZero and OverFlowException. Where the latter two are subclasses of MathException and MathException by itself is derived from Error.pm

  package MathException;

  use base qw(Error);
  use overload ('""' => 'stringify');

  sub new
  {
    my $self = shift;
    my $text = "" . shift;
    my @args = ();

    local $Error::Depth = $Error::Depth + 1;
    local $Error::Debug = 1;  # Enables storing of stacktrace

    $self->SUPER::new(-text => $text, @args);
  }
  1;
	  
  package DivideByZeroException;
  use base qw(MathException);
  1;

  package OverFlowException;
  use base qw(MathException);
  1;

And More ...

The error modules has other special exception handling blocks, such as except and otherwise. They are deliberately not covered here because they are specific to Error.pm, and you won't find them in other OO languages. For those who are interested, please refer the POD documentation that is embedded within Error.pm.

Fatal.pm

If you have some functions that return false on error and a true value on success, then you can use Fatal.pm to convert them into functions that throw exceptions on failure. It is possible to do this to both user defined functions as well as built-in functions (with some exceptions).

  use Fatal qw(open close);

  eval { open(FH, "invalidfile") }; 
  if ($@) {
    warn("Error opening file: $@\n");
  }
  
  ....
  ....
  
  eval { close(FH); }; 
  warn($@) if ($@);

By default, Fatal.pm catches every use of the fatalized functions i.e.

  use Fatal qw(chdir);
  if (chdir("/tmp/tmp/")) {
    ....
  }
  else { 
    # Execution flow never reaches here
  }

If you are fortunate enough to have Perl 5.6 or later, then you can circumvent this by adding :void in the import list. All functions named after this in that import list will raise an exception only when they are called in void context i.e. when their return values are being ignored.

By changing the use statement, as shown below we can be sure that the code in the else block is executed when chdir() fails

  use Fatal qw(:void chdir);

The code listing below illustrates the use of Fatal.pm in conjunction with Error.pm.

  use Error qw(:try);
  use Fatal qw(:void open);

  try {
    open(FH, $file);
    ....
    openDBConnection($dsn);
    return;
  }
  catch DBConnectionException with {
    my $ex = shift;
    # Database connection failed
  }
  catch Error with {
    my $ex = shift;
    # If the open() fails, then we'll be here  
  };

The Perl6 Connection

Since the exception handling syntax in Perl 6 is expected to be modeled closely against Error.pm as detailed in the Perl 6 RFC 63 Exception handling syntax - http://dev.perl.org/rfc/63.pod, also in RFC 80 and RFC 88. It would make sense for developers to make use of OO-ish exception handling capabilities in their code and later on migrate to the exception handling syntax in Perl 6, as and when it is available.

Conclusion

The following are some of the key reasons to choose exception-handling mechanism over the traditional error-handling mechanisms:

  • Error handling code can be separated from normal code
  • Less complex, more readable and more efficient code
  • Ability to propagating errors up the call stack
  • Ability to persist contextual information for the exception handler
  • Logical grouping of error types

So, stop returning error codes and start throwing exceptions.

Have an exceptional time !!

This week on Perl 6 (10/28-11/03, 2002)

Welcome to the latest of the ongoing series of Perl 6 summaries, in which your arrogant moderator does battle with the forces of prolixity in a Brobdingnagian attempt to tame the tortuously tangled threads of Perl 6's design and development mailing lists. And if I keep up the purple prose at that rate, then it'll *still* be clearer than the tangle that is this week's perl6-language discussion.

However, because it's customary and because the language list scares me, we'll start with the comparatively tame perl6-internals.

Fun With File Formats

Toward the end of last week, Rhys Weatherley had asked about being able to insert arbitrary chunks of metadata into parrot bytecode files. Dan ended up producing a `draft sketch' of the bytecode generation facilities and the ability to add arbitrary chunks of metadata was conspicuous by its absence. People didn't seem to be happy about this, lamenting a lack of flexibility, both in the overall file structure and in what one could stick into the bytecode. Dan mounted a sturdy defense, pointing out that we want `a file format that does what we need it to -- present executable bytecode data to the interpreter -- as fast as possible. Everything else is secondary to that.'

Kv Org wondered whether it would be a good idea to worry about sandbox issues in the bytecode format, but nothing came of that question. Well, not this week anyway.

http://groups.google.com/groups

http://groups.google.com/groups

http://groups.google.com/groups

http://groups.google.com/groups

Portable Linking Issues

Andy Dougherty is having portability problems. He wants to portably compile and link three files, and he's having problems and wondered what the best way was to get an early test compiling properly on all platforms. Help was supplied, the build was fixed, and the world remained safe for democracy. (Modulo a few local difficulties.)

http://groups.google.com/groups

Implicit Stack Direction Probe

Meanwhile, Jason Gloudon's patch to move the stack direction probe back to initialization time rather than compile time was offered. I'm assuming that Nicholas Clark's suggested speedup trick from last week was implemented as part of it, but I'm no great understander of C.

http://rt.perl.org/rt2/Ticket/Display.html

Of MOPS and Microops

There's been some discussion of granting a small number of Parrot registers 'most favored' status. The idea being that a small number of registers would actually be held in global (possibly real register) variables, with the rest being accessed through via indirection through the interpreter. Apparently, the JIT core already does some optimization along these lines, and Dan doesn't seem to be sure that doing it for the main interpreter would actually be much of win. Discussion continues.

http://groups.google.com/groups

Very Complete Lexical Scopes

Jonathan Sillito has submitted a patch that `implements a very complete set of lexical scope semantics.' It looks pretty cool to my untutored eye. General response was positive, though Jürgen Bömmels did have a query about how to create a new scope.

http://rt.perl.org/rt2/Ticket/Display.html

miniparrot, a First Attempt

If you've been paying attention to the Parrot build process, then you aware that it was always a goal to use a cut-down variant of Parrot itself to run the configuration tests. The plan is that this miniparrot should be buildable with nothing more than an ANSI-compliant C compiler. Josh Wilmes thinks we're about ready to start building said miniparrot, and offered his first cut to the list. Response was positive, with quibbles, which is about what one would expect.

http://groups.google.com/groups

Meanwhile, Over in perl6-language (or "The Horror! The Horror!")

The dreaded `Operator Reshuffle' thread continues apace -- of the 450 posts last week I'd say about 400 of 'em were discussing various aspects. Bear in mind, too, that the path of discussion could be described as helical (sort of like circular, but getting more and more wound up with each go 'round). There are at least two factions involved, roughly caricatured as `Simon Cozens versus the rest of the world.' Simon can be thought of as the voice of conservatism (or Reason, depending on whether you agree with him or not), generally arguing against stuff he considers massively ugly or confusing. Simon's allies vary depending on which issue he's discussing and his worries include:

  • Perl 6 is going to be even harder to parse than Perl 5
  • Unicode operators in the core language are just wrong. Many people agree with him.
  • Superpositional operators will be too rare to justify giving them precious one character operators.

This is, of course, a gross simplification of what's going on in the various operator threads, but it does cover a fair number of the issues that are arising in the attempt to get ^ back as exclusive or (which then frees ~ up to become string concatenate, which... ah, go read last week's summary, I already did this...)

BTW, 'Vectorizing' is the new 'Hyperizing' (or did I do that last week?)

Here's the various threads involved in the kerfuffle, along with Michael Lazzaro's utterly wonderful summaries of the current core operator list as he sees it.

http://groups.google.com/groups -- Op list, Take 3.

http://groups.google.com/groups -- Take 4

http://groups.google.com/groups -- Take 5

http://groups.google.com/groups -- Take 5a

http://groups.google.com/groups -- Take 5b

http://groups.google.com/groups -- Take 6

http://groups.google.com/groups -- Pointers to Unicode stuff

http://groups.google.com/groups -- Someone coming in late

http://groups.google.com/groups -- Questioning the value of infix superpositions

Smalltalk-Type Collection Classes?

One of the subthreads of the mammoth operator thread covered whether it might be a good idea to include a set of collection classes in the style of the Smalltalk Collection hierarchy to the Perl 6 core dist.

http://groups.google.com/groups

Persistence of superpositions

Buddha Buck wondered how pervasive superpositions were, and for how long they would remain entangled. Damian thinks they should be all pervading and fully propagating. This thread didn't really stay on topic ... .

http://groups.google.com/groups

Proposal: Vector Operators for Hashes

Arcadi made some proposals about how to extend the concept of vector operators to hashes as well as lists and arrays. Discussion ensued. People seem to like the idea of extending vector ops to cover hashes, but weren't necessarily sure that Arcadi's approach was the right one. 'Adverbial' control of how the vector ops work was also discussed, though Larry gave the impression that he thought this might be a generalization ... .

http://groups.google.com/groups

Plaintive Whine About for Syntax

Dave Storrs really doesn't like the syntax of the `parallel streams' variant of for:

    # This iterates over @a and @b in parallel
    for @a; @b -> $x is rw; $y { $x = $y[5] }

and he offered a list of suggestions, though I think more people disliked his alternatives (even among those who didn't like the current syntax) than liked 'em. Damian pointed out that a little finesse with the editor could be of some assistance:

    for @a      ; @b       
     -> $x is rw; $y { ... }

Ed Peshko wondered what happened when you had a lot of parallel streams, and Damian obliged with:

    for  @a;  @b;  @c;  @d;  @e
     ->  $a_var1 is rw, $a_var2 is rw;
              $b_var is rw;
                   $c_var is rw;
                        $d_var is rw;
                             $e_var1 is rw, $e_var2 is rw 
    {
        ...
    }

But this is a somewhat pathological case. Damian also mentioned that he and Larry had thought long and hard about whether to interleave sources and iterators before deciding on the current syntax.

http://groups.google.com/groups

http://groups.google.com/groups

Nondeterministic Algorithms, Flexops and Stuff

Piers Cawley made heads hurt (his included) when he posted a question about using superpositions (aka flexops) to implement nondeterministic algorithms. The particular example given was an algorithm to find a path between two nodes of an acyclic-directed graph (lifted from a text on lisp). Jonathan Scott Duff thought the idea was 'neat.' For an encore, Piers redid the function without flexops, using a continuation-based implementation of choose and fail (which hurts my head more than the superposition-based version, frankly).

http://groups.google.com/groups

Primitive Boolean Type?

Michael Lazzaro asked a tricky question: Can a bit be undefined? If so, then it leads to the somewhat counterintuitive assumption that one would need two bits to store a single `bit.' Which is certainly odd. However, it turns out that native types like bit, int, cannot be undefined; so that's all right. This then branched off into a discussion of whether Perl 6 would have an explicit Boolean type. It won't. Unless Larry changes his mind.

http://groups.google.com/groups

Labeled If Blocks

Last week, Steve Canfield wondered whether Perl 6 would have labeled if blocks, which would allow one to jump out of arbitrary levels of nested ifs. It seems the answer is `no,' but this led to a discussion of possible control statements that affect the flow of control in different sorts of blocks (subs, conditionals, loops, etc.). It's looking like we may end up with a leave statement. The other possibility would be to make return a method, allowing one to do:

    Loop.return($x)

or whatever.

http://groups.google.com/groups

http://groups.google.com/groups

In Brief

There was some discussion on the internals list about what functions need to have an interpreter argument. The basic rule appears to be: `If it's going to allocate memory, it needs an interpreter.'

Leopold Toetsch has rejigged the startup procedure so that we will always have a valid interpreter, making patches like the one that allowed for a NULL interpreter in sprintf unnecessary.

Discussion of the Parrot Copyright/License changes was subdued, bordering on the nonexistent. Let's hope it stays as smooth.

Leo Toetsch has been doing various refactorings of Parrot ops.

There was discussion about how to generate the MD5 hashes for Parrot bytecode `fingerprints.' The catch is that the Perl module Digest::MD5 isn't guaranteed to be available on all Perl installations ... .

Josh Wilmes did a massive 'indentation cleanup' patch (2000+ line patch).

Allison Randal has a fascinating article all about Perl 6 topics and topicalizers at http://www.perl.com/pub/a/2002/10/30/topic.html, which is well worth the read.

Paul Johnson had some thoughts about using properties on statements and the like as a way of providing metadata to things like code-coverage tools.

Who's Who in Perl 6?

Who are you?
Mike Lazzaro. My wife and I own a company called Cognitivity (http://www.cognitivity.com/) in Burbank, California. We met at Caltech, in Pasadena. We use Perl5 for our commercial e-learning software (online, customizable corporate training software). This is the first company we actually own, after working as consultants/contractors/employees for years at other places. It's great.
What do you do for/with Perl 6?
Originally, I just wanted to document Perl6's OO behaviours, but I soon found that to be impossible without documenting everything else first, so that's what I'm doing. I'm going piece-by-piece through all the early Apocalypses, attempting to fill in all the details and implications, which I am writing up in book-like form. As I get them done, I'll post them for review and feedback -- but before that, I'll have a lot of little questions and inconsistencies that I need to pin down.

My feeling is, because I'm *not* on the design team, and I *don't* know all the thinking on how and why things are decided, I'm a good test person to write newbie-level documentation. If you can explain it to me, that's a pretty good indication that you and I can explain it to someone else. I think the disconnection between designer and documenter will be important, in this case, because we want Perl6 to be heavily adopted by mere mortals, not just experts.

Where are you coming from?
I've been using Perl since the 4 to 5 migration. Before that, I was mainly a C/C++ person. Before that, assembler. Perl5 is the best language I've ever used, but lately it's had some enterprise-level scalability problems that I need to solve, if I'm going to keep using it. Hence, I'm helping with Perl6.
When do you think Perl 6 will be released?
Sooner than people think ... maybe a robust alpha within six months, I bet. People are worried about the length of time it's taking to get through the initial decisions, but most of the hard ones have already been done. It's going to pick up dramatically after the next two or three Apocalypses.
Why are you doing this?
Because I've had to work in five different languages over the past few years, and they all suck, each in their own special way. Horribly. If I'm going to continue programming as a career, I want to work in a language that, as much as possible, takes the grunt work out. I don't like re-solving the same design patterns umpteen times. That's something a computer should do for me.

Why am I volunteering for documentation? Dunno, seemed like that effort was falling behind, since everyone keeps asking the same questions, over and over (like me, for example). And I can type fast. And I've got lots of experience at herding cats, which can't hurt ... .

You have five words. Describe yourself.
Programmer. Manager. Writer. Optimist. Cynic.
Do you have anything to declare?
I've grown to hate most technical terms, because nobody uses them to mean the same way. So I have an allergic reaction to descriptions that use a lot of big words to explain something that should be Much More Obvious. You'll find I post a lot of "please clarify" messages, to try to beat that out of people. :-) It doesn't always mean I'm dense, though sometimes it does. Sometimes it means "No -- really. Is that your final answer?"

Acknowledgements, Requests and the Third Thing.

This summary was once again brought to you from the comfort and security of a GNER Express train running between Newark and London, and from the greater comfort and security of my armchair at home. Production was abetted by industrial quantities of site tea (in the case of GNER) and Earl Grey China Moon tea (in the armchair).

Proofreading was mostly done by Piers Cawley, so you can blame him if there are any outrageous typos.

And, as the postamble usually goes, if you didn't like this summary, then what are you doing still reading it? If you did like it, then please consider one or both of the following options:

The fee paid for publication of these summaries on perl.com is paid directly to the Perl Foundation.

Writing Perl Modules for CPAN

As Andy Lester points out in this month's Perl Review, one big advantage of there being so many Perl books around is that the publishers can now get around to putting out books on some of the more "niche" areas of Perl. Finally, we can explore many areas that haven't really been written down and codified before.

Sam Tregar's "Writing Perl Modules For CPAN" certainly does this, and in a good way; most hints and strategies for designing, creating and maintaining Perl modules, including the sometimes arduous community interaction that this entails, have been handed down wordlessly through observation of the old hands. I tried my best in the core perlnewmod documentation to explain some of the issues involved, but Sam - a bit of an old hand himself, with the HTML::Template and Devel::Profiler modules amongst his output - takes the time to cover all the bases: from how to create a module distribution and how to get your PAUSE ID and so on to how to handle feature creep, setting up mailing lists and CVS servers, and with "bonus" chapters on XS programming and CGI applications.

Don't be put off by the book's title; even if you're not planning on making your modules public, we've found that the techniques of good distribution management and source control explained in this book are assets even when you're developing modules internal to a company or specific application.

Frequent readers of my reviews will know that one of my favorite subjects is introductory filler, and this book doesn't get off lightly either; chapter 1, the history and motivation of the CPAN, really ought to go in the foreword, and chapter 2, Perl module basics, should be required knowledge.

The writing style is friendly but direct, although I occasionally feel that the author tends to overuse footnotes a little, (Chapter 7 has 25 footnotes in 10 pages) and has a good mix of practical and philosophical discussion appropriate for this topic. The code style is perfectly fine, although I would like to have seen use strict a little more prominently, and some discussion of error handling and checking would not have gone amiss.

On the down side: typography. For some reason, the book's designer is enamoured of bold and italic typewriter faces for headings, which frankly looks horrible. Sadly, typos are rife, and there are some surprising omissions, too: The wonderful cpan-upload script is not mentioned, nor is the CPAN bug-tracking system, and coverage of testing, one of the recent obsessions of the Perl module community, is quite thin.

On the other hand, I was surprised by the XS chapters; they work. Sam somehow manages to pack just enough information into two relatively slim chapters at the end of the book to allow some pretty complex XS modules to be created by the adventurous reader, but then follows it with quite a bit of repetition in the following chapter, on Inline::C.

Similarly, the chapter on Great CPAN Modules was an unexpectedly good read - I'd never before sat down and thought about why one particular XML parsing module (say) should be more popular than another, and this is a good summary of the issues involved.

If you're thinking about writing a Perl module, whether or not it's for public consumption, then I'd certainly recommend getting a copy of this book; I certainly learned a few things about module maintainance from it, and I'm sure you will too.


Writing Perl Modules for CPAN is published by Apress.

This week on Perl 6 (10/20-27, 2002)

You may have noticed that this summary is late. Um ... [looks sheepish, shuffles feet], the dog ate my homework. I did a tiny bit of procrastination at the beginning of the week and then got totally overtaken by events involving failed AC adaptors and general confusion. Sorry folks, it will probably happen again, but hopefully not in the near future.

So, kicking off, as is customary, with perl6-internals before getting down to attempting to summarize the monster that was perl6-language:

C# and Parrot

The dialogue with Rhys Weatherley and Gopal V from the DotGNU project continues apace, mostly to do with clarifying what C# needs in the way of datatypes and the like. It appears that Leon Brocard is the go to guy if you need to know the exact details of almost anything in a language spec. Maybe he's just really good with Google.

Gopal V wondered whether there was someone involved in p5i who would mind acting as a liaison with the DotGNU people and who could give them a heads up when, for example, the packfile format changed. Leopold Toetsch wondered what type of changes were potential C# breakers, as there were probably things that we thought of as `internal' that the C# team could be depending on. Leo also thought that the liaison person should probably be Dan.

http://groups.google.com/groups

Scratchpad Confusion

At the end of last week, Allen Short pointed out some discrepancies between the implementation of scratchpads and the description of them in PDD6. John Sillito reckoned that PDD6 was waiting on a rewrite from Dan, especially where Scratchpad PMCs were concerned as there were a couple of different patches waiting on Dan's say so. Dan also offered some clarification, but hasn't ruled on the Scratchpad PMCs yet.

http://groups.google.com/groups

Help! Bugs! Crawling All Over Me! OR the Road to 0.0.9

Steve Fink wants the GC bugs ironed out before he goes adding much in the way of new features, and he wants to start putting together a 0.0.9 with working GC, too. To that end, he deliberately broke all the tests by turning GC_DEBUG on for tests. There's a certain amount of cleverness involved in how he did this; read his post if you're interested. Peter Gibbs found what he thought was a fix for a couple of the failures and pointed to the possibility of a fundamental problem in MultiArray as the culprit for the remaining failure. Steve applied this patch with much rejoicing, and then came up with a trial patch that seemed to fix the multiarray-triggered failure. This patch had not been finalized by the end of the week.

Steve also kicked off discussion of the forthcoming 0.0.9 release, when he posted his list of prerequisites and sparked off a decent amount of discussion of various points. Steve's overarching goal for this release appears to be 'bug reduction and general consolidation.'

http://groups.google.com/groups

http://groups.google.com/groups

Keyed ops, the Return.

I think it's safe to say that some people aren't entirely happy with keyed ops as they stand now in Parrot. The week before, Leopold Toetsch had written a proposal for keyed ops. This week, he supplied a proof of concept patch. Jürgen Bömmels liked it but Dan took a little more convincing. I'm not sure he is entirely convinced yet, but he's willing to live with it.

http://groups.google.com/groups

64-bit ints and Noncapable Hardware

Dan announced that he was about to bite the bullet and declare that INTVALS have to be 64-bit integers and wanted to know of any (plausible) platforms that have neither native nor emulated 64-bit integers. Martin D Kealey pointed at what sounds like a scary proposal from C99 involving declarations and clever compilers and wondered whether it might be a way forward for Parrot. Rhys wondered how well the idea would play with something as dynamic as Parrot and the languages expected to run on it, but Martin didn't seem to think it would be much of a problem.

http://groups.google.com/groups

http://wwwold.dkuug.dk/JTC1/SC22/WG14/docs/c9x/extended-integers/

Configuring and DOD

Erik Lechak couldn't get the latest parrot to build on WinXP. Josh Wilmes diagnosed a problem with the way the configuration tools probed for stack direction, and patched things so that stack direction detection was done at runtime once more. Jason Gloudon, who had moved the detection phase out into configuration time wasn't sure that this was a good idea 'cos it would lead to a performance hit in the stack walking code. Nicholas Clark, with his clever head on, came up with three different ways of doing things at runtime without a performance hit, and Dan blessed the third choice.

http://groups.google.com/groups

Execute in place?

Rhys Weatherley has been taking a look at our packfile format code, and thinks it could be improved by designing the format in such a way that it can be mmapped into a block of memory and executed immediately, as opposed to the way parrot currently does it, which involves moving stuff around in memory before starting execution. Dan said that that's how things were originally done, and if it wasn't still possible, then that was a bug.

http://groups.google.com/groups

Copyright Notices and License Stuff

Toward the end of the week, Dan announced that he was about to straighten out the copyright and licensing situation. As a first step, he would be marking everything in the core as Copyright YAS. It looks like Parrot itself will be moving to an MIT-style license `Over no objections whatsoever from the FSF.'

If you've made any contributions to Parrot's code base, then you've probably already been contacted, but if you haven't and have an objection, then you should contact Dan.

Most of the discussion of this happened during the next week, and I'll return to it in my next summary, but response was generally favorable after some clarifications from Dan.

http://groups.google.com/groups

Allow a NULL Interpreter in sprintf Like Functions

Jürgen Bömmels sent in a patch that allowed the use of a NULL interpreter in sprintf like functions. Leo Toetsch applied it, but wondered whether it was actually the right thing. Dan seemed to think that, in the long run, it probably wasn't and that, if something went horribly wrong before an interpreter got properly set up, then it was probably best to use the standard library functions.

http://groups.google.com/groups

http://groups.google.com/groups

Draft Sketch of Bytecode Generation

Dan offered a `very sketchy' draft of his thoughts on what we need from our bytecode generation system. Initial reaction seemed positive.

http://groups.google.com/groups

Meanwhile, in perl6-language

Won't someone please think of the summarizer?

There were about 150 messages in perl6-language this week. The *vast* majority of them discussing the Perl 6 built in operator list. It all started weeks ago, when Damian wanted |, & and the_as_yet_unnamed_xor_operator as superposition generating operators. But that meant we'd need somewhere else to put the bitwise operators. And people like ^ as xor, but that's not likely because of hyper ops. And nobody likes _ as a concatenation operator. It's all become very complicated.

However, in answer to a summarizer's prayer, Michael Lazzaro has taken to posting a scorecard of his understanding of what the current list of built in ops is. (A list of diffs between these would be interesting to see...). Things that appear to be set in stone:

  • ~ is the new _, which was the new . and which nobody liked.
  • ~~ is the new =~. (Otherwise =~ -> match, and ~= -> string append could get somewhat confused...) !~ stays the same.
  • | and & make any and all type superpositions, respectively. Damian has an article on why superpositions are such a good idea forthcoming for perl.com. The phrase `in constant time' will probably not be used.
  • Nobody has any idea what xor will end up as.
  • Some people are worried that changing things too radically from old Perl/Algol type syntax will make for a harder learning curve. Other people tend to think that not many programmers use bitwise ops in Perl at the moment, so the change shouldn't matter too much.
  • It's a real shame that so many Unicode characters are so hard to type.

Here's a list of Michael's various opcode lists. They're usually good entry points to the discussion. (Which is kind of fascinating...)

http://groups.google.com/groups

http://groups.google.com/groups

http://groups.google.com/groups

Character Properties

Luke Palmer wondered whether we were planning on having properties on individual characters on a string; something he felt was an essential feature. There was a certain amount of debate about the use of the word `essential' in this context, leading Luke to give some more information about what he was driving at before he was eventually convinced that what he wanted was an ideal candidate for a module.

http://groups.google.com/groups

http://groups.google.com/groups

Perl6 Built-in Types

Michael Lazzaro asked for a list of Perl6 built-in types and offered his own first cut at such a list. Larry offered some corrections, but reckoned that the list Michael had just posted was the nearest thing we had to a definitive list.

http://groups.google.com/groups

Power of Lisp Macros

Adriano Nagelschmidt has been reading Paul Graham's articles about Lisp and its advantages, especially the macro system, and wanted to know whether the macros were really as useful as Mr. Graham claimed, and whether it was worth adding something like them to Perl. General consensus appears to be ``Yes, they're really good, and yes, Perl 6 will probably have something similar.'' Larry had an interesting post on the subject (no surprise there then...)

http://groups.google.com/groups

http://www.paulgraham.com

http://groups.google.com/groups

In Brief

There was a minor kerfuffle early in the week when the Parrot CVS repository ended up with the wrong permissions. Oops.

Leopold Toetsch has implemented the splice vtable method based on the semantics in PDD2. This sparked a short discussion about copying vs. cloning.

It looks like native types are going to get type numbers just like PMCs, but native types will be negative.

Rhys Weatherley added a bunch of infix operators to IMCC's syntax.

Jürgen Bömmels added `fingerprinting' to .PBC files. The idea being that Parrot can fail at load time if it tries to load a .PBC file that was generated with a different version of core.ops. The previous behavior involved weird, hard-to-track-down runtime errors.

Some spam got past the perl6-internals filters. We were shocked.

Michael Lazzaro announced an updated Perl6 OO Cookbook at http://cog.cognitivity.com/perl6/.

Who's Who in Perl 6?

Apparently, nobody is this week. I appear to have run out of answer sets for the questionnaire. If you've been mentioned in this, or any previous summary and you've not already answered, then please drop me a line and I'll send you the questions.

Acknowledgement, Apologies and All That Good Stuff

This summary was once again brought to you from my office on board the 0625 from Newark to London and from my comfy chair at home. Distractions were provided by Xmame, Perls of the North, broken AC Adaptors and my own natural `Procrastinate now!' instincts.

Proofreading services were provided by me. Having left it as late as I did, I just want to get this summary out of the door before next week's is due. So any speeling mistooks are orl myne.

And, the old refrain: If you enjoyed this summary, then please consider one or both of the following options:

Any fee paid for publication of these summaries on perl.com is paid directly to the Perl Foundation.

Visit the home of the Perl programming language: Perl.org

Sponsored by

Monthly Archives

Powered by Movable Type 5.13-en