Hacker News new | comments | show | ask | jobs | submit login
Introduction to Moose, Perl’s OO system (houseabsolute.com)
159 points by lelf on Aug 3, 2014 | hide | past | web | favorite | 52 comments



Moose is a killer library for Perl. I really miss roles when working in other languages. I often feel like I'm fighting the language if I can't split out some common program logic into a separate module and compose it in.

I can get by in C++(using multiple inheritance and the CRTP), and Haskell(with typeclasses).

D has some interesting features - like template mixins - that look promising, but I haven't been gutsy enough to use it for any new project.


I'm glad I'm not the only one! Explaining why I'd possibly miss anything from the Perl world can sometimes be like pulling teeth.


I'm a heavy Rubyist these days, and Moose is one of the very few things I miss from the realm of Perl.

Here's a fun game: the next time someone asks you what technologies you work with or languages you prefer, somehow work in that you like Perl, at least Modern Perl with Moose. Count which one occurs most frequently: people backing away like you've begun frothing at the mouth, people asking if you've ever heard of ANOTHER_TECHNOLOGY (usually Ruby, sometimes Python), and people who assume you're a sysadmin who occasionally scripts something (they'll ask if you've ever used Puppet or Chef).


https://github.com/peczenyj/MooseX may be of interest to you then, there was a reddit post about it a few days ago.

To be honest, as a ruby person, I don't really see what benefits it brings to ruby but maybe I am just missing something.


> Count which one occurs most frequently: people backing away like you've begun frothing at the mouth, people asking if you've ever heard of ANOTHER_TECHNOLOGY (usually Ruby, sometimes Python), and people who assume you're a sysadmin who occasionally scripts something (they'll ask if you've ever used Puppet or Chef).

If you were to 'speak' Perl verbatim, you probably would start frothing at the mouth (from exertion, not from a deadly disease).


Roles seem conceptually similar to Traits in Hack/PHP, right? If so, yeah, they're one of my favourite features, being able to rip out some common code and just do

    use Something\CoolTrait;
inside of a class is just great!


Maybe it's just me, but I've never seen a use for traits. Any time I need to reuse logic across classes, I'll make it a proper class and compose it in as a member.

What sort of functionality do you use traits for?


That's a delegation strategy, which is a very limited form of composition.

A class with a trait/role can be queried for that interface:

  smile() if $my_object->does('SomeTrait');

Methods provided by a trait/role have direct access to $self.

Also, Moose gives you the ability to apply traits to classes that are not predefined with those traits:

  use Moose::Util;
  my $instance = Moose::Util::with_traits('MooseClass', 'MyTrait')->new(%params);

You can parameterize roles (as in, pass parameters that affect what the role provides). If you put some method modifiers into your roles, you can enhance existing functionality; for example, you can add logging, memoization, and persistence, all without the class having those features beforehand.

In other words, roles/traits make your OOP functionality much more composable.


> I'll make it a proper class and compose it in as a member.

You've just implemented traits.


In PHP traits override methods which is something other than being a member object (though you can use traits to do that as well). http://php.net/manual/en/language.oop5.traits.php


I used traits to extract common functionality from POPOs.


They are taking some of it into the core. So maybe that will help people use it more.


The talk is great. For those who do not have the patience, this is the doc of Moose https://metacpan.org/pod/Moose

This is the Moose Cookbook https://metacpan.org/pod/Moose::Cookbook

I think this is pretty much everything you need to start using Moose.


I should point out that these are slides from a full day class where people also do a lot of exercises. You can see the whole thing at https://github.com/moose/intro-to-moose


The JavaScript library Joose was inspired by moose.

http://joose.it


Notice that they are all just libraries, dedicated changes in Perl’s core: 0.


I see that as a feature, honestly; what other languages have an OO system so massively flexible that you can easily build stuff like this on top of it?

Perl's OO system is often derided as "bolted-on", but once you thoroughly understand `bless` and `->`, your imagination is the limit.


> what other languages have an OO system so massively flexible that you can easily build stuff like this on top of it?

Lisp

...sorry I couldn't help myself


Tcl and Python also have (multiple) bolted on OO systems that can be altered at will.


See the Common Lisp Object System (CLOS) and its Meta-Object Protocol (MOP).


Moose is back-ported Perl6 objects, which borrows heavily from CLOS and the concepts introduced in the Smalltalk traits paper. This is a bit of a simplification of the history, but the ancestry is present, documented and obvious.


You are right, but it is on its way to Perl Core. https://github.com/stevan/p5-mop-redux


and as they say "standard lib is where modules go to die"


https://github.com/hernan604/Tutorial-Joose-JS-PT

Joose js tutorial in portuguese =)

Its possible to have all the moose power in javascript


Why not just use Ruby, all of this is already built in?


Really? Because although I came from Ruby (and before that, C, ASM), I spent 4 years in Perl with half of that doing Moose stuff. Now I'm doing Python, C, and hardware stuff.

I really miss Moose. Pythonistas generally can't believe I could possibly miss anything from the Perl world, and usually aren't interested in hearing my reasons why.

But honestly - I miss doing 75% of my work in bashing out an declarative specification with Moose, especially with the type system (as slow as that can be at runtime; the work-around is making objects immutable which leads to cleaner code anyway).

Python does have the traits package by enthought, which has some vaguely similar stuff in it but nobody seems to use it. Being out of the ruby loop for a while, what's ruby's answer to Moose?


For Python, take a look at: https://github.com/frasertweedale/elk


Nice! I've been pointed to this in the past actually, glad to see it's progressed. Trying it out now.


An alternate perspective: I've used Perl for 10+ years, but switched to Python 5 years ago. Moose was a hack to bring Java patterns to Perl, but I feel Java patterns are not developer friendly these days.

Python patterns are still solid today, so I gladly choose doing things the Pythonic way over the Perl way. Not to mention the meta reasons to use a language (community, libraries, ecosystem).


> Moose was a hack to bring Java patterns to Perl

Say what now? Moose draws from most heavily from CLOS and Smalltalk, as filtered through Perl 6. I don't know of any Java influence in Moose at all.


There was a little. Mostly stevan and Yuval going "oh god not that".


I've gone C/C++/Java -> Ruby -> Perl -> Perl+Moose -> Python.

Moose is the opposite of Java: it has a type system which actually does work for you and brings you amazing helpful stuff for free, whereas Java makes you go through rituals and pain to use a type-system that mostly only ever gets in your way.


I'm fine with the idea that you like perl but the way you present your statement, it's almost as if you consider not understanding how to use the java type system as a compelling argument.


That's an interesting observation (that being fine with the idea of someone using modern perl is a thing), but perhaps there's a grain of truth to my level of Java ignorance - the last Java project of my own was written in the 1.4/1.5 days and left me feeling that getting reusable code out of huge towers of inheritance and interfaces seemed like more work than it should be.


You might want to remember that moose came out in late 2005. Back then I remember plenty of blog posts titled similar to "You did what with Rudy!?" (typically an attack on ruby's general slowness and the strange things people were doing with the rails framework... errm twitter <cough>)


Apparently enough of it wasn't built in that someone went ahead and created a Moose for Ruby[1]. I haven't done a lot of Ruby but I imagine it's nice as a day to day language. I enjoy Objective C's message passing syntax and dynamic runtime so Ruby is likely a good fit for me.

Personally the reason to use Perl over Ruby is the community. I gel a lot better with the members of the Perl community I've met compared to when I was poking my head around Ruby. I don't mean this in a bad/flamy way. No one was "mean" to me or anything. My brain is just damaged in the Perl kind of way rather than the Ruby kind of way.

Anyways, the actual question shouldn't be why Ruby over Perl, rather it should be "why don't we have Moose (or something like it) in every language." There's nothing about it that ties it to Perl. A dynamic runtime isn't a bad thing to have but I can't really see why most of the really nice parts couldn't be implemented in other languages at compile time.

Simply put, Moose is awesome. You can build so much functionality with not a lot of code and it actually glues together well. Type coercions are awesome and super useful in day to day programming. I've been doing a lot of API work where I need flexibility in terms of output (JSON, XML, RSS, etc) where a plain object dump to the specified format isn't enough. In the case of the XML there is an XSD it needs to match against and the structure isn't particularly amicable to sane JSON output.

Care of Roles, Type coercions, Attribute meta roles, and some preemptive thinking I basically just create objects with attributes and a few methods containing business logic and not a lick of serializer logic.

  package My::Foo;

  use MyCo::Moose; #Exports a few things I usually need like aliasing,
  use My::Type::Exports qw(:all);

  with 'My::Role::AwesomeSerializer';

  has 'some_attribute' => (
    is          => 'ro',
    isa         => MaybeSuperComplexObjectType,
    coerce      => 1,
    traits      => ['UseMyJsonSerializer'],
    json_name   => 'someAttribute',
    xml_name    => 'My::SomeAttribute',
    alias       => 'some_call_it_this', 
  );

  # yatta

  __PACKAGE__->meta->make_immutable();

  1;
In my types package I have various coerce methods that accept different data formats. The logic in the class doesn't have to change, nor do I need to write a new constructor/factory like I would in other languages, when the data I'm being given changes in some non-trivial way.

[1] http://pacman.blog.br/blog/2014/02/07/moosex-a-new-ruby-dsl-...


Ruby has maybe half of this built in, at best.


Perl is much faster than Ruby, and has a far, far better debugger. Also, CPAN libraries tend to be quite stable; you usually don't need hacks like Bundler to isolate incompatible libraries.


Check out this exchange here on HN a couple months ago following the comment "I have two programming tattoos: a Perl camel and a Ruby ruby": https://news.ycombinator.com/item?id=7866845


This was my first thought too. Can anyone elaborate on features Moose has that Ruby doesn't?


Did you read the linked article? It's not the prettiest intro I've ever seen, but for perl users its benefits can be seen on http://www.houseabsolute.com/presentations/intro-moose-class... vs http://www.houseabsolute.com/presentations/intro-moose-class...

Ruby code wouldn't be as verbose as this, but still once you're used to building classes with Moose accessors, types, traits etc. in a mostly declarative manner, going back to hand-rolling checks and exceptions on bad attribute values, not to mention accessor methods and so on definitely feels like a step backwards.

In fact now that I'm doing a lot of Python these days I've come to the horrible realization that it's Moose which has made me yearn for a language with stronger emphasis on typing and correctness than Python can provide!

    Edit: and I don't mean "like java", where it only ever seems to get in your way...
    Moose does useful things and gives you stuff "for free" once you've told it what
    type something should be. And allows you trivially inherit/override type
    declarations, rather than jumping through hoops as in Java.
It's a full about-face compared to the liberation I felt going from C/C++/Java to Ruby back around 2006-2007.

Slowly working through Learn you a Haskell, but doubt I'll get a chance to use Haskell professionally.


Do you mean the optional type enforcement? Admittedly it's not built-in to ruby, but it's easy to replicate.. and a lot less verbose:

  # Implementation:
  
  module TypedAttrs
      def attr_accessor_type name, type
          define_method name do
              instance_variable_get "@#{name}"
          end
          define_method "#{name}=" do |value|
              raise ArgumentError unless value.is_a? type
              instance_variable_set "@#{name}", value
          end
      end
  end
  
  # Example:
  
  class Foo
      extend TypedAttrs
      attr_accessor_type :bar, Integer
  end
  
  a = Foo.new
  
  a.bar = 5
  p a.bar
  a.bar = "hi" # ArgumentError


Sure. And just for attributes, there's also delegation, read-only attributes, builders, lazy init, roles, modifiers which are enforced at construction time (if `required` is true).

Moose isn't hard to implement, it's actually had quite a few alternate implementations even in Perl. Python has enthought's traits package, and I've just been pointed to https://github.com/frasertweedale/elk as well.

BTW it sucks to nit-pick, but the Moose version isn't any more verbose than yours:

    package Foo;
    use Moose;
    has 'bar' => ( isa => 'Integer' );


    has foo => (is => 'rw', required => 1);
    has bar => (is => 'ro', lazy => 1, builder => '_build_bar');
sets up both accessors and the relevant constructor logic - and bar's accessor will call the _build_bar method on self to get the value if it wasn't provided to the constructor.

Method modifiers (before/after/around) are way more elegant than rename-the-method, and compose nicely from roles - and roles are substantially more powerful than mixins.


Unless something has changed in Ruby, multiple inheritance would be one. (although some say that is bad, but hey timtoady)


I've never used Moose, but in my limited experience, most of the cases where multiple inheritance is useful seem to be ones that basically amount to Ruby's modules/mixins system¹. Are there any examples of useful patterns that aren't covered by that?

¹in fact, under the hood, Ruby modules are classes, and mixins are multiple inheritance— it's an artificial, deliberate limitation.


That's true, when I saw Moose roles I immediately thought of Ruby's mixins. They're a little more expressive though; Moose gives you ways to interrogate roles and classes that use them in more meaningful ways (IMHO), and it's not uncommon for roles to use method modifiers (thus making roles co-exist more easily) rather than clobbering methods outright.

This is all achievable in Ruby of course, the Moose docs sort of codify it and provide sugar to make these patterns the path of least resistance.

Most cases of multiple inheritence I've seen is in non-Moose Perl code, where it's being used a little like a mixin. DBI classes and code making lots of use of meta-programming (Class::MOP stuff).


Great presentation. I have not used Moose much, but I have started using a lighter weight version of it called Moo.


¿it's hard to put a next/previous button?


Yeah, don't accidentally hit the back button to go to the previous page. There's no history, so you'll end up here and you'll have to start over.


bottom right if you have js enabled...


If you have js disabled, you get the whole thing as a normal document with a scrollbar.




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: