2020/12/18

2020 Perl Advent Calendar - Day 18

<< First | < Prev | Next >

Yesterday we took our first glance at some example code using Object::Pad. Today I'd like to continue with some more in-depth examples showing a few details of the new syntax provided. These will be real examples from actual code on CPAN.

The class keyword introduces a new package that will form a class, much like Perl's existing package keyword. It creates the new package, much as the package statement does, and additionally sets up the various Object::Pad-related machinery to have the new package be a proper class. It also makes the other new keywords available - method and has. As with package it supports setting the $VERSION of the new package by specifying a version number after the name. It also supports several new sub-keywords to further specify details about the class, such as a base class that it is extending (via the extends keyword).

Even though the class keyword acts the same as the package keyword, it isn't currently recognised by parts of CPAN infrastructure, such as the indexer which creates package-to-file indexes. As such, any module uploaded to CPAN still needs to have a package statement as well, to keep these tools happy. It's usual to find them both in combination:

use Object::Pad;

package Tickit::Widget::HBox 0.49;
class Tickit::Widget::HBox extends Tickit::Widget::LinearBox;

...

Like with package the class syntax can be used in either of two forms. It can set the prevailing package name for following declarations if used as a simple statement, or it can take a block of code surrounded by braces, and applies just to the contents of that block. The first form is usually preferred for the toplevel class in a file, with the latter form being seen for internal "helper" classes within a file. For example, the Device::Chip::NoritakeGU_D module contains three small internal helper classes defined using a block

class Device::Chip::NoritakeGU_D::_Iface::UART {
    use constant DEFAULT_BAUDRATE => 38400;

    has $_baudrate;

    ...
}

The class keyword was at least partly designed during the 2019 Perl 5 Hackathon event in Amsterdam, at which there was a similar idea for a module keyword. That has yet to be implemented anywhere, but a common theme to both ideas was that they would imply a more modern set of default pragma settings than default Perl begins with. After a class statement (or inside its block), the strict and warnings pragmas are applied, and on versions of Perl new enough to support it, the signatures feature is turned on and the indirect feature is turned off.

The method keyword adds a new function into the class namespace, much like sub does. The $self invocant parameter is handled automatically within the body of a method, meaning that a parameter signature or @_ unpacking code does not have to handle it specially. The code can totally ignore this and it will work correctly.

Because the signatures feature is automatically enabled on supported Perl versions, it makes method declarations inside classes particularly short and neat. For example, this from Tickit::Widget::Scroller:

method scroll ($delta, %opts)
{
    return unless $delta;
    
    my $window = $self->window;
    @_items or return;
    
    ...
}

Straight away we haven't needed to write the usual two lines of method setup code, of handling the $self variable and then unpacking the other arguments out of @_. As we have already seen with the use of async/await syntax, this method keyword helps reduce a lot of the "noise" of machinery out of the code, and lets us more clearly and easily see the domain-specific details inside it.

<< First | < Prev | Next >

No comments:

Post a Comment