Copy link to clipboard
Copied
Our development team recently discovered that we are getting multiple errors when using implicit get accessor (person.firstName) instead of generated get accessor (person.getFirstName()). Here are instructions of how to reproduce the error:
1. Create a new ColdFusion application with the following files:
Application.cfc:
<cfcomponent output="false">
<cfset this.invokeImplicitAccessor = true />
</cfcomponent>
Person.cfc:
component accessors=true {
property firstName;
}
index.cfm:
<cfscript>
local.person = new Person();
local.person.firstName = "Zachary";
for( local.i = 0; local.i < 1000; local.i++ ) {
local j = local.person.firstName;
}
</cfscript>
index2.cfm:
<cfscript>
local.person = new Person();
local.person.firstName = "Zachary";
for( local.i = 0; local.i < 1000; local.i++ ) {
local j = local.person.firstName;
}
</cfscript>
2. Test the index.cfm with JMeter, use 2000 threads, 10s Ram-Up Period and Loop count 1 (test plan: https://pastebin.com/nBtpL4zP)
3. In our tests the page always fails with the same error message:
Element PERSON.FIRSTNAME is undefined in LOCAL.
4. The error % we are getting with the above settings usually falls somewhere between 8 to 10 %, meaning that 160 to 200 requests out of >2000 requests fails.
5. When index2.cfm gets tested with the same settings, we don't get any errors
Here are some details about the test environment:
OS: Windows Server 2016 Standard
ColdFusion: Adobe ColdFusion 2018 Release
JMeter 5.0 (https://jmeter.apache.org/download_jmeter.cgi)
Does anyone have any idea why this is happening? Is there some ColdFusion settings we could tweak? The above example application is >very minimal, and we are not doing anything special, so I don't see any reasons why implicit accessors should fail, especially when >generated accessors seems to pass the same test without any issues.
We appreciate any help or suggestions of what to try to get the >implicit accessors working.
br,
Antti Koskenalho
Copy link to clipboard
Copied
I tested with this:
component accessors=true {
property firstName;
property age;
}
With first example I'm able to call person.setFirstName( "Zachary" ).setAge( 30 ) without any errors, which makes sense to me, as the fist method call returns the Person object, and I can call it's setAge() method. With your example i also get returntype any and it fails with error Value must be initialized before used.
Copy link to clipboard
Copied
Have you tried using his explicit setters, as he proposed today and previously on Jan 26. I hoped you would have then,at least to see if it made your error go away under the load test. it may not be the preferred solution, but it could be a workaround until the problem was understood.
BTW, whether it's a bug or not still is not clear. A race condition may not be a "bug" in CF, per se, but an unexpected result due to some characteristic of your environment. Still, it's indeed worth filing as an issue in the tracker, to see if Adobe or anyone else can recreate it or not. You ought to also point them to this thread, to see all the things discussed and considered so far.
Copy link to clipboard
Copied
Charlie Arehart​,
I haven't tried with explicit setters, as we ended up using generated accessors presented in index2.cfm implementation as a workaround. However, I do see value in using explicit setters as well, if they work. I could try that next week as well.
Copy link to clipboard
Copied
soltiger wrote
I tested with this:
component accessors=true {
property firstName;
property age;
}
With first example I'm able to call person.setFirstName( "Zachary" ).setAge( 30 ) without any errors, which makes sense to me, as the fist method call returns the Person object, and I can call it's setAge() method.
It should work, of course. There's no questioning that. What I question is whether it is good practice.
If setFirstName() returns a type, then the object model will be confusing. For example, you might as well forget the terms getters and setters. For setFirstName() is at once mutator as well as accessor.
Copy link to clipboard
Copied
I found this about Method chaining:
Copy link to clipboard
Copied
soltiger wrote
I found this about Method chaining:
I am aware of this example. I am not one for dogma, but would suggest you use method-chaining sparingly. Here you are 'setting' properties that are just simple values. But, in general, the properties may be complex objects that themselves contain properties.
Complexity is the reason why you should use method-chaining in moderation. As it may introduce unnecessary coupling to your code. Which will make your software less versatile and, in the long run, more difficult to maintain.
Copy link to clipboard
Copied
On second thoughts, you should not use
local.j=local.person.firstName;
It may work sometimes, but it is, strictly speaking, wrong. That is because firstName is a private field of Person and is in Person's variables scope. So the correct expression is
local.j=local.person.getFirstName();
Copy link to clipboard
Copied
Best to my understanding, and based on the Adobe documentation (ColdFusion Help | CFC Implicit notation), implicit getters and settings should be supported by ColdFusion, and so far I haven't seen any documentation stating that we shouldn't use them. Internally CF invokes the property's get() and set() methods (see Adobe's example) when dot notation is used. However, to rule out the possibility that the generated accessors ( generated by using "accessors=true" in componen cfc ) fails, I tried to manually define the getFirstName() and setFirstName() methods as they have done it in that example. There was no difference when compared to generated accessors.
Copy link to clipboard
Copied
soltiger​, your approach is correct. I reread from the beginning and saw that you had, correctly, defined invokeImplicitAccessor in Application.cfc.
I may not be a fan of the attribute invokeImplicitAccessor, but I should add that my statement
On second thoughts, you should not use
local.j=local.person.firstName;
It may work sometimes, but it is, strictly speaking, wrong.
is just opinion. It comes after I encountered situations where ColdFusion confused accessors(getters) with mutators(setters), making implicit properties behave as if they were keys in a structure. In fact, I am wondering whether you too have stumbled on something similar.
In any case, the main reason I don't use ColdFusion's implicit accessor is that it breaks some fundamental rules in object-oriented design. For example, encapsulation and separation of concerns. Nevertheless, it is a handy feature, as it is flexible.
If you must use invokeImplicitAccessor=true, bear in mind that:
"Implicit" means that you and I don't know what ColdFusion is doing under the hood. But here's one clue: the return statement.
Add a setter and a getter to Person.cfc, and test with the following code
<cfscript>
component accessors=true {
property name="firstName";
function setFirstName(string fName){
writeOutput("#getFunctionCalledName()# called. <br>");
variables.firstName = arguments.fName;
}
function getFirstName(){
writeoutput("#getFunctionCalledName()# called. <br>");
// If you leave out the following line, you will reproduce the error
return variables.firstName;
}
}
</cfscript>
Copy link to clipboard
Copied
Plese find the bug report I just created from here: Tracker https://tracker.adobe.com/#/view/CF-4203997