Skip to main content
Ben Nadel at RIA Unleashed (Nov. 2010) with: Carol Loffelmann and Vicky Ryder and Simon Free
Ben Nadel at RIA Unleashed (Nov. 2010) with: Carol Loffelmann Vicky Ryder Simon Free

Reflectively Accessing Built-In Functions In ColdFusion

By
Published in Comments (4)

Don't do this. It doesn't really work. Built-in functions, in ColdFusion, just weren't really designed to be passed-around as references. I'm putting this exploration here purely for my own reference (no put intended).

To start this experiment, I used the getFunctionList() which, despite the odd naming, returns a struct in which each key is a function name that ColdFusion makes available in the global namespace. The value of the struct is just an empty string.

The question was then, given a built-in function name, like "writeDump", could I programmatically get a reference to said function. Ironically, and this is part of the whole, "don't do this" take-away, writeDump is one of the methods that you can't pass around as a first-class citizen in Adobe ColdFusion (despite the fact that it's in the getFunctionList() result).

That said, most of the functions can be passed-around, at least in a degraded sense. To access these functions in Adobe ColdFusion, I used the evaluate() function, which dynamically executes CFML code. On the Lucee CFML side, they have a built-in way to do this — a function named getBuiltinFunction().

Here's my code for transforming the getFunctionList() collection into a collection of first-class references:

<cfscript>

	// The getFunctionList() returns a struct of function names, which would normally
	// allow us to perform a quick look-up to see if a function exists in the runtime.
	// However, in this case, we're going to use it power our reflective look-up of first-
	// class, built-in function references.
	functionRefs = getFunctionList().map(
		( methodName, value ) => {

			try {

				return getFunctionList().keyExists( "getBuiltinFunction" )
					// Lucee has a built-in reflective API for accessing functions.
					? getBuiltinFunction( methodName )
					// Adobe ColdFusion has no reflective API, fall-back to evaluation.
					: evaluate( methodName )
				;

			} catch ( any error ) {

				return "missing";

			}

		}
	);

	// Filter down to any methods that we failed to locate through reflection.
	missingFunctionRefs = functionRefs.filter(
		( key, value ) => isSimpleValue( value )
	);

	writeDump(
		var = missingFunctionRefs,
		top = 10
	);
	writeDump(
		var = functionRefs,
		top = 10
	);

</cfscript>

If we run this CFML code in Adobe ColdFusion 2021-2025, we get the following output:

As you can see in the screenshot, the following built-in functions failed to be located through reflection:

  • isNull()
  • location()
  • throw()
  • trace()
  • writeDump()
  • writeLog()

I suspect that some of this is because functions like isNull() and throw() might actually be compile time directives and not run time operations (just my theory). But, functions like writeDump() and location() - I have no idea why those would failed to resolve.

If we run the same CFML code in Lucee CFML 6, we get the following output:

In Lucee CFML, none of the built-in functions fail to resolve. Which is nice; but, in both runtimes, even the functions that do resolve can't really be used in a natural way.

If I try to use one of the function references as a member of the resultant functionRefs struct, Adobe ColdFusion throws an error. Example:

functionRefs.structNew()

... throws the error:

The structNew method was not found.

However, if I store the reference into an alias first:

fn = functionRefs.structNew

... and then use fn:

writeDump( fn() )

... that does work. But, it's still basically broken because if we try to pass-in a named argument for the struct type:

writeDump( fn( type = "ordered" ) )

... this breaks in both Adobe ColdFusion and Lucee CFML:

  • ACF: "Entity has incorrect type for being called as a function. The symbol you provided fn is not the name of a function."

  • Lucee: "Can't cast Null value to value of type [function]. value is null."

Just to be clear, if I were to replace the fn alias with the built-in structNew(), this works just fine:

writeDump( structNew( type = "ordered" ) )

It only breaks when I try to use structNew() as a function reference.

So, the moral of the story is Just don't. The language just wasn't designed to be used this way; and the attempt to back into these mechanics don't work very well.

Want to use code from this post? Check out the license.

Reader Comments

283 Comments

Cool thought experiment, but why would I ever want to (or need to) reference these functions reflexively? I've heard people refer to functions as "first class citizens" before, and I know that means they can be passed around. I always assumed it was for some sort of inversion of control mechanism. Now you have me wondering what I'm not getting. 🤔

16,062 Comments

@Chris,

Yeah, I don't think you would ever need to do this. It was just a thought that I stumbled over while doing this other post about runtime extensions:

www.bennadel.com/blog/4825-creating-runtime-extensions-and-polyfills-in-coldfusion.htm

^^^ this post actually took me like a week to write because I went down a lot of wrong-turns and things that kind of worked in Lucee but not in ACF. Mostly it was just a lot of rando "what if" kind of thoughts.

283 Comments

@Ben Nadel,

I love those rabbit holes. The learning happens in the experimentation. The deeper learning comes from the wrong turns.

16,062 Comments

Exactly! This is part of my concern over using ChatGPT too much. I feel like I don't want anything to prevent me from going on wild tangents. I like using AI to ask questions and think through some scenarios; but, I'm very hesitant to have it do too much heavy lifting exactly for this reason.

Post A Comment — I'd Love To Hear From You!

Post a Comment

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel