How do YOU specify "simple" arguments in CFML?

One thing that I sometimes run into in my CFML applications is a method that can accept multiple types of “simple” values (such as both a numeric value or a string value). I never know quite how to define the method. I often end up just using any:

function myMethod( required any value )

But, the problem here is that any is a bit misleading. Meaning, my method might blow up if it receives an array or a struct. Which feels … not great.

I could probably just use string, and rely on the fact that CFML can auto-cast “simple” values as needed:

function myMethod( required string value )

But, this also feels a bit misleading since I can also accept a number.

Part of me wishes that CFML had the notion of a simple data type:

function myMethod( required simple value )

Something that would essentially signify:

type simple = string | numeric | date | boolean;

Just thinking out loud. Would love to hear more about how you all handle this kind of a case.

4 Likes

It doesn’t seem awesomely elequent but…

how about a switch / case where you test for the various “types”
And have a default of auto-casting - as a back-stop?

The case statements could either be the required change - or a call to a specific private function

(pseudo-code, of course - because I am too lazy to write real code)

switch {
    case "testForNumericType" => myPrivateNumericFunction(arguments,value) {};
    case "testForBooleanType" => myPrivateDateTimeFunction() {};
    etc...

   default => yourInitialFunctionWithDuckTyping(arguments.value) {};
}

I would assume you would need some test cases to verify the order that you would present the case statements… eg while (although) isDate(3) returns true… “I” would guess it should be handled as a “numeric” type.

1 Like

Yeah, I think some variation of this is what has to end up happening. And, when you turn around and make those inner-calls, you need to cast the value to the right type:

myPrivateNumericFunction( + value );
myPrivateDateTimeFunction( dateAdd( "d", 0, value ) );
myPrivateBooleanFunction( !! value );

Historically, type-checking in ColdFusion is about possible casting and not the actual runtime type. Which never really mattered prior to “member methods”. I started a long thread about this a year ago - tangentially related to this topic:

1 Like

I just use “any” in that case, or honestly just leave off the type. It’s not totally ideal, but that’s what I do :slight_smile:

1 Like

Oh man, I literally forgot you could even omit the type in a method signature :rofl: But, yeah, sounds we’re in the same boat.

@bennadel : Something that would essentially signify:

type simple = string | numeric | date | boolean;

I don’t see the need. String is a simple type that covers the 4 cases you mention.

CFML is weakly-typed, from birth. That is one of its strengths, I therefore wonder why you would want to strengthen the typing in a language that was intentionally created weakly-typed. :smiley:

It gets complicated because ColdFusion really isn’t as loosely typed as it once was. But, the validation and decision functions haven’t really caught up with that yet (it would be a backwards compatibility nightmare). Consider this CFML code:

<cfscript>
  value = "yes";

  if ( isBoolean( value ) ) {
    echo( value.yesNoFormat() );
  }
</cfscript>

This throws an error, The function [yesNoFormat] does not exist in the String. But, if you change it to value=true, then the code runs.

Once CFML introduced “member methods”, they fundamentally made the language more strongly typed. And, I’m suggesting that a new simple type would allow someone to say that a given value is “simple”, but that there are no other assertions being made about it. And, it’s up to the internal logic of the given Function to take caution when consuming the value.

Basically, this is what the any type is - it says, here’s this value, it’s defined, but that’s all I know about it. It’s up to YOU as the Function logic to take care. The simple value is exactly that; only, it narrows it down to the simple values.

CFML has changed; and I’m just trying to figure out how to work within the new constraints.

Hi @bennadel, Thanks for your explanation. I now have an idea of your need.

But I hope you will agree that what you’re asking for has the potential to open up a number of cans of worms.

If you replace value.yesNoFormat() with yesNoFormat(value) the code will work as expected. Either form works without error in Adobe ColdFusion.

The expression value.yesNoFormat() implies that value is an object. With value=true it is an object of the wrapper class java.lang.Boolean, With value="yes" it is indeed an object of java.lang.String, hence the error.

The worms are on the loose. As far as I can see, the above situation would be the same if we had Simple type. Would it be more appropriate, in this particular example, to request that Lucee CFML introduce the yesNoFormat function for strings?

Yes, I agree that the worms are loose :laughing: :laughing: I don’t have the best suggestion here - I am mostly feeling the pain and wanted to see what other people would do.

For now, I just keep using "any" and rely on my controller layer to type-case on the way in:

// Cast to strict Boolean
service.myMethod( value = !! rc.value );

// Cast to strict Numeric
service.myMethod( value = val( rc.value ) );

// Cast to strict Date
service.myMethod( value = dateAdd( "d", 0, rc.value ) );

I like to view the “controller” as the layer that is responsible for wrangling the data. So, if the web-request happens to submit all data a Strings, then I lean on the Controller to translate the String values to the “expected” data type on the CF side.

Of course, this is all predicated on me wanted to use member methods at a lower layer.

Anyway, just thinking out loud - I don’t think there’s an obvious answer.

1 Like