However, Simon Horwith seems to think using
"I think that this is very bad form. I encourage anyone who reads this comment to please not include files inside of your CFCs. It defeats the whole purpose of using components."
In his post, Sean suggests a Mixin implementation in which a mixin() method is used to copy method from a source CFC instance into the current CFC instance. While I do think <cfinclude> has an odor to it, I've though about it all evening, and this approach gives me a "smell" as well. Here's why:
First, I think this method does more than <cfinclude> to "defeat the whole purpose of using components." (I don't think either actually completely defeats the purpose.)
The purpose of a component is to provide a template from which something (an instance) can be, well, instantiated. This something is an Object, capable of containing data and functionality that operates on that instance's data.
However, a Mixin, by itself, has no instance data. In fact, a Mixin, in the Ruby-esque, dynamically-typed-language form that I've encountered them, is a collection of functionality that may use existing instance data, but can't have any of its own.
If there's a way to defeat the purpose of using a component, it's by creating a component that can't, by definition, be what a component is (a collection of functionality and instance data)!
In short, I don't think a Mixin should be something that can be instantiated; it has no instance.
(We could probably argue a bit about Abstract classes and methods a bit here, but that's way outside of the scope of ColdFusion, so can we skip it?)
Second, there's no clean way to make a mixin() method available to classes at large. You'd either need a universal base class (not a good idea), or to take Sean's approach of modifying the web-inf version of component.cfc. That's the base of all CFCs, and is created when ColdFusion is installed. I'm not a big fan of having to modify it, because its creates a customized version of ColdFusion on your machine. That's OK if you can get away with it, but many, such as those creating COTS software, just can't do such things.
Third, the actual implementation of a mixin() method could be problematic. Sean addresses one in his entry: what do you do if the method you're trying to mix already exists? It could be optional to overwrite it, controlled by an argument. (Using <cfinclude> provides a layer of safety, but does limit mixin capability. If you try to redefine an existing function, ColdFusion won't even instantiate the component.) I've also seen someone suggest that the mixin() method provide "safe" namespaces for methods to be copied to (like myMixin_doSomething()).
Further, what about public vs. private Mixins? There are cases where the mixed functionality may be an internal utility - should it always go to both variables and this scopes? How do we control this? With <cfinclude>, there's no new caveats; you can just use the access attribute on the <cffunction> tag.
While <cfinclude> may be more limited in terms of capability, it is existing, stock ColdFusion functionality, not open to multiple implementations, and therefore a standard API that's not likely to change.
<cfinclude> - not without problems
Using <cfinclude> has its own problems. I haven't seen anyone voice my strongest problem with it: the mixin is explicit, done at instantiation, and is therefore fairly rigid and static. If you use it, there's no (good) way to dynamically control what gets mixed at runtime.
However, with mixins, do we *want* people to conditionally mix? That's a situation I'd rather see an IoC container solve (yes, this is a hint to my real point in this post).
It also just "feels" weird. Earlier today, while talking about this over instant messenger, I told Sean that it "feels like kissing your sister." (Please don't get any odd, hillbilly ideas about my gene pool. I'm an only child, and can therefore only use the phrase as a hypothetical simile.)
I'm not happy with any of the current ways to mix in ColdFusion. At the moment, I lean towards <cfinclude> because I feel it's safest (no method overwrites, and lack of mixing capability), follows the KISS principle (no implementation debates), and it doesn't make me use Components that can't be true Objects.
However, I think there's a better solution than either <cfinclude> or mixin(): a third party to govern mixing mechanics. Hi, ColdSpring!
ColdSpring and Mixins
If you read the comments on my first post, you'll see that both Kurt Wiersma and Chris Scott, both involved in the ColdSpring framework, hint that we'll see some sort of Mixin support for ColdSpring. I'd really like to see this, as it'd alleviate some of my concerns:
Those doing things that use IoC and AOP are the most likely to need a Mixin, and ColdSpring could provide a third-party implementation of mixing mechanics that'd both set some rules (method overwrites?) and let you have wide mixing support without modifying ColdFusion itself.
You'd mix only if appropriate, and have an IoC container that could help resolve what you really *want* to mix. If you were mixing in persistence methods, this could probably let you do something along the lines of mixing in database-specific persistence at runtime, overcoming a big problem with <cfinclude> based Mixins.
I don't see any way that ColdSpring could use .cfm files as the Mixin templates, so it'd probably use CFCs. That's a sacrifice I'd be willing to make.