Wednesday, 7 May 2014

CFML: We learn something every day...

G'day:
This was brought to my attention via one of my colleagues. I guess it's predictable behaviour, but it's less than ideal, I think.

Here's some code:

// Parent.cfc
component {

    function f(){}

}

// Child.cfc
component extends="Parent" {
    include "mixins.cfm";
}

<cfscript>
// mixins.cfm
function f(){}
</cfscript>

<cfscript>
// test.cfm
o = new Child();
writeDump(o);
</cfscript>

So here we have Parent.cfc which implements a method, f(). Child.cfc overrides this method, but uses a mixin include to do so. In our case it was because we need to override the same methods in a coupla places, hence factoring the f() method out into an include we can share between CFCs.

And on ColdFusion, we get this:

The following information is meant for the website developer for debugging purposes.
Error Occurred While Processing Request

Routines cannot be declared more than once.

The routine f has been declared twice in different templates.

Suck.

To me, this is a rule for the sake of a rule. And it seems Railo agrees with me, because on Railo the code runs fine.

Can anyone think of a legitimate reason for ColdFusion to behave the way it does?

Intererstingly, whilst researching this article, I came across this other article (from this blog) "Which is better: having your methods inline in a CFC, or included from a separate file? (cont'ed)", and in there I conclude that taking this approach to doing mixins is a bit shonky. I am not sure I agree with myself quite so emphatically any more. It certainly seems a good fit for what we're trying to achieve currently.

To work around this, I think we've done this sort of thing:

// Mixin.cfc
component {
    function f(){}
}

// Child.cfc
component extends="Parent" {

    mixin = new Mixin();
    f = mixin.f;
    
}

So we now have a separate Mixin.cfc, and instantiate that within Child.cfc, and overwrite the f() method from Parent.cfc with the f() function in Mixin.cfc. And this works.

It'd be much nicer if CF had the concept of static methods, in which case we'd not need to instantiate Mixin. But so be it.

I've raised a ticket to get this artificial restriction removed: 3756524; and another one to implement static methods in CFML: 3756518 (there's already a ticket in for Railo: RAILO-2941).

That's it.

--
Adam