5 ms·
This was my first thought too. Can anyone elaborate on features Moose has that Ruby doesn't?
by RVuRnvbM2e 12y ago
This was my first thought too. Can anyone elaborate on features Moose has that Ruby doesn't?
- csirac2 12y agoDid 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/#slide27 http://www.houseabsolute.com/presentations/intro-moose-class... vs http://www.houseabsolute.com/presentations/intro-moose-class/#slide28 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.
- RVuRnvbM2e 12y agoDo 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
- csirac2 12y agoSure. 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 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' );
- esaym 12y agoUnless something has changed in Ruby, multiple inheritance would be one. (although some say that is bad, but hey timtoady)
- jeorgun 12y agoI'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.
- csirac2 12y agoThat'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).
- mst 12y agohas 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.