Posted in ColdFusion | Posted on 04-13-2009 | 3,628 views
Bob asks:
I've been googling for a couple days and can't find an answer to this. I have a function in a CFC with an argument of type numeric. If the value passed to the function is not numeric, an error is thrown. How can I catch that error? I tried wrapping the cfargument tags in a try/catch block, but CF doesn't like that. I'd like to handle it in a way that I can return a default value if the proper value isn't passed in.
You've got a couple things in play here, so let me address them one by one. First, you noticed that you couldn't wrap your cfargument tag in a try/catch block. That is by design. When it comes to CFC methods, there are two 'special' types of code blocks that must placed in particular order.
The first is cfargument tags. The second is var statements. In both cases, you can use CFML comments anywhere. But the important thing here is to remember that cfargument tags have to be used first and you can't mix any other tags in there. Even a simple CFIF is not allowed.
So given that he wants to use a default value when a non-numeric argument is passed, how can he handle it? First, he has to change his cfargument tag to be looser in terms of validation. His current code probably looks like so:
By it's very nature, this line says that the argument, raysage, must be passed and must be numeric. Period. In order to change it to allow for non-numeric values, you would simply do:
Then, after any other cfargument or var statement, you would do:
2 <cfset arguments.raysage = 0>
3</cfif>
Obviously 0 isn't too important there. Whatever default you want to use should be placed there instead.
I shared the above with Bob and he responded with:
You know, something interesting to cover might be what the purpose of the type attribute is if you can't gracefully enforce it. For example, why would I set an attribute to type="numeric" if I can't do anything with that except blow it up?
My response to him was that his use of the argument is probably a bit unusual. Normally people want the argument check to be strict: You MUST pass it as type So and So. Period.
Most of the time people would not want logic like he had. That's why we had to use a bit more code to handle his specific business rule. The same would have applied if he had some other rule, like numeric, but greater than zero. Outside of type checking, anything else would be custom.


Another thing you can do, is stick to using strict validation for non-remote methods and then use a proxy CFC for all your remote methods.
While using a proxy requires a little more set up, it allows for a lot more control and allows you to set up better error handling.
Take the example where you a UDF that calls another to perform an operation. That UDF may in turn call another UDF for something else. If you simply perform error checking at the presentation layer, you should only need to check the input variable once, or use one try catch, not one in each of the UDFs. Not only are things tidy, it forces you to create rigid code.
As another poster mentioned, argument typing is meant to provide other programmers guidance as to what type of value is expected by a method in an API and "enforce" it so they don't have to dig behind the argument to figure that out. It's not designed to provide a validation / response mechanism to a user of an application.
We also can note that error trapping is a clumsy and resource intensive way of providing a simple response to a user, "Hey, we need a number here", or defaulting a value to 0 for instance if that's what is needed.
The only place I can think of is when you're shoving data into a database/spreadsheet... Otherwise, doesn't it seem overkill to enforce type if CF is typeless?
I can see more use for validating against masks rather than atomic datatypes -- Credit card numbers, phone, email, etc... and those are best validated at user entry no matter which interface de jure you select.
Is that a truth that trapping an error costs more than pre-validating? Seems to me that you're spending the same time, just in different layers...
(Just purely out of curiosity, it would be interesting to know the design decision that prompted data typing on arguments...)
I think it depends on what type of application you are building. If you are providing an API that other developers (or you) will use, and you need to ensure that the developer passes in a struct and not a string for instance (or your code will break), then providing a type on the argument makes a lot of sense. The error that will be thrown to the developer will likely be more clear than the error you'd get from running the code that needs the struct (and got a string instead).
For validating form data, throwing errors is somewhat resource intensive, because CF's error handling machinery is put into play. Time a request that throws an error, catches it and returns a message to the user interface vs a request that processes an if statement and returns a message to the user interface.
[Add Comment] [Subscribe to Comments]