Hi everyone I have found that I often have to use...
# cfml-general
c
Hi everyone I have found that I often have to use:
Copy code
<cfinclude />
When creating cross cfml engine [ACF/Lucee] compatible code. For instance, if you do something like this, you will get a compilation error:
Copy code
function GetFrameworksByParam() {
        
        var local = {};
        
        local.frameworkbyparam = {
            var1 = "hello world"
        };

        local.szResponse = {};

        if(server.keyExists( 'lucee' )){
            local.serializeParam_lucee_object = local.frameworkbyparam;
            local.serializeResponse_lucee = Serialize(local.serializeParam_lucee_object);
            local.szResponse = local.serializeResponse_lucee;
        }
        else{
            local.serializeParam_acf_object = local.frameworkbyparam;
            local.serializeParam_acf_type = "xml";
            local.szResponse = Serialize(local.serializeParam_acf_object, local.serializeParam_acf_type);
        }
        
        
        WriteDump(var=local.szResponse);
}

GetFrameworksByParam();
The error occurs because of there are differences between the amount of params that the native method:
Copy code
Serialize()
Can accept. In ACF, it is two params, whereas in Lucee, it is just one param. Differences in param names, if the params are named within the method call, also cause errors. The compiler checks code in every conditional branch. But, if you hide the code in an include, there is no error:
Copy code
function GetFrameworksByParam() {
        
        var local = {};
        
        local.frameworkbyparam = {
            var1 = "hello world"
        };

        local.szResponse = {};

        if(server.keyExists( 'lucee' )){
            local.serializeParam_lucee_object = local.frameworkbyparam;
            include "includes/serialize-lucee.cfm";
            local.szResponse = local.serializeResponse_lucee;
        }
        else{
            local.serializeParam_acf_object = local.frameworkbyparam;
            local.serializeParam_acf_type = "xml";
            include "includes/serialize-acf.cfm";
            local.szResponse = local.serializeResponse_acf; 
        }
        
        
        WriteDump(var=local.szResponse);
}

GetFrameworksByParam();
includes/serialize-lucee.cfm
Copy code
<cfset local.serializeResponse_lucee = Serialize(local.serializeParam_lucee_object) />
includes/serialize-acf.cfm
Copy code
<cfset local.serializeResponse_acf = Serialize(local.serializeParam_acf_object, local.serializeParam_acf_type) />
Am I correct in thinking that CFML application servers don't check code within
cfinclude
, at compile time?
z
yep
πŸ‘ 3
c
Cheers for the confirmation...πŸ™
c
Railo/Lucee were not around, when Coldfusion was created, so it can't be a strategy for building cross compatible code. Why do CFML engines exhibit this behaviour?
z
that's just how parameter validation works, aside, i generally avoid using serialize and only use serializeJson
πŸ‘ 1
c
Wait a second. Are you saying that it is only method parameter validation, which is not carried out inside a
cfinclude
, by the compiler, but that the compiler does check other code constructs inside a
cfinclude
z
no\
πŸ‘ 1
c
So, essentially, it is like the 'wild west' inside a
cfinclude
😊
z
nope
c
I guess, runtime errors are still caught?
z
cfinclude is compiled on demand
c
OK. I see...
z
so in the good old early days of cfml, you could write extra dynamic code by writing out a template and including it
c
A template. being a view [HTML/CFML tags]?
z
a .cfm file
πŸ‘ 1
c
so in the good old early days of cfml
And you can't do that now?
z
why not? but the language evolved, so you didn't need to use that hack approach anymore
c
So are you saying: https://github.com/lucee/Lucee/blob/6.0/test/functions/ImageFormats.cfc#L29 Is a modern approach to circumventing the compilation error for method param differences? So this bypasses the compiler?
Copy code
var imgFormats = evaluate("imageFormats( true )"); // v2, evaluate to bypass compile error with v1
z
well it works
there's many ways to skin a cat
c
So I could do:
Copy code
local.szResponse = evaluate("Serialize(local.serializeParam_acf_object, local.serializeParam_acf_type)");
z
once a variable is created, the local scope is the immediate scope, so there's no need for the prefix
πŸ‘ 1
c
Do you know when this evaluate strategy started working? What version of ACF, roughly? Or has it been around since evaluate() was introduced?
Anyway, thanks for your help. This has been most enlightening...πŸ™‚
z
but like with JS, you are better off using feature detection https://trycf.com/gist/fe5355de2a20b31f5ad2521f1c29e176/lucee5?theme=monokai
arrayLen(getFunctionData("serialize").arguments)
πŸ™ 2
a
This is not how I would handle this, if I am reading things correctly. I would have something like this:
Copy code
/shims/
    lucee/
        Shims.cfc
    CF/
        Shims.cfc
On lucee map
/shims
to
/shims/lucee
, and one CF map
/shims
to
/shims/CF
And in yer app use
Shims::serialize
(Or do similar with yer dependency injection setup).
πŸ‘ 1
The decision as to whether yer on Lucee or CF should not be tightly coupled to what you need to do based on that decision. If that makes sense.
πŸ™ 1
(and more importantly vice-versa)
πŸ‘ 1
b
@Charles Robertson This is exactly what ColdBox does in a few places (though I'd be more likely to use subclassing and method overrides rather than cfinclude). Note, sometimes you can work around this by using
attributeCollection
when it comes to tags with differing attributes per engine. https://github.com/coldbox-modules/s3sdk/blob/development/models/AmazonS3.cfc#L1410-L1413
πŸ™Œ 1
c
Just out of interest, can you use argumentCollection with a native method? I know you can definitely use it for UDFs. This would also resolve the problem.
b
I would encourage you to report back what you find when you test that πŸ™‚
βœ… 1
z
nah, argumentCollection doesn't work with BIFs yet https://luceeserver.atlassian.net/browse/LDEV-18
πŸ‘ 1
a
I preferred Brad's answer to that question πŸ˜‰
c
@zackster That’s great to know. Maybe, ACF will follow suit, one day πŸ€”
@bdw429s According to a comment at @zackster link above:
One thing to note: BIFs implemented in CFML are compatible with
argumentCollection
, while those implemented in Java are not.
Thanks for that nugget, @Ryan Guill
But, having looked at the link [BIFs implemented in CFML]: https://github.com/lucee/Lucee/tree/master/core/src/main/java/resource/library/function It doesn’t seem to do what the comment is describing. These functions use the attribute collection of the function’s tag equivalent. But you cannot pass the params in via the argumentCollection param, except for
queryExecute()
, which allows you to use an options param to do so. So, the answer is, currently, no. But it could be a Lucee feature, in the near future? πŸ€”