A possible Bug? <cffunction> inside conditional

Hi all. I’m getting an unexpected result in my code. I distilled it down to this test…

<cfif true>
	<cffunction name="test_function" output="false">
	    <cfreturn "100">
	</cffunction>
	<cfoutput>#test_function()#</cfoutput>
<cfelse>
	<cffunction name="test_function" output="true">
	    <cfreturn "200">
	</cffunction>
	<cfoutput>#test_function()#</cfoutput>
</cfif>

Maybe I am missing something here, but I would clearly expect my code to output 100. However when it runs, it for sure is outputting “200”. Possibly Lucee is reading the entire page and looking at the functions outside of the conditional code and this is an expected way for Lucee to run? I tested this and confirmed it is the same under both 5.2.8.50 as well as 6.0.0.585.

Thanks.

Yes, it seems a bug.

Well… it’s a misunderstanding on the part of the dev, not a bug. It’s intended behaviour.

Function statements are indeed compiled separately, before runtime. Always have been.

So the second one replaces the first one.

CF is a bit less forgiving here (and Lucee is not doing itself or anyone else any favours here, by not following CF’s lead): CF will error with “Routines cannot be declared more than once”, as it’s specifically - and by design - a CFML rule that… well… one can’t declare the same function twice.

If you wanna do this sort of thing… use a function expression instead. Those are evaluated at runtime.

So like:

if (true) {
    test_function = () => 100
} else {
    test_function = () => 200
}

That said though… conditionally defining a function like this seems… unlikely to be the best way to solve whatever you might be trying to solve. It makes a mess of the single responsibility principle a coupla times over, if nothing else.

What are you actually trying to do?

5 Likes

Adam,

That answer makes a lot of sense. And explains what is going on for me. I agree, there are a handful of ways I can work around this, and I learned something new today. I was just a bit shocked I had never seen such a bug before or this would have been the first time I ever tried to do this. I for sure will do something that will run at execution time and not compile time.

Once you answered I tried something different, which teaches me even more…

Test Code

<cfif true>
	<cfinclude template="function100.cfm">
	<cfoutput>#test_function()#</cfoutput>
<cfelse>
	<cfinclude template="function200.cfm">
	<cfoutput>#test_function()#</cfoutput>
</cfif>

function100.cfm

<cffunction name="test_function" output="false">
    <cfreturn "100">
</cffunction>

function200.cfm

<cffunction name="test_function" output="false">
    <cfreturn "200">
</cffunction>

Therefore forcing each to run at compile time. And thus my runtime only includes the file that has the compiled code. Now I truly understand more about the underpinnings.

Thanks! Appreciate you!

2 Likes

And - bonus - it’s a better way of organising the code and is closer to each bit of code having a single responsibility.

Glad it helped.

And it’s always good to learn new stuff and understand things better!

1 Like