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'
.
1 Answer
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
-
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 thatstricmp
is not used but a multibyte capable variant, meaning vim tries to localize the lowercase somewhat.– MassCommented Oct 25, 2021 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 thatis
and==
differ when comparing non-like types like1 == '1'
vs1 is '1'
.)– B LayerCommented Oct 25, 2021 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 LayerCommented Oct 25, 2021 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, whereasfoo == "bar"
does not. E.g.,let foo = 0 | echo foo == "bar"
yields 1.– MassCommented Oct 25, 2021 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 LayerCommented Oct 25, 2021 at 4:46