Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??

Recently in The Future of Perl 5, there was a discussion of my keynote at the Glasgow Perl Conference. Rather than wade into that thread, I thought I should provide a brief explanation of what I was trying to achieve: a modest proposal (er, pardon that description) that was achievable, still Perl, and would not only return the conciseness of the language but would also allow Perl 5 to leapfrog many popular dynamic languages in terms of functionality (I'll skip the Perl 6 discussion and the inline discussion). This isn't a large-scale strategy to "fix everything", but a couple of small (ha!) steps which would make Perl much easier to write and maintain in large companies.


Perl has a long, strong history. Unfortunately, because Perl was the trail-blazer for many techniques taken for granted today, it sometimes went down dead-ends and those who followed learned from Perl. Perl also stole much from other languages and it's time to steal a bit more. Consider, for example, the lowly Fibonacci function. It would be natural to write it like this:

sub fib { my $nth = shift; return $nth if $nth <= 1; return fib( $nth - 1 ) + fib( $nth - 2 ); }

That looks like a perfectly natural way to write that function and if you pass it expected values, it returns expected results (we'll ignore the performance and memory issues as those aren't unique to Perl 5). But what if you pass it a -2? Or an undefined value? Or a string? Or a float? Or a typeglob? Or, or, or ...

At https://allaroundtheworld.fr/, we're used to working with large clients and large codebases and that sort of coding trips us up many times. It's hard building a large system, slinging data around left and write (er, "right"), without hitting these problems. In terms of maintenance, it's a nightmare. For short scripts, it's ok. When you're trying to build large-scale systems, it's a constant drag on developer time, even with tests (because you have to spend time and money to write tests to verify you've correctly handled what the language itself handles in many other languages). To write a robust Fibonacci function, you might write something like this:

sub fib { croak("…") if @_ != 1; my $nth = $_[0]; croak("…") if not defined $nth; croak("…") if $nth !~ /^+?\d+$/a; return $nth if $nth <= 1; return fib( $nth - 1 ) + fib( $nth - 2 ); }

But let's be honest: almost nobody does that and if you did, you'd be spending more time and money on something you often don't have to spend time and money on in other languages.

At a first pass, merely having optional typing in signatures would dramatically improve this:

sub fib(UInt $nth) { return $nth if $nth <= 1; return fib( $nth - 1 ) + fib( $nth - 2 ) }

I've found that many companies are already using experimental signatures in their production code because of how many bugs they prevent. Adding in a handful of optional types (and allowing class names), would tremendously improve the readability of Perl and help to bring it up to modern standards. We're almost there for signatures, but they've been experimental for four years and with the recent fix to deal with the subroutine attribute problem, they'll be experimental for at least another two years.

As for OO programming, Larry deliberately added bare-bones functionality to see what people would build on top of it. If you read perlootut it explains the basics of OO, but that's for new developers. Experienced developers coming to Perl will already know that. And they'll see the following CPAN modules referenced:

  • Moose
  • Moo
  • Class::Accessor
  • Class::Tiny
  • Class::Tiny::Antlers
  • Role::Tiny

Of course, at that point we say "but this means you can choose the OO system that really meets your needs. I count around 70 OO systems (with more on the way) on the CPAN. That's not counting the many "in-house" systems I've found at clients. Our popular competitors, such as PHP, Ruby, and Python, also have "minimal" OO systems, but those are much easier to use than Perl's minimal OO system. Here's a simple Point class:

Ruby:

class Point attr_accessor :x attr_accessor :y def initialize x, y @x = x @y = y end def inverted return Point.new @y, @x end end

PHP:

class Point { public $x, $y; public function __construct ($x, $y) { $this->x = $x; $this->y = $y; } public function inverted() { return new Point( $this->y, $this->x ); } }

Python:

class Point: def __init__(self, x, y): self.x = x self.y = y def inverted(self): return Point(self.y,self.x)

Core Perl 5:

package Point; use Carp 'croak'; sub new { croak('…') unless @_ == 3; my ( $class, $x, $y ) = @_; return bless { x => $x, y => $y } => $class; } sub x { croak('…') unless @_ == 1 || @_ == 2; my $self = shift if ( @_ ) { $self->{x} = shift; } return $self->{x}; } sub y { croak('…') unless @_ == 1 || @_ == 2; my $self = shift if ( @_ ) { $self->{y} = shift; } return $self->{y}; } sub inverted { croak('…') unless @_ == 1; my $self = shift; return Point->new( $self->y, $self->x ); } 1;

Is it any wonder that Perl has a certain reputation? It gets better with Moo or Moose, but those are CPAN modules and by not having a clean, minimal OO syntax in the Perl 5 core, we have 70+ CPAN OO systems competing for mindshare. Most of our competitors have very little competition in this space, which means that they don't have to spend so much time learning the OO module of the week that some companies adopted. Plus, the OO features can be optimized at the core language level (a huge win).

Here's a simple syntax I toyed with for Perl 5 (hard-coded class name in the inverted method just for an example):

class Point { has Num ($x, $y); method inverted () { return Point->new( x => $y, y => $x ); } }

That still feels like Perl 5 (to me). I tried to make it as minimal a change as possible and it's still a much cleaner syntax. Or here's an LRU cache written in this shorter syntax:

class Cache::LRU { use Hash::Ordered; our $num_caches = 0; # class data (unused +in this example) my $x = Hash::Ordered->new; # private instance da +ta has UInt $max_size = 20; # public instance dat +a method set ( Str $key, $value ) { if ( $x->exists($key) ) { $x->delete($key); } elsif ( $x->keys > $max_size ) { $x->shift; } $x->set( $key, $value ); } method get ( Str $key) { return unless $x->exists($key); return $x->set( $key, $x->delete($key) ); } }

That's very easy to read and generally leverages familiar syntax. It would also be just enough sugar to easily build upon, but also offers a much nicer core OO syntax than many competing languages. The key for something like that is to keep paring away features to ensure we have the minimal syntax necessary to get it done. For example, don't like the method keyword with the implicit invocant? We could forget about it and just use the existing sub functionality and supply the invocant—$self—manually. No new code to write in the Perl core! We can get there and have a shinier language (maybe even something others would take a look at), but we'd need the smallest proposal possible and fight hard to avoid bike-shedding. Oh, and we'd need it implemented, too :) We know it can be done because there are similar modules on the CPAN. Why not do it?

For comparison, here's that code in Moose:

package Cache::LRU { use Hash::Ordered; use Moose; use MooseX::Types::Common::Numeric qw/PositiveOrZeroInt/; use Carp ‘croak’; use namespace::autoclean; has '_cache' => ( is => 'ro', isa => 'Hash::Ordered', default => sub { Hash::Ordered->new }, ); has 'max_size' => ( is => 'ro', isa => PositiveOrZeroInt, default => 20, ); sub set { croak('…') unless @_ == 3; my ( $self, $key, $value ) = @_; if ( $self->_cache->exists($value) ) { $self->_cache->delete($value); } elsif ( $self->_cache->keys > $self->max_size ) { $self->_cache->shift; } $self->_cache->set( $key, $value ); } sub get { croak('…') unless @_ == 2; my ( $self, $key ) = @_; if ( $self->{cache}->exists($key) ) { my $value = $self->_cache->delete($key); $self->_cache->set($key,$value); return $value; } return; } __PACKAGE__->meta->make_immutable; }


In reply to Recap: The Future of Perl 5 by Ovid

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (4)
As of 2024-03-28 14:38 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found