To Type or Not to Type - The Big Question

Newbie Cafe

I thought i'd follow up on the post about polymorphism with a more down to earth post about typing in ColdFusion, because 90% of that post turned out to be about typing anyway. And believe it or not, there's still more to say on the topic.

Once you get to know your way around a little, one of the most confusing things for a CF developer who is new to OO is whether or not to explicitly type your arguments and return types, and indeed, how to deal with problems that arise if you do. Because when problems arise, you start to think "Why am i explicitly typing these CFCs? What good is it?" - and the To Type or Not to Type question is revisited again.

Those coming into OO in CF from other strictly typed languages will probably tend to advise us to type our CFCs, because, well, that's what they are used to doing, and they know the territory and its advantages. They also might tend to work on more complex applications and in teams, because they are highly experienced. And typing has advantages in complex applications and when working in teams.

Those writing about OO already in the CF world are also almost certainly experienced in OO from other languages. So you're likely to see examples that employ explicit typing in those writings. And as a newbie, you'll probably just follow along there in an effort to do it right. But explicitly typing your CFCs needs skill and experience to get right. So us CF/OO newbies, who are not used to needing to strictly type our variables, run into some brick walls almost immediately.

What we need to understand, i believe, is that explicitly typing your CFCs has it's advantages and disadvantages. The same is true for loosely typing your CFCs. Let's see if we can get an overview, so we can make a more informed choice about typing from the very beginning.

Advantages of Explicitly Typing your CFCs

* If you're working in a team or will be providing an API that other developers will use, it will probably be a lot easier for others to understand your code if you type your CFCs. (You could also provide similar documentation in the hint attribute.)

* You gain a degree of what's called "type safety" in your code, but this a little more theoretical than practical in CF.

In a strongly typed language that's precompiled like Java, your code won't compile if your types don't line up - for instance, if you try somewhere to pass a variable declared as a string into a class that is expecting an object of type Person. That's type safety. The code won't even run.

But in CF, the code will run, and what you'll get is a slightly different error at runtime. So if you make a mistake and don't catch it yourself, your users will be exposed to it. So in this sense, in ColdFusion, type safety works more through the fact that the expected type is documented in the method's type and returntype attributes, and the runtime error says to the developer "See, i told you so!"

* As a more personal side benefit, explicitly typing your variables may help you to feel like you know what you're doing. ;-)

Disadvantages in Explicitly Typing your CFCs

* For the newbie, if you start off explicitly typing your CFCs, it can be difficult to get your objects to play together nicely. To build an app of any complexity, you'll probably need to understand polymorphism and may need to get your head into design patterns. And that takes awhile. So your learning curve becomes much steeper, and if you're learning on your own, you may just hit a white wall or a glass ceiling and not know how to go on.

* Typing needs to be hard coded, and is server-wide, not application specific. Which can wind up to mean that your code is less portable. If you need multiple instances of an application on a single server or are building an app to be distributed and installed on other servers, you or your clients can easily run into difficulties.

Mappings might need to be set up, which may conflict with other mappings on the server. You might wind up having different versions of the same app that you want to run side by side on a single server, and then each version needs to be gone thru and the type, returntype and extends attributes will all need to be changed, and the whole thing will need to be tested to make sure it all works.

Some people have placed all their CFCs in a single directory, so they can easily "see" each other and just type them with the CFC name. If you use factories and instantiate your factories from the root of the site, you can get by. Others have tried placing their CFC's in the webroot of their site, and then when CFAS looks in the webroot first for the CFC, it finds it there.

Security conscious developers tend to want to place their CFCs outside of the webroot, so neither of those workaround is acceptable to them.

Blue Dragon has the possibility to set up Application specific mappings, which solves this problem. Hopefully CFMX8 will also implement this feature.

* It takes extra processing time, especially if the process uses a number of CFCs. This may or may not have a noticable effect.

* Error handling is a challenge for all kinds of typing, native types included.

To give a simple example that illustrates this with a native type, let's say that you have a form that asks the user to fill in their birthdate. You're going to pass the form values into a CFC when the form is submitted. You type your setter to expect a date, like so:

<cffunction name="setBirthDATE" access="public" returntype="VOID" output="false">
      <cfargument name="birthDATE" type="date" required="true" />
      <cfset variables.birthDATE = arguments.birthDATE />
   </cffunction>

Knowing that one of your users may enter something in that field that ColdFusion doesn't recognize as a date, you begin to realize that you'll need to handle the "is not of type DATE" error that bounces off this function somewhere else ... where should i do that? You can't do it from within the method itself.

Should i wrap every piece of code that calls setBirthDATE() in a try - catch block and search for the error " ... is not of type DATE" and handle that? If i use this CFC in multiple places in my code, that's going to be a mess. It would be much better if all my "... is not of type ... " errors were encapsulated.

With dates, even in ColdFusion, we become concerned with type safety when we know we're going to insert a date as a date type of some sort in a database or use date functions on the date. But as you can see, simply typing a method's argument as a date doesn't make it a date! In other words, our explicitly typed method doesn't take full responsibility for a situation where we don't know the type ahead of time. The same is true with any other type besides "date", be it a native type or a CFC.

In cases where you don't know the type ahead of time and would like to handle the error, it can be a challenge to architect. You may feel like your object should be able to take responsibility for dealing with types that it rejects as being incorrect, but it won't. It will behave like a government official that you call and ask, "Can i renew my drivers license here?" and they just say No! and hang up. GovernmentOfficial doesn't take any responsibility if your request is of the wrong type.

Since you'd probably want to set up some way to encapsulate the type error and handle it in one place, you might then look for a solution to that. One way might be to process all your calls to that method thru another method that accepts any type and wraps the call to the typed method in a try catch block or other validation approach. If you're using CFCs to handle all your data, you'll eventually come to that idea. Again, this would be only for methods where you don't know the type ahead of time and it's not managed with polymorphism in some way.

Let's go back to our birthdate example and take a look at a variation that might handle a typing error more responsibly.

<cffunction name="setBirthDAY" access="public" returntype="VOID" output="false">
   <cfargument name="birthDAY" type="any" required="true" />
   <cfif IsDate(arguments.birthdDAY)>
      <cfset setBirthDATE(arguments.birthDAY)>
   <cfelse>
      <cfset variables.invalidFields = listAppend(variables.invalidFields,"birthday") />
   </cfif>
</cffunction>

<cffunction name="setBirthDATE" access="private" returntype="VOID" output="false">
   <cfargument name="birthDATE" type="date" required="true" />
   <cfset variables.instance.birthDATE = arguments.birthDATE />
</cffunction>

In this variation, we've kept setBirthDATE as before, with an argument typed to accept a date, except that we've changed the access to private so that this method can't be called from outside the CFC. And we've added setBirthDAY() as a public method that accepts any type in it's argument. setBirthDAY() checks to make sure that whatever value is passed into it is indeed a date, and if it is, it calls the setBirthDATE() method and passes that validated value into it. If it's not a date, it adds birthday as an invalid field to a list of invalid fields, the idea being that we would check if there are any invalid fields before persisting our data, and if there are, redirect to the form and display a message to the user asking them to correct the birthday field.

Now, what i like about setBirthDAY() is that it's taking responsibility. setBirthDATE() is almost unnecessary. We could easily refactor our code to look like this:

<cffunction name="setBirthDAY" access="public" returntype="VOID" output="false">
   <cfargument name="birthDAY" type="any" required="true" />
   <cfif IsDate(arguments.birthdDAY)>
      <cfset variables.BirthDATE = arguments.birthDAY />
   <cfelse>
      <cfset variables.invalidFields = listAppend(variables.invalidFields,"birthday") />
   </cfif>
</cffunction>

and eliminate the setBirthDATE() method.

What i'm saying here is that when you see a need to handle typing errors in your code because you're not sure what the type is going to be at runtime, typing your arguments isn't going to help you, and you may find that you're better off using type="any" and encapsulating your error handling within the method itself.

If we go back to our setDriver() example from the polymorphism post, we could consider dealing with it in a similar manner as the setBirthDAY() example. Someone brought up the problem of the Child in the comments under the post. In our example, a Child is also a Person, but shouldn't be allowed to drive the car. And indeed, in real life, a child is able to get their hands on the keys and turn them in the ignition, unlike our Dog. So it's a real-life problem this time that may need a solution in our app.

So what if we found ourselves suddenly in the position where the police knocked on the door and said, "If you don't modify your application immediately so that your child can't drive that car, you're going to jail!"

The pressure is on. There's no time to order any more books on design patterns from Amazon.com and sit up late into the night reading them, hoping to come up with some polymorphic design pattern style solution that will allow Man and Woman but not Child to drive our car, even tho' they are all Persons, without tearing our whole application apart and starting over. We don't have time for that. We need a solution, and we need it now.

Here's what i did to keep myself out of jail.

I moved all the components into a test directory on my laptop so i could easily show the police officers on our front porch how i'd solve this problem. Elisa offered then a cup of coffee and told them i'd have a solution for them in a few minutes. As she was coming back into the kitchen, she eyed me intensely and said "Hurry!" under her breath.

<cfcomponent displayName="Person" output="false">
   
   <cffunction name="getFirstName" access="public" returntype="string" output="false">
      <cfreturn variables.firstName />
   </cffunction>
   <cffunction name="setFirstName" access="public" returntype="VOID" output="false">
      <cfargument name="firstName" type="string" required="true" />
      <cfset variables.firstName = arguments.firstName />
   </cffunction>

</cfcomponent>

<cfcomponent displayname="Woman" extends="test.Person">

<cffunction name="goShoppingForShoes">
...
</cffunction>

<cffunction name="putOnMakeup">
...
</cffunction>

</cfcomponent>

<cfcomponent displayName="Man" extends="test.Person">

   <cffunction name="fixCar" output="false">
      ...
   </cffunction>
   
   <cffunction name="playPoker" output="false">
      ...
   </cffunction>

</cfcomponent>

<cfcomponent displayname="Child" extends="test.Person">

<cffunction name="playWithToys">
...
</cffunction>

<cffunction name="screamLoudly">
...
</cffunction>
   
<cffunction name="doSomethingUnexpected">
...
</cffunction>

</cfcomponent>

She just came back to the kitchen to get a few donuts for the officers out on the porch. "How's it going?", she whispers under her breath, with that edge she gets sometimes. "Going good. Gimme a few more minutes."

"They're waiting ... "

<cfcomponent displayname="FamilyCar">

<cffunction name="getDriver" returntype="test.Person">
<cfreturn variables.Driver />
</cffunction>

<cffunction name="setDriver" returntype="void">
<cfargument name="Driver" type="test.Person" />
         <cfset var argMetaData = getMetaData(arguments.Driver)>
         <cfif argMetaData.name Contains 'Child'>
            <cfthrow message="Whoa! You're too young to drive the car!" type="UnderageDriver">
         </cfif>
<cfset variables.Driver = arguments.Driver />
</cffunction>

</cfcomponent>

As you can see, i left everything pretty much as it was. setDriver() is still expecting a Person so we don't get no kangaroos or anything like that trying to drive the car. But ... if you take a close look at setDriver(), i added a few bits of code in there to check if the Person sitting down in the drivers seat is of type Child, and if it is, we throw an error. Check the CF documentation for getMetaData(), which is a native ColdFusion function, for more information.

So let's test this and see how it works:

<cfset ourCar = CreateObject('component','test.FamilyCar') />
<cfset myKid = CreateObject('component','test.Child') />
<cfset myKid.setFirstName('Junior') />
<cfset myKid.playWithToys() />
<cfset myKid.doSomethingUnexpected() />
<cfset ourCar.setDriver(myKid) />

Ok, great. It's working. I'm getting the error onscreen.

Whoa! You're too young to drive the car!

So i take the laptop out to the porch to show them and the officers are pretty impressed.

One looked at the other and said "That Java programmer 'cross town. Is he still in the slammer?"

"Naw, i think he got out a few weeks ago, didn't he?"

Anyway, the officers thought it was pretty damn good as it was, but one of them scratched his head under his cap, you know how they do taking the brim between their thumb and index finger, and asked, "Aren't you supposed to redirect kids to another site or something?"

"You mean like to disney.com?"

"Yeah! Right!"

"Hang on a minute"

Sitting there on the porch, i made a quick adjustment to my Application.cfc file in my test directory, tested it, and ran it for them.

=== Application.cfc ===
<cfcomponent output="false">
   <cfset this.name = "test">
   
   <cffunction name="onError" returnType="void" output="false">
      <cfargument name="exception" required="true">
      <cfargument name="eventname" type="string" required="true">
      <cfif arguments.exception.type EQ "UnderageDriver">
         <cflocation url="http://www.disney.com/" addtoken="No">
      </cfif>
   </cffunction>

</cfcomponent>

"Wow! That's it! Perfect!"

When our kid sat down in the drivers seat, he got redirected to disney.com and forgot all about trying to drive the car.

Anyway, so the cops were really pleased. My wife asked them if they wanted more coffee or anything, but they stood up and said "No thank you ma'am. We'd best be on our way."

As they were starting their sqaud car, my wife looked up at me with her big dreamy eyes and said "Darling, i'm so glad you're not a Java programmer".

;-)

For anyone new to to all this, i've just been playing around here, experimenting with a few novel ideas in code. I'm not saying that any of this is certified, best practice, or even intelligent. But i did keep myself out of jail in a pinch back there, and could use the same technique to quickly adapt to new requirements in another application if my technique stood the test of scrutiny and time.

Stepping back further, i'm questioning the value of always typing the arguments and returntypes in CFCs. If i was working in a corporate environment and was asked to, i'd say "Sure, no problem." If i'm developing an app on my own, my tendency would be to type only if i saw a direct and practical need (like we do for a date that needs to be stored in the database.)

We don't type variables unless there's a clear need in CF, and i'm inclined to take the same approach with CFCs. Otherwise, a hint attribute will suffice for documentation to remind me and anyone else looking at my code that an argument is expecting a specific type of object.

Comments
Hi Nando,

Overall very cool article. Clearly explains typing in CF and I wish I'd had access to it a long time ago!!! Couple of things. One is that it is worth remembering that it is usually pretty safe to use typing for simple types - numerics, strings and the like (lthough sometimes if you use base classes you can't as you have no idea what type a given argument will be).

I've got to say that I am just a little bit uncomfortable with the final example though. It solves the problem so that is cool, but now your familycar needs to have explicit knowledge of every kind of object that is NOT allowed to drive the car. In the real world a watermelon is unlikely to go for a spin, but in the programming world I could as easily try to drive with a watermelon as with a child because my probram knows nothing about arms or legs. So your inexperienced programmer might try to get his watermelon driving the car and now you've got to redirect it to the local farmers market to be sold :-> Over time the list could get really long and become extremely unmaintainable.

I would either suggest handling the typing problem "correctly" using strong typing (not my approach, although probabluy the right way to go for larger teams and larger projects) or just enjoying duck typing and letting it go. How do YOU know a child can't drive a car? Maybe they're really tall and through some freak of government administration they have a valid drivers license. Heck, in the real world a watermelon probably can't drive your station wagon, but in a program as long as it has a DriveCar() method which meets the interface, even a watermelon can drive!

And that s the flexibility (and also the danger) of duck typing. If it quacks like a driver, it can drive :->
# Posted By Peter Bell | 10/7/06 4:54 AM
And if it doesn't you just get a pretty simple error telling you DriveCar() method not found. You skip down to the correct line, look at the calling ree in the error message and then you realize that you forgot to add the DriveCar() method to your mutant watermelon, or for some strange reason had confued a watermelon for a person and then either replace your object or add/inherit/mixin the appropriate method and now the appropriate object (whether a person or a watermelon) is ready to safely take a drive. Lets not get too hung up on real world analogies folks. In the programming world, even a watermelon can drive - if only we give it the chance!
# Posted By Peter Bell | 10/7/06 4:58 AM
Peter,

What i'm attempting to do here is step back and analyze, for myself, any and all criteria one can use when thinking thru the question "should i use typing in my CFCs or not?" - from the perspective of the CF world. The reason being that this typing issue, and all things related to it, has hung me up for a long time.

The most common argument for using typing, type safety, is a little thin in my mind, for all the reasons i gave. Documentation of what a method expects, if that's the reason for typing, can be done in the hint tag, and you avoid the problems. There's also the very natural tendency of newbies to follow examples to try things out, and then employ an approach without taking the time, or knowing how, to think it thru.

So then what's left?

I understand what you're saying about the watermelon, but the apps i build models real world scenarios. If watermelons could drive in the world i was modeling, then my class structure would be different. As it is, they are excluded from driving, because a watermelon is not a Person.

The example i gave, although contrived, is an attempt to look at CFC typing in the same way we look at using native types, like date, in CF. Once in awhile, we ARE concerned with type safety, and build our code to deal with it in a graceful way, so that when we insert or update a date as a date type into a database, we're sure it won't error. Our code is responsible, it takes care of the whole thing. What would that "once in awhile" look like if we take the date example and look for something similar with CFC typing? When i really need typing, i want my code to be responsible for a type mismatch. Just adding the type and returntype attributes doesn't fully ensure type safety. As i see it, you've got to do more, namely, handle the runtime error. When is that justified, and how might it look?

Like i said, in CF, we generally only employ typing and type checking when we really need to, like with dates. When do we "really need to" with CFCs? And is this a valid perspective to take on the issue?

I'm trying to teach myself how to think about typing in CF.
# Posted By Nando | 10/7/06 10:15 AM
Hey Nando,

First point to make: I didn't want my comment to be perceived as a criticism of the post as a whole, I think you are doing an amazing job with these postings, and I always look forwards to the next one.

There are valid reasons for strongly typing in CF (I agree with the ones you mentioned and I'm sure there are other reasons that neither of us get), but I certainly don't use typing for my objects most of the time and it works extremely well for my use cases. I find the trouble of strongly typing my objects to be greater than the value it provides for me (although I fully get why others would do it).

I have mixed feelings about whether child drivers should be caught by runtime code or not. Unless you have an extremely dynamic model when non-technical end users can drive the objects passed to methods in a way that you hadn't anticipated based on parameterization, I usually prefer to create plenty of test cases, get the ugly CF errors and fix my logic. However, there are times where it is nice to catch such issues properly at runtime. I guess the only thing I was disagreeing with was using a negative dataspace which can get very large very quickly. If I was implementing the catching logic, I'd list the VALID objects and anything not valid would throw an invalid object message. Otherwise every time you add an object to your system you have to add it to the catching logic for every single other object method that accepts an object but not that object. In a small number of use caes where (say) there are 20 objects that are valid and 5 that are invalid it might make sense to use a negative dataspace, but on the whole I'd just use "If NOT Adult then error" for most use cases.

Please keep up the great work - love these posts!
# Posted By Peter Bell | 10/7/06 2:08 PM
Peter,

So ... in response to your mixed feelings about the child driver ... ;-)

Regarding those CFC types that are known when we write the code, as we test our code, either we're going to get a runtime error, or we're going to get a runtime error, depending on whether we explicitly type our CFCs or not. Either way, we just fix it and move on. In most cases, the error i get when using "any" is more meaningful to me.

So in the case where the type is known when we write the code, "type safety" boils down to a slightly different runtime error in ColdFusion. There's no significant difference in my mind between using "any" or "dot.path.myCFC" in regards to type safety. I was a little surprised to realize that, because it certainly looks safer or better to use dot.path.myCFC.

As our applications become more complex, we run into more and more situations where the type is only known at runtime. This is the case with my setDriver() method. The keys are in the drawer by the front door. Any Person that knows where they are is a potential driver, Man, Woman, or Child.

When the type is only known at runtime, that's where polymorphism and design patterns start to come into play, and the real OO headaches begin. Only a very experienced application architect is going to be able to get it right from the beginning, so that as requirements change, our codebase is architected in such a way that we don't have to make major modifications to it all the time. Most of us CF'ers are nowhere close to that. I'm certainly not, as you can see from my design ... my setDriver() method was typed to accept a Person. It only took a few days before the flaw revealed itself.

So the cops showed up, as everybody knows now, and suddenly the requirements changed. To me, the point is that the technique i used to accomodate the change is very flexible. If the cops show up tomorrow because my grandmother crashed the car and tell me she's too old to drive, i don't have to call an expensive OO architect in for a consultation. "Gotta problem here. Grandma's an Adult and i just found out she can't drive." I just have to make one quick change to an If statement. And if that statement becomes too unwieldy, the case that you pointed out in your comment, then i could easily refactor it in a few moments and change the logic. I wouldn't have to rework my whole inheritance structure.

The other thing i like about it is that it takes full responsibility for the situation. I know that some people will probably disagree with me on this point, please do in fact, but i don't like how a typing error bounces off a method into the void. I'd rather that a method has the ability to deal with it internally. Otherwise you just wind up wrapping a method in another method to deal with a typing error.

So this technique allows me to deal with a case where i would think type safety is important both flexibly and from within a function. I know i'm approaching this from an entirely different angle, and going out on a limb in doing so.

As far as i can tell, the tricky thing to deal with in object oriented application design is when you don't know the type until runtime. In Java, because it is strictly typed, you need to design your model with a lot of forethought, employing interfaces and polymorphism. It won't compile otherwise.

In ColdFusion, IF i choose to consider explicitly typing my CFCs at all, i'm beginning to think that the only case where it makes sense to do so is to ensure that a CFC is a certain type at runtime, like my setDriver() example. It would be to enforce the "business logic" of the application, to make sure that the players do what they are supposed to do and don't do what they are not supposed to do. If it's just to change the error message, i don't see the point. If it's just to follow the convention developed in a strictly typed world, i don't see the point either.

In a larger sense, before we all run off and spend the next few years learning design patterns so we can use OO in ColdFusion, i'm asking "when do we really, really need <i>type safety</i> ... at runtime? (because runtime is all we have) In what cases would this be important?" and "What does type safety mean in the loosely typed world of ColdFusion?"

I'm beginning to think it means something entirely different than it does in the strictly typed world of Java, from which OO design patterns arose.

And Peter, feel free to comment and (constructively) criticize! :-)
# Posted By Nando | 10/8/06 1:27 AM
Hi Nando,

I know others wouldn't, but I happen to agree 100% - you're preaching to the choir here! I use lots of base classes and other dynamic programming techniques which don't work if you strongly type. There are downsides to my approach, but it works perfectly for my use case.

What I was really hoping to see (and I posted an article linking to this one to try to stimulate it) was someone from the other side of the church posting more explicitly on the downsides of not typing.

There is no question that with no compiler, a lot of the benefits of strong typing go away because you don't catch errors in the IDE - only when you exercise the code, so mainly you end up with a different runtime error message - that's about it. For me the benefits of strong typing are not even close to worth it, was just hoping someone from the other side would put their 2c in to remind us both of the downsides of the trade off we both make.
# Posted By Peter Bell | 10/8/06 5:56 AM
Hello,

im wondering, if you have a Child class, why dont you have a Parent class?


Greetz Erik
# Posted By Erik Westra | 10/11/06 12:57 AM
Hi,

Well, in this simple model, Child extends="test.Person", as do Man and Woman. I might need a Parent class if Parent becomes important to the application. For instance, say the Child was quite young, and in this family, someone needed to change the diapers. Not any old Person would want to do that, normally. It's generally the job of a Parent. So Parent might then extend Person, but the changeDiapers() function would go in Parent (and any other Parental functions).

Silly example, but i'm trying to make a point. You only need a class in your model if it's going to do something in your application. Since so far, our example app wasn't concerned about parenting, we didn't need a Parent class, even tho in real life a child always has a parent or two.
# Posted By Nando | 10/11/06 2:26 AM
Well, the Parent, or maybe Grownup class would solve a part of your problem in another fashion, as you could type the argument of you method to Parent or Grownup instead of to Person.

I do however understand the point you are making.

Greetz Erik
# Posted By Erik Westra | 10/11/06 2:59 AM
Thank you for posting an excellent article about typing in CF and a way to avoid the runtime exception that could be generated if you don't provide the correct type to the method.

But I don't like this code:

<cffunction name="setBirthDAY" access="public" returntype="VOID" output="false">
<cfargument name="birthDAY" type="any" required="true" />
<cfif IsDate(arguments.birthdDAY)>
<cfset variables.BirthDATE = arguments.birthDAY />
<cfelse>
<cfset variables.invalidFields = listAppend(variables.invalidFields,"birthday") />
</cfif>
</cffunction>

Your function is accessing the variables scope and I thought this was a poor practice (reduces portability).

In whatever code that calls the function above you'll need an invalidFields variable and that code will need process that variable to see if there were any problems everytime you call the setBirthDay function. So I don't see where you've reduced your code on the page that calls this function when compared to just using cftry and cfcatch around the call to setBirthDate.

But again thanks for posting and helping me think through ways to handle problems that occur when a function doesn't receive the correct argument type it expects.

Bruce
# Posted By Bruce | 10/11/06 5:45 AM
Bruce,

The code sample here is meant to be in a CFC. So variables.invalidFields would wind up encapsulated within the CFC, not in a calling template.

The calling template would probably need to additionally call a validate() function within this CFC at a certain point that would check if variables.invalidFields contained anything, this is true, but the complexity of what's valid and what isn't would be encapsulated within this CFC, in one place. Your calling code wouldn't need to know about it.

If there are say, 12 setters in this CFC, and the calling code uses 12 try / catch blocks and you use this CFC in 6 places within your code, that's 72 try / catch blocks, all with varying validation code in them.

And sure, we could add a setter for variables.invalidFields, but it would probably be best practice to make that access="private" so it could not be called from outside the function. I was trying to make a few points about typing, so i made the example as simple to follow as i could.

I don't like how a typing error bounces off a method at runtime. That forces me to handle all typing errors at runtime, and if i have to do that, it makes my code much more complex when i have thousands of function calls throughout my app.

I'm only occasionally concerned about type at runtime in ColdFusion, because CF is loosely typed. And to me, "at runtime" implies that i don't know the type at runtime. The fact the CF doesn't check type at compile time isn't my problem.

When i really AM concerned about type, like in the case of a date, it makes no sense to me to use typing in my function, because then that forces me to add another layer of encapsulation around my function to handle the runtime typing error. So i'd need 2 methods to do the job.

One of the guidelines of OO is that a method should do one thing and do it well. So i like this approach because for me, this method is taking full responsibility for the situation. But others might like it better to split this up into 2 methods (or spread hundreds or thousands of try / catch blocks everywhere).

Gotta go. Dinner is ready!
# Posted By Nando | 10/11/06 11:33 AM
Nando:

Thanks for the explanation. I understand much better how your example would work. I'm going to try your methodology on a future project.
# Posted By Bruce | 10/11/06 1:47 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.1.004.