Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Python OO v Moose

by Ea (Friar)
on Feb 06, 2013 at 11:23 UTC ( #1017386=perlmeditation: print w/ replies, xml ) Need Help??

With all the hype being thrown about Python v Perl and my own baby steps into Moose, I thought I'd have a quick look at how the other side does it and found both quite comparable. Not knowing any Python, I grabbed some code from a tutorial page and tried to implement the same 2 attribute, 1 method class in Moose.
Python
class OurClass(object): """Class docstring.""" def __init__(self, arg1, arg2): """Method docstring.""" self.arg1 = arg1 self.arg2 = arg2 def printargs(self): """Method docstring.""" print self.arg1 print self.arg2
Perl
package OurClass; use Moose; has ‘arg1’ => ( is => ‘rw’ ); has ‘arg2’ => ( is => ‘rw’ ); sub printargs { my $self = shift; say $self->arg1; say $self->arg2; } no Moose;
For those who like their statistics simplistic:
  • Python (29 words, 190 chars)
  • Perl (25 words, 142 chars)

    Rather than seeking approval from any self-appointed echo chamber, I'm wondering if there are any here with the Python chops to tell me that I've created a straw man (like missing out the call to __PACKAGE__->meta->make_immutable;) or that there's a Python feature specific to OO that they really wish was in Moose or implemented more naturally.

    I'm not trying to get anyone's back up, just meditating on how to make the comparison fair.

    best,

    Sometimes I can think of 6 impossible LDAP attributes before breakfast.
  • Comment on Python OO v Moose
    Select or Download Code
    Re: Python OO v Moose
    by choroba (Abbot) on Feb 06, 2013 at 11:34 UTC
      There should be some =pod in the Perl code to pair with the docstrings. Also, use ASCII single quotes ' (or nothing before the fat comma):
      package OurClass; =pod =cut use Moose; has arg1 => (is => 'rw'); has arg2 => (is => 'rw'); sub printargs { my $self = shift; say $self->$_ for qw/arg1 arg2/; } no Moose;
      لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
        The single quote strangeness was due to a copy/paste from GoogleDocs. I'll have to keep that in mind when using that to share code. The """ is starting to make more sense now. I'm not sure if I have any preferences for documentation style yet. I like POD for the space it gives the text, except when I don't want to look at it, especially since I tend to prefer keeping the documentation near the methods. Javadoc is easily hidden in Eclipse, but I'm a little put off by its differentness. I haven't seen a style that really grabs me so far.

        I was in two minds in the printargs method. It looks better the way you've written it. I was trying to keep it simple so that people with no knowledge of Perl could see how it works, but I do like the for line. Likewise, I'd used lots of whitespace in the attribute distributions to make it 'friendlier'.

        Sometimes I can think of 6 impossible LDAP attributes before breakfast.

          I used to intersperse my pod and code, but eventually grew to dislike that, so now place all my pod at the end of the file.

          Yes, there's something to be said for keeping documentation and code close together, but having them in the same file is close enough for me. Putting all the pod at the end I think encourages me to write documentation that flows better as a document - making the pod less a list of methods, and more a how-to.

          package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
    Re: Python OO v Moose v Badger
    by Anonymous Monk on Feb 06, 2013 at 13:05 UTC

      You're not really saying anything :) but then neither am I

      1

      package OurClass; use Badger::Class base => 'Badger::Base', mutators => 'arg1 arg2', config => 'arg1 arg2', init_method => 'configure', methods => { printargs => sub { my $self = shift; print $self->arg1, "\n", $self->arg2, "\n"; } }, ;;;;

      2

      package OurClass; use parent 'Badger::Base'; sub init { my ($self, $config) = @_; $self->{ arg1 } = $config->{ arg1 }; $self->{ arg2 } = $config->{ arg2 }; return $self; } sub arg1 { @_==2 and $_[0]->{arg1}=$_[1]; $_[0]->{ arg1 } } sub arg2 { @_==2 and $_[0]->{arg2}=$_[1]; $_[0]->{ arg2 } } sub printargs { my $self = shift; print $self->arg1, "\n", $self->arg2, "\n"; }

      3

      $ wc OurClass.pm 11 32 271 OurClass.pm
      package OurClass; use Badger::Class base => 'Badger::Base', mutators => 'arg1 arg2', config => 'arg1 arg2', init_method => 'configure', ;;;; sub printargs { my $self = shift; print $self->arg1, "\n", $self->arg2, "\n"; }
    Re: Python OO v Moose
    by tobyink (Abbot) on Feb 06, 2013 at 13:19 UTC

      "there's a Python feature specific to OO that they really wish was in Moose"

      I'd say the Moose OO model is far more powerful and useful than Python's. Roles, method modifiers, lazy builders, delegation and coercion are all really good for reducing repetitive code and improving OO design. With enough work most of that can be emulated in Python, but Moose gives it to you straight out of the box.

      By the way; don't know if you're aware, but you can do this in Moose:

      has [qw(arg1 arg2)] => (is => "rw");

      Or of course:

      has $_ => (is => "rw") for qw(arg1 arg2);

      Also I'll offer a MooX::Struct example for your class. MooX::Struct is a compact builder for simple classes that mainly consist of attributes (not methods). It uses Moo which offers an easy upgrade path to Moose.

      use v5.12; use MooX::Struct OurClass => [ qw( $arg1 $arg2 ), TO_STRING => sub { join "\n", @{+shift} }, ]; my $object = OurClass["Hello", "World"]; say $object;
      package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
        That's a little more compact than I was hoping for to show to non-Perl people, but I may start using it myself. <quote>Also I'll offer a MooX::Struct example for your class. MooX::Struct is a compact builder for simple classes that mainly consist of attributes (not methods).</quote> I was looking for this just last week, but I wanted one of the attributes to be a unique list, so there was a bit of overhead in writing the accessors.
        has 'name' => ( is => 'rw', isa => 'Str', required => 1 ); has 'members' => ( is => 'rw', isa => 'HashRef', default => sub{ {} }, ); sub add_members { my ($self, @members) = @_; $self->members()->{$_}++ for (@members); # no duplicates in list } sub list_members { my $self = shift; return keys %{$self->members()}; }
        I use it to create a group with a name and then add members to the list as I pick them out of a database. When I'm finished in the database, I go through all the groups and dump the members list. How would you do that in MooX::Struct and would it be able to modify the members list after instantiation?

        Sometimes I can think of 6 impossible LDAP attributes before breakfast.

          By default, all attributes in MooX::Struct are read-only, but it's easy to make them read-write...

          use MooX::Struct -rw, Person => [qw( $name @addresses )];

          For your members example, Moose's native traits would probably be helpful. Moo doesn't currently offer anything similar to this, but there is somebody developing such a beast - I believe it will be on CPAN soonish. I'd probably do something along these lines...

          use v5.14; package Person { use Moose; use overload q[""] => sub { $_[0]->name }, fallback => 1; has name => ( is => 'ro', isa => 'Str', required => 1, ); } package Club { use Moose; use overload q[""] => sub { $_[0]->name }, fallback => 1; has name => ( is => 'ro', isa => 'Str', required => 1, ); # This is a private attribute. We want people to only # manipulate the member list via add_members, etc. has _members => ( traits => ['Array'], is => 'ro', isa => 'ArrayRef[Person]', init_arg => undef, default => sub { [] }, handles => { add_members => 'push', has_members => 'count', list_members => 'elements', _uniq_members => 'uniq', }, ); # ensure uniqueness after add_members => sub { my $self = shift; @{ $self->_members } = $self->_uniq_members; }; } my $club = Club->new(name => "The Breakfast Club"); $club->add_members( Person->new(name => "Allison"), Person->new(name => "Andy"), Person->new(name => "Brian"), Person->new(name => "Brian"), # duplicate ); $club->add_members( Person->new(name => "Andy"), # duplicate Person->new(name => "Claire"), Person->new(name => "John"), ); say for $club->list_members;
          package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
    Re: Python OO v Moose
    by sundialsvc4 (Monsignor) on Feb 12, 2013 at 19:42 UTC

      (Shrug...)   The tools are different, that’s all.   Remember also that Moose is designed to provide a pragmatically acceptable object-oriented context with regard to a language (Perl) that does not intrinsically have one, whereas the Python features that you describe are native to the (current versions of the) language.   Both languages are great.   I use both of them all the time.

      But this is apples vs. oranges.   The only directly-comparable relationship that I can think of would be to “the not-here-yet language commonly known as Perl 6.”   As things stand here, Moose is doing as well as it can ... which is, pretty well.

    Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Node Status?
    node history
    Node Type: perlmeditation [id://1017386]
    Approved by Corion
    help
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others pondering the Monastery: (10)
    As of 2014-09-02 17:01 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      My favorite cookbook is:










      Results (25 votes), past polls