Skip to main content
Participating Frequently
June 30, 2022
Question

Strange Comparison Issue

  • June 30, 2022
  • 4 replies
  • 2253 views

Day 2 of testing CF 2021 and I'm puzzled by what seems to be another bug.  Consider the following:

 

<CFSet A='147.xxx.yyy.zzz'>
<CFOutput>
  #A#---<br>
  Left 4: #Left(A,4)#---<br>
  Left 4 eq: #iif(Left(A,4) eq '147.',DE('Yes'),DE('No'))#<br>
  Left 4 is: #iif(Left(A,4) is '147.',DE('Yes'),DE('No'))#<br>
  Left 4 equal: #iif(Left(A,4) equal '147.',DE('Yes'),DE('No'))#<br>
  Left 4 CFIf eq: <CFIf Left(A,4) eq '147.'>Yes<CFElse>No</CFIf><br>
  Mid dot: #iif(Mid(A,4,1) eq '.',DE('Yes'),DE('No'))#<br>
  Left 3 Compare: #iif(Left(A,3) eq '147',DE('Yes'),DE('No'))#<br>
  First Item in List: #iif(GetToken(A,1,'.') eq '147',DE('Yes'),DE('No'))#<br>
</CFOutput>

 

This outputs the following in CF 2021 (update 4):

 

147.xxx.yyy.zzz---
Left 4: 147.---
Left 4 eq: No
Left 4 is: No
Left 4 equal: No
Left 4 CFIf Compare: No
Mid dot: Yes
Left 3 Compare: Yes
First Item in List: Yes

 

But in CF 2016:

 

147.xxx.yyy.zzz---
Left 4: 147.---
Left 4 eq: Yes
Left 4 is: Yes
Left 4 equal: Yes
Left 4 CFIf eq: Yes
Mid dot: Yes
Left 3 Compare: Yes
First Item in List: Yes

 

Here's a CFFiddle of it .

 

Of course the solution is clear: just use GetToken and be done, but I don't want to have to review all the code before the upgrade to CF 2021.

 

Any thoughts?

 

    This topic has been closed for replies.

    4 replies

    Inspiring
    February 14, 2023

    Just found this issue when testing before our official upgrade to CF2021, thanks for pointing it out.  While I appreciate that there's a JVM argument, I never saw a response from Adobe about if that would break anything internally.  I added a comment to the bug that was marked as duplicate:

    I don't think it should be possible for === to be TRUE and == to be FALSE, === should be more strict than ==. This code demonstrates the problem:

    <cfset ip = "50.5.3">

    <cfoutput>

       #Left(ip,3) === "50."#

       #Left(ip,3) == "50."#

    </cfoutput>

    Results CF2021 u5: YES NO

    Results CF2016 u15: YES YES

     

    Is there a plan to fix this?

    James Moberg
    Inspiring
    February 14, 2023

    Are you specifically comparing the first value of an IP address using this method?  I recommend using listFirst(ip,".") eq 50 and avoid the use of "===". I prefer to write code that is readable, futureproof and cross-compatible with all CFML platforms & versions.

    Inspiring
    February 14, 2023

    Agree, I changed the code and searched for other places this could happen, but I still think this is a bug that should be fixed by Adobe.  It just seems really wrong that === works and not == in this case, since === should be more strict by checking type and value.

    BKBK
    Community Expert
    Community Expert
    July 2, 2022

    Long story short: it is definitely a CF2021 bug. The bug has nothing to do with iif() or de(). 

     

    It concerns just left(). The numeric nature of "147." seems to throw ColdFusion off the string scent.

     

    Demo:

    <cfset A="147.xxx.yyy.zzz">
    <cfset B="abc.xxx.yyy.zzz">
    
    <cfoutput>	
    left(A,3) is "147":	 #left(A,3) is "147"#<br>
    left(A,4) is "147.": #left(A,4) is "147."#<br><br>
    
    left(B,3) is "abc":	 #left(B,3) is "abc"#<br>
    left(B,4) is "abc.": #left(B,4) is "abc."#<br>
    </cfoutput>

     

    Output:

    left(A,3) is "147": YES
    left(A,4) is "147.": NO

    left(B,3) is "abc": YES
    left(B,4) is "abc.": YES

     

     

    BKBK
    Community Expert
    Community Expert
    July 3, 2022

    I consider compare(), mentioned by James Moberg, and its companion, compareNoCase(), to be the most hassle-free functions to use when comparing strings.

    Charlie Arehart
    Community Expert
    Community Expert
    July 1, 2022

    Guys, I can add something here. It's not "the solution", but it's a clue. One of the little-noticed changes in CF2021 was related to strict equality matching. The docs on it offer how if one WANTS to do a strict equality conditional test, there is a new === operators, which works in the fiddle even for your good ol' cfif, not just cfscript conditionals:

     

    <CFIf Left(A,4) === '147.'>

     

     

    And result WILL be true, while either eq (as you have it) or eq will be false. I'm not exactly sure I understand why this makes a difference, but perhaps someone else will connect a dot.

     

    And of course, I realize you will not want to have to change your code to solve this. I mention this first more to help you (or anyone, or Adobe) perhaps connect the dot to what changed to make your test now fail. (It sure seems to have to do with the . in the number, so at least it's not "all" conditionals that will somehow just start activing wonky.)

     

    And I would agree 100% that a change like this should have some sort of setting to allow you to revert the behavior, if you need it, whether that's a setting in the application.cfc/cfm or in the JVM. Let's see if someone might identify if one does exist.

     

    Rather than add this comment to the tracker ticket (leading to cross-posting confusion, if people would reply to one and not the other), I will instead point there to this thread and mention briefly what I added here.

     

    (BTW, here is one other place that Adobe discussed the new feature. It doesn't add much more on this feature--but some may be tickled to see the new cfscript savecontent capability also mentioned there.)

    /Charlie (troubleshooter, carehart. org)
    James Moberg
    Inspiring
    July 2, 2022

    That's "CF2021/2018 only" syntax.  I prefer writing CFML that functions on CF2016.  (I can't even add TRY/CATCH to my test because using it it throws a parsing error when run on CF2016.)

    Any thoughts regarding ACF2021 returns different results depending on whether a variable is used versus an inline value?

    I understand the need for strict equality and I like that.  It's one of the primary versions that I explicitly cast values as you're never exactly sure what ColdFusion is identifying a string as under the hood.  The article doesn't mention "IS".  It mentions "EQ" and indicates that it the backward compatibility "equality operator was still comparing two objects by its values".

    This behavior doesn't make any sense to me.  I would consider both values on the left to be the same regardless of whether one was staticly used while the other uses an assigned variable.

    This isn't equal when using CF2021...
    left("147.xxx", 4) is javacast("string", "147.")

    But this is equal...
    myVal = "147.xxx";
    left(myVal, 4) is javacast("string", "147.")

     

    Charlie Arehart
    Community Expert
    Community Expert
    July 2, 2022

    James, first I was indeed talking about cf 2021 (only, not even 2018) since that's what Ross was dealing with. I saw your additional comments, and I appreciate your concern, but I was focused on Ross's original and primary problem.

     

    And I agree, too (as I said) that even what I foumd both doesn't make sense and seems should be able to be controlled. I have no more to offer with regard to earlier cf versions. I realize it may surprise some to hear me say I don't have more to offer, but there are simply some cf topics where I don't have enough experience with them to even hazard a guess, and I'm OK acknowledging when that's so. 🙂 

    /Charlie (troubleshooter, carehart. org)
    James Moberg
    Inspiring
    June 30, 2022

    I use TryCF.com and it didn't like the use of the DE() function, so I rewrote it and used YesNoFormat() instead.

     

     

    <cfset A = javacast("string", "147.xxx.yyy.zzz")>
    <cfoutput><pre>
    #A#---
    Left 4: #Left(A,4)#---
    Left 4 eq: #yesNoFormat(Left(A,4) eq "147.")#
    Left 4 is: #yesNoFormat(Left(A,4) is "147.")#
    Left 4 equal:  #yesNoFormat(Left(A,4) equal "147.")#
    Left 4 CFIf eq: #yesNoFormat(Left(A,4) eq "147.")#
    Mid dot: #yesNoFormat(Mid(A,4,1) eq ".")#
    Left 3 Compare: #yesNoFormat(Left(A,3) eq "147")#
    First Item in List: #yesNoFormat(GetToken(A,1,".") eq "147")#
    </pre></cfoutput>

     

     

     

    NOTE: Here's a gist in case this forum's ability to display a code preview ever becomes broken.
    https://gist.github.com/JamoCA/876e577d3f69b516d0224b03f87f9c1d

     

    Even when the original value is explicitely cast as a string (which I am required to do a lot), Adobe ColdFusion 2021 is still different than CF2016, CF2018 and Lucee 4.5 & 5. (NOTE: TryCF.com throws an error for the above code... not sure why.)

     

    James Moberg
    Inspiring
    June 30, 2022

    Using compare works, but it accepts 2 strings according to the spec. It's also true for an "is" comparison when explicitly casting "147." as a string.

    Compare: #yesNoFormat(not compare(Left(A,4), "147."))#
    Left 4 is/Cast: #yesNoFormat(Left(A,4) is javacast("string","147."))#