Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations wOOdy-Soft on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Comparisons Not Correct

Status
Not open for further replies.

stanlyn

Programmer
Sep 3, 2003
945
US
Hi,

Over the years I've run into this issue when comparing values and it is happening again. So, here I am asking you guys the big why?

Code:
lcUserID = Inputbox('Enter UserID String', 'License Server UserID', lcDecUserStr, 30000)
	
If Alltrim(lcUserID) != Alltrim(lcDecUserStr)
	Replace Setup.ls_conn_user_string With goCrypt.EncryptStringENC(lcUserID)

The value for alltrim(lcUserID) is "sa", and the value for Alltrim(lcDecUserStr) is "" (empty). I've also replaced != with <> with same incorrect results.

This is clearly not equal to each other no matter how we see it. Setting exact=on makes it show as .T. in the debugger. However, we can clearly see they are NOT equal, so why does the debugger see it differently?

Can anyone shed some light on this, as I've had this unexpected behavior over many years now.

See screenshot of debugger...

Thanks, Stanley

 
We've talked a lot here about comparing two strings. But the behaviour was probably originally designed with the FIND command in mind (FIND is the predecessor of SEEK).

With the default setting, you can FIND or SEEK a record even if you only know the first few characters of its key. With EXACT ON, you need the full key. This works in a similar way to the test for equality in regard to the length of the string, and might be part of the reason that this behaviour was implemented in the first place.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Stan,

you repeatedly say you get .T. from ""="sa", but that's never the case, neither with EXACT ON nor OFF.
Anyway, you should keep in mind nw, that the = operator does not mean what you learned in math, it does not mean that in most languages, also in .NET C# it's only for assignments and comparisons need to be done by the == operator.

If you get .T. from ""="sa" and .F. from ""<>"sa", then perhaps it's about the VFP version? Also Tamar said:
Tamar Granor said:
In SQL code (that is, using VFP's SQL commands), it doesn't matter which side is shorter; the comparison ends at the end of the shorter string

I don't know, let me verify that at any setting of ANSI and EXACT:
Code:
Clear
Create Cursor crsTest (x I)
Append Blank
Set Exact Off
Set Ansi Off
Select * from crsTest Where ""="sa" into cursor crsResult
? _tally
Set Exact On
Set Ansi Off
Select * from crsTest Where ""="sa" into cursor crsResult
? _tally
Set Exact Off
Set Ansi On
Select * from crsTest Where ""="sa" into cursor crsResult
? _tally
Set Exact On
Set Ansi On
Select * from crsTest Where ""="sa" into cursor crsResult
? _tally

This has _tally = 1 in cases where ANSI is OFF, as would be expected. I don't know about the behaviour of earlier VFP versions, though, the EXACT setting is much older than the ANSI setting. Nevertheless your example was about an IF statement/comparison and not about SQL.

Finally, if you want exact behaviour from the = operator you SET EXACT ON and SET ANSI ON, but you also loose simplicity with these setting, also this will need to be set for each datasession. Instead use the == operator.

Another use case of the "ill logic" behaviour are parameterized views, eg a view SQL like [tt]SELECT * FROM Person WHERE Firstname=?m.lcFirstname AND Lastname=?m.lcLastname[/tt] used with borth EXACT and ANSI OFF can be used for searching a person via firstname or via lastname or via both without needing three view definitions. Because when you set m.lcFirstname or m.lcLastname to the empty string you practically skip the condition, every string equals empty string.

So insteaad of SET EXACT ON use == as a solution, the same goes about ANSI ON or OFF, especially when thinking about such view parameterizations. But ANSI differs a bit, ANSI ON also doesn't do a complete comparson, so if you search Firstname="Stan" you also find "Stan ". Otherwise queries on char fields would always need padding, that's not comfortable. But with ANSI ON Firstname="" only will be true for empty Firstname fields, you can't make use of the vie parameter trick.

Most important stop thinking about = as doing what you expect and what you learned in math and accept that == is made for that. You'll get used to it in the same way as you're used to = working as both assignment operator and comparison operator depending on the context it's used in. You must have had the same discomfort about that when first learning programming. Last not least double meanings are usual in natural language in very many places, it's not impossible to comprehend and accept this, as it's so common not only in VFP. What really is special about VFP is doing the "begins with" coparisoon, not other language does that, but other languages also have different comparison operators.

Bye, Olaf.
 
Hi,

You may want throw a look into Hacker's Guide to Visual Foxpro

Set ANSI, Set Exact

These two commands do almost the same thing, but in different situations. They both control the way string comparisons are performed. SET ANSI affects SQL commands; SET EXACT affects Xbase commands.

Usage
SET ANSI ON | OFF
SET EXACT ON | OFF

Xbase started life as an interpreted language whose commands were meant to be entered interactively. In that situation, it was handy to be able to type something like SEEK "SM" and move the record pointer to the first "SMITH" (or whatever happened to be the first record starting with "SM"). It was especially convenient to be able to do similar things in FOR clauses, so you could list all the people whose names started with "S" or all the parts whose part numbers began with "124".

To make those kinds of things possible, the default behavior of the "=" operator is to compare strings only until the end of the string on the right-hand side. That is, in Xbase, "123"="12" and "Smithsonian"="Smith". But "Smith"<>"Smithsonian". Pretty weird.

SET EXACT controls this behavior. When it's OFF (the default), you get the partial comparisons. When EXACT is ON, strings have to match exactly. You can also use the "==" operator to test for exact equality. (In fact, we read "==" as "exactly equals.")

Once upon a time, the double equal sign operator wasn't optimizable, but it has been for a lot of versions already. So, we prefer to leave EXACT OFF and use the double equal sign because it's a local solution to a local problem.

SET ANSI, which also defaults to OFF, is almost the same. It affects FoxPro's SQL commands: SELECT, DELETE-SQL and UPDATE-SQL. There's one subtle difference. With SET EXACT OFF, it matters which side of the "=" is shorter. With SET ANSI OFF, it doesn't matter. The strings are compared to the end of the shorter string, whichever side it's on. So, in SQL commands, "Smithsonian"="Smith" and "Smith"="Smithsonian."

The exactly equals operator isn't as strict in SQL commands as it is in Xbase commands. Regardless of the setting of ANSI, in a SQL command, == ignores trailing blanks.

One final note: Keep in mind that the "not equals" operators, "<>" and "#", are also affected by SET EXACT and SET ANSI.

Both SET EXACT and SET ANSI are scoped to the data session.

hth

MK
 
Hi,

Now I FINALLY get it, I think?... With exact off, the debugger was stating that my "aa" <> "" was false, because no comparison was made because the right side only contained 0 characters, and because of the <>, the inverse is correct, as there is no !== ?

Now knowing that fox is not comparing the values as a whole, instead char by char, until the end of the right side.

If this is correct, then it took this last read thru mjcmkrsr post for it to make sense, and coupled with all the other posts and the word "weird" showing up in many of those posts.

Such a long thread, for such a simple question, (I thought)...

Thanks to all, as this is really good reference for someone like me that has battled this over the years...

Stanley
 
>as there is no !== ?
Well, that's not the reason, but the result of <> is simply the negated result of the = operator.

In my first answer I already said:
myself said:
You always have the have same thoughts for = and <>, as <> simply is the negated result of the = operator.

You can replace = with == (outside of SQL) but you can't replace <> with !==, that operator (!==) is not existing, instead you need to use NOT in conjunction with == as in NOT a==b to have an exact version of the <> or != or # operator not depending on the EXACT setting.

[tt]a<>b[/tt] and [tt]a!=b[/tt] (and [tt]a#b[/tt]) is the same as [tt]NOT a=b[/tt] (therefore the behaviour of = is inherited in the <> and != and # operators)
[tt]a=b[/tt] can be made exact by doing [tt]a==b[/tt] instead
[tt]a<>b[/tt] can't be made exact withg [tt]a<<>>b or a!==b[/tt] as these operators do not exist, but there is an alternative - you can do [tt]NOT a==b[/tt] as exact version of [tt]a<>b[/tt]

And that was what Vilhelm-Ion already proposed in his first answer. You just had no explanation of why.

Bye, Olaf.

PS: You might also not yet know ! is the same as NOT, so != is shorthand notation for NOT= or a!=b is shorthand for NOT a=b, which can be "translated" to NOT a==b.
 
To expand on Mike Lewis' reference to FIND and SEEK, SET EXACT ON|OFF is one of two important settings that affects those search methods. The other is SET NEAR ON|OFF, we set to OFF if we don't want a failed search to jump to EOF.

When searching portions of an index expression SEEK, and based on the desired behavior, I often reverse these two values to:
Code:
SET EXACT OFF
SET NEAR ON
 
as there is no !==

But there is a comparable:
Code:
[b]!("aa" == "")[/b]
which works regardless of the SET EXACT setting.

Example:
Code:
?SET("EXACT")
m.TstStr1 = "aa"
m.TstStr2 = ""
?m.tststr1 <> m.tststr2
?!(m.tststr1 == m.tststr2)

The other contributing factors can be unexpected additional spaces and (especially if user's input the data) is Case.
Therefore, to eliminate those possible issues, I often use:
Code:
m.FirstString = "aa"
m.NextString = "Aa  "
?!(ALLTRIM(UPPER(m.FirstString)) == ALLTRIM(UPPER(m.NextString)))

Good Luck,
JRB-Bldr





 
But there is a comparable:

!("aa" == "")

which works regardless of the SET EXACT setting.

True. But isn't that because of the double equals? In just the same way that [tt]"aa" == ""[/tt] workds regardless of SET EXACT. If you change the double equals to single equals, then the expression is indeed sensitive to EXACT.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Yes, JRB-Bldr, or NOT a==b, as said. And yes, that's because of == being the exact comparison. It's a less obvious conversion coming from <> than converting = with ==, it's easier to see, if you come from using # or != beforehand, as those translate to not equal rather than <> translates to unequal in reading the code. There is no need for <<>> or !== operators, as we can do !a==b or NOT a==b. There also is no need for #, != or <>, as they all could be written NOT a=b, but it's more convenient to have these oparators, especially if a and b are lengthy expressions you'll hardly see the conjunction with NOT.

Bye, Olaf.

 
As an aside, I always use [tt]NOT[/tt] rather than [tt]![/tt]. For me, the trivial amount of extra typing far outweighs the improved readability: the word NOT means exactly the same as it does in English, whereas an exclamation mark has no logical connection with the concept of negation.

But that's just my opinion, borne on years of habit. I don't suggest others should necessarily do the same.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Very true, I don't know in which language the meaning of the exclamation mark as NOT operator originated, perhaps C. I would say it comes from !=, as a way of writing the character [math]\ne[/math] and separating ! from this as unary NOT operator lead to this meaning. It must be quite old, as |= would be closer to it, visually, but the pipe symbol most probably came in later, also | and & or || and && rather have the meaning of OR and AND, so | also already has the OR meaning.

I prefer the english terms, but nevertheless have often used the exclamation mark in code, too.

Bye, Olaf.
 
Wonder why # never became "exactly not equal"? Or has it?

I've been using the <>, !=, =, .not. and == for years. The unpredictability issues I've had over the years with this really comes down to not understanding how the comparisons were being made. This thread has put that to rest... And thanks to all...

Stanley
 
VFP likes to have three of a kind, it seems, # is nothing else but <> and !=, it visually resembles a double striked equal sign, so you could take it for "really not equal". It could also mean not not equal, which would make it equal, though. Joking aside, no there is nothing but == on matter of exactness. You even have problems on getting an exact > when EXACT is OFF, eg try "aa">"a".

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top