From: Peter Vanbroekhoven Date: 2005-10-22T03:07:08+09:00 Subject: Re: [RCR] Cut-based AOP On Fri, 21 Oct 2005, Eric Mahurin wrote: > One more thing. This RCR introduces a new reserved word to the > language: "cut". This will break any code already using "cut" > as a variable or method name (and calling it with no receiver). > An additional reserved word should not be introduced to the > language unless you really need it. So far, you haven't > demonstrated that a "cut" really provides anything else useful > over what you could do with the #preclude part of your RCR. > #preclude would just be another method so it shouldn't cause > compatibility issues like "cut". The syntax of cuts parallels that of subclassing, preclude parallels module inclusion. I think these are two valid views, and none is less intuitive than the other because it borrows its syntax from another concept in the language. So I think the discussion comes down to this: is it more class-like, or more module-like? In our opinion (I speak only for myself, but I'll say our nonetheless) it is more class-like. The reason is that this object with the wrapper methods extends a given class. It does so like a subclass extends a class. And just like a subclass, that wrapper thing inherits the interface of the class it wraps. It's that interface that it needs to work with. In many cases it will have to be taylored to that interface. Especially within AOP. Say I want to build an aspect that notifies me if a bang method is called on a given class. When I apply that aspect to say String, the set of wrapper methods will be different than for say Fixnum. Hence each instantiation of an aspect will often differ in the methods it provides, and maybe even in their definitions. The cut is in a way an instantiation of an aspect. Which does not mean that these cuts can't have common behavior. But that's what modules are for. The behavior that is not reused belongs in a cut, just like with classes. Having these cuts makes some things surprisingly simple (note: this only works with a new version of the patch, which is not yet available because I'm still working on it): class BangCut < Cut def initialize(sup) super sup.instance_methods(true).grep(/!$/) do |sym| add_notifier(sym) end end def cut_method_added(sym) add_notifier(sym) if /!$/ =~ sym.to_s end def add_notifier(sym) module_eval %{ def #{sym}(*args) puts "calling #{sym}" super end } end end cut = BangCut.new(String) class String def scramble! length.times do r1 = rand(length) r2 = rand(length) self[r1], self[r2] = self[r2], self[r1] end self end end p "hello".gsub!(/ll/, 'l') p "Hello world!".scramble! I'm sure you can do this using only precluded modules, but it will be quite a bit more involved. An important part of cuts is also managing them and the methods in them. Maybe you don't see this as important, but it is, especially when doing AOP. Aspects can vary independently from the classes they applies to, and they can even vary from class to class. Thus we need cuts that naturally vary from class to class, and not modules that are about reusing the exact same functionality. Making management of the different layers possible for each class separately is in our opinion important, and that is exactly why we started on this, because for Matz' "def meth:pre ; end" syntax it is hard to do because you can't get a handle on this method itself in a very Rubyesc way. It's an error to postpone this, and first do #preclude and then build a tacked on management system that won't be so Rubyesc. Cuts provide a Rubyesc management system for the wrapper methods for a specific class. Don't get me wrong though, I'm not opposed to having a #preclude method too. But IMO the cut concept needs to live as well. Peter