4

What is the difference between == and is; ==# and is#; ==? and is? when checking whether or not two strings are equal? Sometimes I see foo is# 'bar', and I wonder whether or not it is always equivalent to foo ==# 'bar'.

4

While I was pretty sure the answer was "they are identical" I was only 99% sure so...I checked the code.

Function eval4() in eval.c is the entry point for "expr4" operations, i.e. comparisons (==, <=, is, !=, isnot, etc.) This function sets up the two values to compare and then calls typval_compare() in typval.c for the actual comparison.

At the end of typval_compare() is an else block that is reached if the types being compared don't match non-string types (boolean, dictionary, list, etc).

All the "expr4" string comparison operations occur in this block and they all use this line (the ic is case-sensitivity flag):

    i = ic ? MB_STRICMP(s1, s2) : STRCMP(s1, s2);

Translation: is and == will always have the same result when comparing strings; same holds true for the "match case" and "ignore case" variants: is# and ==#, is? and ==?.

This is consistent with the docs which say...

When comparing two Strings, this is done with strcmp() or stricmp().

Bonus material

The question only refers to String vs String comparisons and there's not much more to say about that. But when we bring types other than String into play some interesting differences between is and == arise. I figured they're worth mentioning here.

Given the above, are there any practical differences between == and is and friends?

Well, one big difference is seen when comparing non-alike types, particularly Numbers and Strings. With is, "a different type means the values are different". But with == there's a type conversion before comparison. Specifically...

When comparing a String with a Number, the String is converted to a Number, and the comparison is done on Numbers.

(Source :h expr-==, about 60 lines down)

To demonstrate:

let v1 = 4
let v2 = '4'
echo v1 == v2    " true
echo v1 is v2    " false

That's pretty straightforward but check this out...

let v = 0
echo v == "foo"    " true...and potentially confusing
echo v is "foo"    " false

What's going on here? It's Vim's conversion rules. Strings containing no numbers get converted to the number zero. Thus, echo v == "foo" is equivalent to echo v == 0 and has a "true" result, i.e. 1. If, instead, we used let v = 1 (or any other non-zero number) the result would be "false" for both == and is.

One conclusion that can be drawn from this is that if you're comparing something to a string and you don't know its type the safer bet is to use is rather than ==.

Finally, and straying far afield from string comparison but possibly of interest to folks...

is et al. check for "instance" equality and so will tell you if two variables reference the same List, Dictionary or Blob instance. == will check for value equality.

let b1 = [1,2,3]
let b2 = [1,2,3]
let b3 = b1

echo b1 == b2   " true
echo b1 == b3   " true
echo b1 is b2   " false
echo b1 is b3   " true
6
  • This answer avoids the question of why someone would use is on a string: e.g., echo 1 == '1' 1 is '1' '1' is '1' (Number vs String). Incidentally, I guess the help is slightly wrong in that stricmp is not used but a multibyte capable variant, meaning vim tries to localize the lowercase somewhat.
    – Mass
    Oct 25 at 4:22
  • @Mass I don't understand your point. 1 is not a string. The question says nothing about comparing non-string types. (And I'm fully aware that is and == differ when comparing non-like types like 1 == '1' vs 1 is '1'.)
    – B Layer
    Oct 25 at 4:25
  • As a matter of fact, I misread the question at first and my first answer (look at the edits) was about differences between is and ==. Then I realized that the question wasn't about that at all! It's about string vs string only.
    – B Layer
    Oct 25 at 4:30
  • Fair point, OP can clarify. But my comment was about let's say you have a variable foo and want to check that a) it's a string and b) it's equal to bar. foo is "bar" succinctly expresses that, whereas foo == "bar" does not. E.g., let foo = 0 | echo foo == "bar" yields 1.
    – Mass
    Oct 25 at 4:33
  • "For checking equality of strings" and "when checking whether two strings are equal" is pretty cut and dry, IMO, but if OP says they're also interested in the concept you mentioned then I'm happy to expand my answer. (OTOH, the docs are pretty explicit about that topic while a little less exact about OPs question. I was only 99% sure about my conclusion until I checked the code.)
    – B Layer
    Oct 25 at 4:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.