I was working on a little app of mine over the weekend that uses a
closed-source (encrypted) CFC for some of it's functionality. The
CFC (which will go unnamed to protect the innocent), does a number of
things, but it's functionality wasn't quite "complete" enough for my
application, so I extended it to add a couple more features. No
problem, until I started having this really weird error about an
invalid method return type for a private method that I didn't even know
existed.
After a quick dump of the 'variables' scope, I
discovered the problem was nothing more than a variable
collision. One of the instance variable from the encrypted CFC
happened to be the same as what I wanted to call one of the methods I
was adding. Needless to say, I was a little bothered by this; now
my method wouldn't be able to conform to same naming conventions as the
rest of the CFC's methods. However, being the [relatively] mature
adult that I am, I quickly got over it, did a quick search and replace, and went on with my business.
The reason I'm writing is that I want to restate the point that you should never put anything
directly into the 'variables' scope in a CFC except public data fields
that are clearly documented with CFPROPERTY. Instance variables
should always go into a substruct (I prefer 'my', but 'instance' seems
to be a more common name), both to keep them nicely packaged, and to
avoid this kind of variable collision. This is particularly
important if you're going to be distributing your CFCs for other
developers to use and possibly extend.
Hey Barney,
I'm not sure I 100% agree.
While I agree that it's definitely a best practice to put instance data into a specific "scope", such as variables.instance, there are times when a component has members that aren't necessarily parts of its instance or state. I've both put these directly into variables and put them in another 'special' scope.
Yeah, I do the same thing. ;) It's "slidable" if you're the sole user of your component, because you control both sides, and can manipulate either one to rectify any collisions. But if you're distributing your code, that's no longer the case, so you have to be extra careful to not give your end users trouble.
"you should never put anything directly into the 'variables' scope in a CFC except public data fields that are clearly documented with CFPROPERTY"
I totally disagree with that. First off, 'variables' scope is protected, not public. Using CFPROPERTY to document non-public data is also very misleading. CFPROPERTY is supposed to be used for public data fields in a CFC that acts as a return type in a web service. That's it.
What I would suggest is that if you are writing a CFC that you expect people to extend, you need to think very carefully about what you put in the (protected) 'variables' scope since it will be visible to any CFCs that extend yours.
Using variables.my.* or variables.instance.* is a good idea since it will separate the data space form the function space.
Whoops. You're correct, of course, Sean. CFPROPERTY should be used to document variables in the 'this' scope. I was completely off base on that one, and can offer no excuse other than I might have been tired.