Monday 1 July 2013

Question for y'all re CFML interfaces

G'day:
I can't work out what my opinion is on this.


Have a look at this code:

// IAdditionalOptional.cfc
interface {

    public numeric function f(required numeric x);

}

// AdditionalOptional.cfc
component implements="IAdditionalOptional" {

    public numeric function f(required numeric x, numeric y){
        if (structKeyExists(arguments, "y")){
            return x * y;
        }else{
            return x * 2;
        }
    }

}

<!--- testAdditionalOptional.cfm --->
<cfset o = new AdditionalOptional()>
<cfoutput>#o.f(21)#</cfoutput>

In this example I have an interface IAdditionalOptional.cfc (ignore the file names, I know they're no good; I just needed to call them something) which stipulates that f() needs to take a numeric argument x. In AdditionalOptional.cfc, I implement f() to take the required argument x, but also has an optional argument y.

When I run testAdditonalOptional.cfm I get an error (and completely expectedly so):

Function argument mismatch.

The f function does not specify the same arguments or arguments in the same order in the AdditionalOptional ColdFusion component and the IAdditionalOptional ColdFusion interface.


I know why this happens. However I kinda raise an eyebrow at this. Because f() does still fulfill the contract requirements of the interface: it can be called with just the required argument no problem. So any place that method needs to be called like that, it can be. Sorted.

And how about this:

// IRequiredArg.cfc
interface {

    public numeric function f(required numeric x, required numeric y);

}

// RequiredArg.cfc
component implements="IRequiredArg" {

    public numeric function f(required numeric x, numeric y=2){
        return x * y;
    }

}

<!--- testRequiredArg.cfm --->
<cfset o = new RequiredArg()>
<cfoutput>#o.f(21)#</cfoutput>

In this example the interface requires the y argument to be required, however in the implementing CFC it's optional but has a default value. Now this errors as well, but - again - to me the implementation of f() does actually fulfill its contractual obligations that IRequiredArg requires: it can be used to take two numeric args and return another numeric: job done. That it can also only take one arg and still effect the job at hand is neither here nor there, surely?

I guess the CFML implementation of interfaces was lifted from Java, wherein there's not such thing as "optional arguments", so it perhaps was not a consideration. But given CFML is more flexible in this area, I wonder whether this flexibility should have been considered in CFML's interface implementation.

Or is there something I'm missing here, which means I'm talking ballocks? It would not be the first time. Even today.

;-)

Thoughts?

Update (18/2/2015)


I have concluded this is a bug. I have raised a ticket for ColdFusion: 3941525; and Lucee: 171.


--
Adam