Another Module Idea

Ovid on 2008-07-10T22:33:18

Absent of auto-boxing, I find handling many basic things in classes to be very annoying. Thus, I've toyed with scrapping this sort of ugly code:

package Stuff;

sub new {
    my ( $class, @args ) = @_;
    bless {
        args => \@args,
    } => $class;
}

sub add_args {
    my $self = shift;
    push @{ $self->{args} } => @_;   # UGLY!!!
}

Instead (I know it's a lousy name, but it's just an example):

package Stuff;
use Class::Bits 'aref';

sub new {
    my ( $class, @args ) = @_;
    bless {
        args => aref(@args),
    } => $class;
}

sub add_args {
    my $self = shift;
    $self->{args}->push(@_);   # NOT UGLY!!!
}

Obviously, support for hashes would need to be in there, too (and all requisite methods, including a decent slice syntax). We need Perl 6 now! :(


Not to pimp my own module or anything, but...

mauzo on 2008-07-11T01:48:25

Data::PostfixDeref (also a lame name, but never mind) will allow you to write

sub add_args {
    my $self = shift;
    push $self->{args}[], @_;
}

instead. It has its limitations: there is no slice syntax, because I haven't decided whether $foo->{bar}[][1, 2, 3] is too weird or not yet, and because it's somewhat trickier to implement; and it doesn't allow a direct deref $foo->[] due to the optimizer not getting run on the ops involved.

It doesn't use a source filter, instead it hooks into PL_check[], so it shouldn't suffer from all the 'can't-parse-perl' issues source filters have; nevertheless, I'd still consider it 'alpha'...

list as object

Eric Wilhelm on 2008-07-11T07:23:01

That would be List::oo.

But Class::Accessor::Classy should do what you want without even needing to write the add_args() method.

Re:list as object

Ovid on 2008-07-11T08:09:57

List::oo does look very similar to what I want, except that I want is simply to have all the the ease of use of objects for arrays and hashes (maybe scalars?) without the messiness. Also, by using nicely de-coupled functions to build things, I wouldn't have to "buy into" a particular object system. This would work with Moose as well as with hand-rolled code (which is why Class::Accessor::Classy doesn't seem like the right fit for me).

Re:list as object

Eric Wilhelm on 2008-07-11T16:32:22

"All the ease of use of objects without the messiness"? What's the messy part? List::oo blesses an arrayref, so you're never far from punching through the abstraction. If the constructor is the messy part, then you have L().

Or do you mean cognitive messiness? Abstraction layers do tend to be abstract, and everything's a waterbed, so...

As for object systems - C::A::Classy really isn't much of one. And that is intentional. I'm not sure what the benefit of de-coupling is supposed to be - you get to write more code?

It sounds as if you want all of the features of an object system, without having to say that you're using an object system. Can we just call it a codepole, stick it in the ground, and get on with pitching the real tent?

You need Perl 6 now?

Aristotle on 2008-07-12T04:52:01

You’re saying it’d be easier to port your codebase to Perl 6 than to upgrade your perl to a version that supports autobox? :-)

Re:You need Perl 6 now?

Ovid on 2008-07-12T11:15:39

Except that if I distribute modules, I want to minimize the dependencies. How many times have people failed to install a module because they don't like the the number of dependencies, have an aversion to a particular dependency or can't risk upgrading a particular dependency? The dependency problem is a very real one in Perl 5 and suggesting (admittedly sexy) XS code to solve this problem seems like overkill :)

A very tiny, lightweight embeddable utility would be nice here (yes, there's the risk of duplicate code, but at least I don't screw with other's installations).

Moose

jrockway on 2008-07-13T09:40:37

Ya do know that Moose + MooseX::AttributeHelpers would abstract away all that code you wrote, right?

Boxing is nice, but not really what you need for your example.

Anyway, here's the same code with Moose:


package Stuff;
use Moose;
use MooseX::AttributeHelpers;

has args => (
        is => 'ro',
        isa => 'ArrayRef',
        metaclass => 'Collection::Array',
        auto_deref => 1,
        provides => {
                push => 'add_args',
        },
);

sub BUILDARGS {
          shift; # shift off the invocant
          return { args => \@_ };
}

Then:


    my $foo = Stuff->new(qw/foo bar baz/);
    $foo->add_args(qw/quux gorch/);

    my @args = $foo->args; # foo, bar, baz, quux, gorch

Re:Moose

jrockway on 2008-07-13T09:41:09

BTW, normally I align the => arrows, but use.perl killed the spaces in the <code> block. Yay.

more Moose

hdp on 2008-07-13T14:51:50

package Stuff;
use Moose::Autobox (); # don't actually autobox

sub new {
  my ($class, @args) = @_;
  bless {
    args =>
      # this is the class that autoboxing would use anyway
      bless \@args => 'Moose::Autobox::ARRAY',
  } => $class;
}

sub add_args {
  my $self = shift;
  $self->{args}->push(@_); # NOT UGLY!!!
}

# Likewise, use Moose::Autobox::HASH for hashes.