Mixins, But With Tablespoons #
Mauricio’s at it again. I solemnly swear that I will be linking to him greater than five times over this next month and each time you will be fine with it. See, watch how fine you’ll feel when you read about his remake of Module#include
.
The include
method is basically the mixin method in Ruby. You have a class that has its own each
method. You mixin the Enumerable
module and you get all these neat methods for free like inject
and select
and sort_by
and on and on.
class MyList include Enumerable def each; ... end end
What if you don’t want the sort
method, though? You want to deposit only granular measurements of a mixin. This is what Mauricio tackles. And his new include
goes like this:
class MyList include Enumerable, :exclude => :sort_by, :alias => {:detect, :siphon} end
All part of a LazyWeb query from Dan. And Mauricio’s code is only 17 lines long, very easy to peruse.
lukfugl
I like it, but I’ll make the same comment I was going to make on Dan’s journal (didn’t because Dan has comments off for non LJers):
I’d prefer a syntax that looks like this:
In other words, suck the tail of the argument list into a hash. For each method that would be included, look in that hash. If the key is there but with a value of nil, exclude that method. If the key is there with a non-nil value, include it under the alias.
To me, such a syntax would be much cleaner and unified…
lukfugl
And here’s the implementation for the alternate syntax proposed above (shamelessly tweaked from Mauricio’s code, not tested):
trans
This notation isn’t so good either for Nitro and Og which uses dynamic modules. Hash parameters on #include can alter the behavior of the module via these include options.
Like I said on Mauricio site, Facets goes about it in slightly more Rubyeque way—a block is used with a mini-DSL to alter the new module. I named the method #integrate, instead of resusing #include, but it could be applied to #include just as well.
trans
Maybe I should give and example here too:
The internal part of the block is nothin special, its just be class_evaled on the new module—I’ve just created a few new useful method for this context. You could even define a new “one-time” method in it.
mfp
wow, that’s quite some pressure you’re putting on me, _why… 5+ worthy blog entries is a lot :)
Daniel Berger
Hm, I kinda like both lukfugl’s and trans’ ideas.
/me ponders
Sam
Haskell’s type classes are a really snazzy way of doing this… The syntax could be emulated by ruby syntax trivially I imagine.
crzwdjk
But can this be used to implement perl6-style roles? Because that would be a neat thing to have in ruby.
why
Definitely. Both permutations above are excellent! Very well shown.
gmosx
Tran’s permutation is great (an added plus: it integrates nicely with the dynamic mixins used in Nitro/Og ;-))
Dave Burt
Can I just say, I don’t like the syntax the alias parameter is given in.
{:detect, :siphon}
prefers to be{:detect => :siphon}
. 1) It looks less similar toalias detect siphon
(which would imply the reverse alias) and 2) it is less easily confused with an array or block or anything other than the hash it is.Daniel Berger
crzwdjk, if you happen to read my journal, my original idea was inspired by Curtis Poe’s Class::Trait Perl module.
While this solution wouldn’t match the trait spec completely (i.e. the Schaerli paper), it does deal with composition, which is the only part of traits I think we need for Ruby.
Also, see David Naseby’s blog entry (from a while back) on a theoretical implementation of traits here. It was that blog entry that I based the “interface” package on.
riffraff
Can I ask for matz’ proposed syntax?
I admit I love it when I see math operator overriding.
trans
Traits Algebra? Hmm… then why not:
(Note: If the second plus didn’t show it’s _why’s fault!)
Still, that might be a little too terse, though it certainly seems very cool on first sight.
strayneuron
I love trans’ (non-algebraic) iteration
+1
Daniel Berger
riffraff, ick.
MenTaLguY
Hmm, the thing I’d like more than anything else would be the ability to only include those bits which I explicitly request.
I mean, okay, so you can explicitly something which would conflict today—but what if the module adds a conflicting method in the future?
That’s one thing that’s bothered me about Ruby for a long time. When everything’s the equivalent of a Java-ish star-import (e.g.
import com.blah.*
), you live dangerous-like.kig
So maybe
But that is going to break things if the module’s methods depend on now-non-existing methods.
kig
Module arithmetics implementation (was going to post here but it got a bit long)
Daniel Berger
kig
It’s like array set operation notation. Is the following more readable?
Comments are closed for this entry.