Exploring Mixins And ColdFusion Components

Posted April 1, 2009 at 2:31 PM by Ben Nadel

Tags: ColdFusion

I am not sure what the exact, technical definition of a "Mixin" is; but, from what I understand, a "mixin" is generically meant to define a scenario in which an object is composed of functionality that was not originally defined within it. This can be done either at compile time through includes or at runtime through method injection or includes. Earlier today, someone asked me about some mixin behavior and I didn't have an existing blog post to point them to. As such, I figured I would take lunch to throw together a few examples.

To start off with, let's create two ColdFusion templates, each of which contains a user defined function. The first one, public_udf.cfm, will define a method with "public" access:

  • <cffunction
  • name="PublicFunction"
  • access="public"
  • returntype="string"
  • output="false"
  • hint="I am public function that was declared OUTSIDE of a component.">
  •  
  • <cfreturn "I am a public function." />
  • </cffunction>

The second one, private_udf.cfm, will define a method with "private" access:

  • <cffunction
  • name="PrivateFunction"
  • access="private"
  • returntype="string"
  • output="false"
  • hint="I am private function that was declared OUTSIDE of a component.">
  •  
  • <cfreturn "I am a private function." />
  • </cffunction>

Now that we have these methods in place, let's use them in a standard page. We're going to include them as we would any standard user defined function (UDF) and then invoke them:

  • <!--- Include the UDFs. --->
  • <cfinclude template="public_udf.cfm" />
  • <cfinclude template="private_udf.cfm" />
  •  
  • <!--- Call the methods in the page scope. --->
  • <cfoutput>
  • #VARIABLES.PublicFunction()#<br />
  • #VARIABLES.PrivateFunction()#<br />
  • </cfoutput>

When we run this, we get the expected output:

I am a public function.
I am a private function.

I am demonstrating this more to show that the concept of Public / Private methods don't really have a meaning outside of components. Technically, I believe components and templates are executed in similar methods in that they are each a page with its own context, so technically, I guess you could think of a page's VARIABLES scope as being tantamount to the private scope of a component. But, as a standard page doesn't have a public scope, the demo is rather moot.

OK, let's get onto the more exciting stuff - mixing these UDFs into a component.

The first thing I want to try is mixing them in at compile time of the component. By that, I mean we are going to execute the CFInclude in the pseudo constructor of the CFC (the area within the CFComponent tags but outside the CFFunction tags):

  • <cfcomponent
  • output="false"
  • hint="I am a component whose methods are created via Mixin methodology.">
  •  
  • <!--- Include the mixin UDFs in the pseudo-constructor. --->
  • <cfinclude template="public_udf.cfm" />
  • <cfinclude template="private_udf.cfm" />
  •  
  •  
  • <cffunction
  • name="Init"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I return an initialized object.">
  •  
  • <!--- Return THIS reference. --->
  • <cfreturn THIS />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="GetVariables"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I return the private scope of this component.">
  •  
  • <cfreturn VARIABLES />
  • </cffunction>
  •  
  • </cfcomponent>

You can see in this code (and subsequent demos) that the Mixin.cfc (our test component) has an Init() method and a GetVariables() method that can return the private scope for debugging. You can also see that I am including our two UDFs at compile time when the component is being instantiated.

Now, let's test this component to see how it behaves:

  • <!--- Create the Mixin component. --->
  • <cfset objMixin = New( "Mixin" ).Init() />
  •  
  • <!--- Output the public scope (THIS). --->
  • <cfdump
  • var="#objMixin#"
  • label="Mixin PUBLIC Scope."
  • />
  •  
  • <br />
  •  
  • <!--- Output the private scope (VARIABLES). --->
  • <cfdump
  • var="#objMixin.GetVariables()#"
  • label="Mixin PRIVATE Scope."
  • />

When we instantiate the Mixin.cfc component and output it's public and private scopes, we get the following CFDump output:


 
 
 

 
ColdFusion Mixin Demo - Pseudo Constructor.  
 
 
 

As you can see, when we include the UDF mixins at compile time, the public and private properties of the user define methods are carried through such that our public method is available in our public THIS scope and our private method is available in our private VARIABLES scope. You'll also notice that the public methods are available in the private scope as well.

Ok, now let's try to include the UDF mixins at runtime from within the component's Init() method:

  • <cfcomponent
  • output="false"
  • hint="I am a component whose methods are created via Mixin methodology.">
  •  
  • <cffunction
  • name="Init"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I return an initialized object.">
  •  
  • <!--- Include the mixin UDFs in explicit constructor. --->
  • <cfinclude template="public_udf.cfm" />
  • <cfinclude template="private_udf.cfm" />
  •  
  • <!--- Return THIS reference. --->
  • <cfreturn THIS />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="GetVariables"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I return the private scope of this component.">
  •  
  • <cfreturn VARIABLES />
  • </cffunction>
  •  
  • </cfcomponent>

As you can see, all we've done is moved the CFInclude tags from the pseudo constructor to the explicit constructor (Init()). Now, when we run the same test as above, we get the following CFDump output:


 
 
 

 
ColdFusion Mixin Demo - Explicit Constructor (Init() Method).  
 
 
 

As you can see, when we include the UDF mixins at runtime from within a CFC method, the methods end up in the CFC's private scope regardless of what their compile time access properties are.

Now, if we want to use this methodology but we want proper scoping, we can manually copy the public method to the public scope. To do this, after the UDFs are included, we need to explicitly copy the public one from the private scope to the public scope:

  • <cfcomponent
  • output="false"
  • hint="I am a component whose methods are created via Mixin methodology.">
  •  
  • <cffunction
  • name="Init"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I return an initialized object.">
  •  
  • <!--- Include the mixin UDFs in explicit constructor. --->
  • <cfinclude template="public_udf.cfm" />
  • <cfinclude template="private_udf.cfm" />
  •  
  • <!---
  • The UDFs we just included are in the PRIVATE scope.
  • If we want any of them to be public, we need to copy
  • them to THIS explicitly.
  • --->
  • <cfset THIS.PublicFunction = VARIABLES.PublicFunction />
  •  
  • <!--- Return THIS reference. --->
  • <cfreturn THIS />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="GetVariables"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I return the private scope of this component.">
  •  
  • <cfreturn VARIABLES />
  • </cffunction>
  •  
  • </cfcomponent>

Now, with our copy line in place:

  • <cfset THIS.PublicFunction = VARIABLES.PublicFunction />

... when we run the above test, we get the following CFDump output:


 
 
 

 
ColdFusion Mixin Demo - Explicit Construct (Init() Method) With Copy To THIS Scope.  
 
 
 

As you can see, both methods ended up in the private scope as before, but now, our PublicFunction() has been copied manually to the THIS scope and is publicly accessible.

After includes, there is really only one other kind of mixin that I can think of and that is to inject a method into a component at run time. In the following demo, the Mixin.cfc is not going to do any of the including; rather, the instantiating pages is going to manually copy our functions references into the existing CFC instance. Here is our updated CFC:

  • <cfcomponent
  • output="false"
  • hint="I am a component whose methods are created via Mixin methodology.">
  •  
  • <cffunction
  • name="Init"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I return an initialized object.">
  •  
  • <!--- Return THIS reference. --->
  • <cfreturn THIS />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="GetVariables"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I return the private scope of this component.">
  •  
  • <cfreturn VARIABLES />
  • </cffunction>
  •  
  • </cfcomponent>

And, in this demo, we are going to copy the UDFs from the page scope to the public scope of the instantiated CFC:

  • <!--- Include the UDFs into the page scope. --->
  • <cfinclude template="public_udf.cfm" />
  • <cfinclude template="private_udf.cfm" />
  •  
  • <!--- Create the Mixin component. --->
  • <cfset objMixin = New( "Mixin" ).Init() />
  •  
  •  
  • <!--- Store our page-scope UDFs into the component. --->
  • <cfset objMixin.PublicFunction = VARIABLES.PublicFunction />
  • <cfset objMixin.PrivateFunction = VARIABLES.PrivateFunction />
  •  
  •  
  • <!--- Output the public scope (THIS). --->
  • <cfdump
  • var="#objMixin#"
  • label="Mixin PUBLIC Scope."
  • />
  •  
  • <br />
  •  
  • <!--- Output the private scope (VARIABLES). --->
  • <cfdump
  • var="#objMixin.GetVariables()#"
  • label="Mixin PRIVATE Scope."
  • />

With this technique, when we run the above code, we get the following CFDump output:


 
 
 

 
ColdFusion Mixin Demo - Runtime Method Injection.  
 
 
 

As you can see, this time, both our UDFs are available in the public scope; but, unlike the CFInclude-based mixins (or actual pre-defined CFC methods), the private scope has no reference to these methods at all.

You can also inject methods into the private scope using a method injection proxy. In that kind of scenario, you would pass the method reference to a public method that would turn around and inject the given method into the VARIABLES scope. It achieves the same thing, only with a different target scope. Heck, you can even inject the method proxy that takes care of the variables injection.

Once a method is mixed into a CFC, it has access to all the same methods and properties that any pre-defined method would have. As far as ColdFusion is concerned, a mixin is exactly the same as a standard component method. This brings us to one final topic of discussion and that is method binding. When a UDF is used outside of a component and then called, the method is bound to the context of the calling page. By that, I mean that if you define a UDF in template A and then invoke it in template B, the UDF executes as if it were defined in template B (its calling context).

Once you copy a method into a CFC, however, the rules change. A method reference copied to a CFC is bound to the that CFC. And, when that method is invoked on that component, it uses the CFC as the context rather than that of the calling page. Of course, this only works if you call the method ON the component. If you were to copy the method reference out of the CFC and back into the page, the method take on the pervious behavior (bound to calling page context).

So there you go. I hope this sheds some light on mixin behaviors for anyone who was unclear as to what they were or how they worked.




Reader Comments

Apr 1, 2009 at 3:51 PM // reply »
67 Comments

Well summarized, sir.


Apr 1, 2009 at 3:52 PM // reply »
67 Comments

(Now compare and contrast with prototypal inheritance in JS. ;-)


Apr 1, 2009 at 4:27 PM // reply »
11,238 Comments

@Rick,

Oh man. To be honest, I am not even sure HOW Javascript methods work when injected into object instances. I don't think I've ever tried that before.

I guess it's the same as passing a fn pointer as a callback. Javascript methods are lexically (spelling?) bound, so I assume injecting them won't make a difference. Of course the "this" keywords is dynamically bound....

Oh man, my head hurts. Damn you Rick!


Apr 1, 2009 at 4:34 PM // reply »
47 Comments

Thank you for the post, very well written and explained!


Apr 1, 2009 at 5:17 PM // reply »
20 Comments

I'm shocked that you can cfinclude a page that's just a function. I thought it would throw some sort of nesting error for having a function in a function.


Apr 1, 2009 at 6:32 PM // reply »
11,238 Comments

@Anthony,

Yeah, it's a bit odd, right? Including a function inside a function.


Apr 2, 2009 at 12:07 AM // reply »
149 Comments

Great examination! Very informative. The biggest surprises to me were that you can even use a cfinclude in the pseudo constructor of a cfc (!!?!?) That seems nutty.

Now what I'd like to see are reasons you'd use any of the mixin techniques described here with ColdFusion.

Are there valid reasons for ever authoring standalone UDFs and then including them on a page?

I've always aggregated all of the utility UDFs I need into a single CFC that injects them into the application scope onApplicationStart.

Then I can call them ( or inspect them ) anywhere as application.util.function() and never have to worry about managing them.

Great post.


Apr 2, 2009 at 6:03 AM // reply »
33 Comments

Good post. Sean Corfield posted about mixins a while ago and there's some interesting banter in the comments here: http://corfield.org/blog/index.cfm/do/blog.entry/entry/Mixins

I have to say I think mixins are a horrible 'pattern'. If you use them in even a medium scale project you can run into debugging and maintenance nightmares as you can get errors thrown from code which doesn't exist except at runtime. Debugging hell!

Between dependency injection via Coldspring and the cfinterface tag I really can't think of a reason to use mixins these days.


Apr 2, 2009 at 8:22 AM // reply »
2 Comments

there is so much information in this article it really helped me during my study.


Apr 2, 2009 at 8:27 AM // reply »
11,238 Comments

@David, @George,

I agree, I don't really use this technique very much. I used it a few times with dependency injection, but I have since gone other routes for such things.

I think Isaac uses something like this in the OnTap framework to lazy load his actual component methods (using OnMissingMethod() to install them only when necessary)... but not sure on that, so I don't want to speak for him.


Apr 2, 2009 at 9:54 AM // reply »
11,238 Comments

@Rick,

Cool behavior in Javascript:

http://www.bennadel.com/index.cfm?dax=blog:1552.view


Oct 3, 2009 at 1:19 AM // reply »
29 Comments

@ben

Seems like there should be a better way to make modules (OOP, not cfmodule) and mixins.

I mean, in a rubyesque way.

Psuedocode is easier.

comp Math
...func pi
...func sin
...func cos

comp Debug
...func print
...func dump
...func inspect

Use Math as a ruby module. Similar to ruby's require, you have to create a reference to the class. Call methods from the class (class methods). No object is instantiated.

Use Debug as a ruby mixin. Again, you have to create a class reference like ruby's require. Then, you have to copy all the methods to the local scope, similar to ruby include.

cfm App
...Math=createObject(comp, Math) # ruby require
...x=Math.pi()
...x=Math.sin(y)
...x=Math.cos(y)
...Debug=createObject(comp, Debug) # ruby require
...for (method in Debug.methods) { structInsert(variables, method) } # ruby include
...print(x)
...dump(x)
...inspect(x)

This App needn't be a cfm. Could be a cfc or other. You'll have to be careful with a cfc, though, where you do the class reference and method copy. You'll usually be calling the rubyesque module or mixin from runtime code.


Oct 3, 2009 at 1:27 AM // reply »
29 Comments

@ben

Dango!

Just now saw your post about swapping CFC methods at runtime.

I have to keep up with your blog more.


Oct 19, 2009 at 8:54 PM // reply »
28 Comments

Have you tried using mixins in CF9 yet? I'll give you a hint: not what you'd expect...


Oct 31, 2009 at 4:32 PM // reply »
11,238 Comments

@Tony,

I haven't had a chance to try this yet; let me see what happens.


Oct 31, 2009 at 4:40 PM // reply »
11,238 Comments

@Tony,

I just tried a CFInclude-based mixin and it worked fine. What should I be looking for?


Oct 31, 2009 at 4:40 PM // reply »
11,238 Comments

@Tony,

An injected method also seems to work fine.


Oct 31, 2009 at 6:30 PM // reply »
28 Comments

@Ben,

Sorry I should've followed up to my previous comment. When I first tried using mixins in CF9, it didn't appear as if they would work because none of the functions in the mixin appear if you dump the object. However, the functions work as expected.


Oct 31, 2009 at 8:54 PM // reply »
11,238 Comments

@Tony,

No worries my man.


Jun 4, 2011 at 12:07 PM // reply »
63 Comments

Late entry here ... I'm not very confident in my understanding here so FWIW ....

Is the implementation here similar to the functionality provided by creating JavaScript closures? Where declaring a function in the body of another function makes the variables of the outer function publicly available to the inner?

If this makes sense :)


Jun 4, 2011 at 5:55 PM // reply »
11,238 Comments

@Edward,

ColdFusion has announced Closure support in future versions of ColdFusion; but, unfortunately, that is not something we have just yet. Right now, when you invoke a function that is NOT a method on an object, the function executes in the context of the CALLING code, not the defining code. The function's lexical binding is meaningless... in the future, we'll have our closure's though!!! :D



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 20, 2013 at 11:45 AM
Using jQuery's Animate() Step Callback Function To Create Custom Animations
This is really useful. I found out that you don't actually have to use a dummy css property (surprisingly). To animate a property in a linear-gradient for instance I did this this.css('someLinearGra ... read »
May 20, 2013 at 10:51 AM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Josh, Oh snap! You're totally right! I'm not sure I've ever tried that. I did know that you can call a number of other array-methods on ColdFusion query columns: http://www.bennadel.com/blog/167 ... read »
May 20, 2013 at 10:45 AM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Ben - I believe you can achieve the same functionality with ColdFusion's built in ArrayToList() function. ArrayToList( users[ "id" ] ); ... read »
May 20, 2013 at 10:21 AM
My Experience With AngularJS - The Super-heroic JavaScript MVW Framework
Is there any error logging and handling framework in angularjs, if not then in what way I can do this. ... read »
May 19, 2013 at 2:31 PM
My Experience With AngularJS - The Super-heroic JavaScript MVW Framework
It's funny really just how well that image describes the way I would imagine most people that go with angular for some project is. I have had a similar roller-coaster ride with it as well, but not qu ... read »
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools