chapters/22.markdown @ a16e1fecfe07 default tip

Be clear
author Steve Losh <steve@stevelosh.com>
date Mon, 27 Mar 2017 13:10:55 +0000
parents f09f87e10570
children (none)
Comparisons
===========

We've gone over conditionals, but `if` statements aren't very useful if we can't
compare things.  Of course Vim lets us compare values, but it's not as
straightforward as it may seem.

Run the following commands:

    :::vim
    :if 10 > 1
    :    echom "foo"
    :endif

Vim will, of course, display `foo`.  Now run these commands:

    :::vim
    :if 10 > 2001
    :    echom "bar"
    :endif

Vim displays nothing, because `10` is not greater than `2001`.  So far
everything works as expected.  Run these commands:

    :::vim
    :if 10 == 11
    :    echom "first"
    :elseif 10 == 10
    :    echom "second"
    :endif

Vim displays `second`.  Nothing surprising here.  Let's try comparing strings.
Run these commands:

    :::vim
    :if "foo" == "bar"
    :    echom "one"
    :elseif "foo" == "foo"
    :    echom "two"
    :endif

Vim echoes `two`.  There's still nothing surprising, so what was I going on
about at the beginning of the chapter?

Case Sensitivity
----------------

Run the following commands:

    :::vim
    :set noignorecase
    :if "foo" == "FOO"
    :    echom "vim is case insensitive"
    :elseif "foo" == "foo"
    :    echom "vim is case sensitive"
    :endif

Vim evaluates the `elseif`, so apparently Vimscript is case sensitive.  Good to
know, but nothing earth-shattering.  Now run these commands:

    :::vim
    :set ignorecase
    :if "foo" == "FOO"
    :    echom "no, it couldn't be"
    :elseif "foo" == "foo"
    :    echom "this must be the one"
    :endif

**Whoa**.  Stop right there.  Yes, you saw that right.

**The behavior of `==` depends on a user's settings.**

I promise I'm not messing with you.  Try it again and see.  I'm not kidding,
I can't make this stuff up.

Code Defensively
----------------

What does this mean?  It means that you can *never* trust the `==` comparison
when writing a plugin for other people to use.  A bare `==` should *never*
appear in your plugins' code.

This idea is the same as the "`nmap` versus `nnoremap`" one.  *Never* trust your
users' settings.  Vim is old, vast, and complicated.  When writing a plugin you
*have* to assume that users will have every variation of every setting.

So how can you get around this ridiculousness?  It turns out that Vim has *two
extra sets* of comparison operators to deal with this.

Run the following commands:

    :::vim
    :set noignorecase
    :if "foo" ==? "FOO"
    :    echom "first"
    :elseif "foo" ==? "foo"
    :    echom "second"
    :endif

Vim displays `first` because `==?` is the "case-insensitive no matter what the
user has set" comparison operator.  Now run the following commands:

    :::vim
    :set ignorecase
    :if "foo" ==# "FOO"
    :    echom "one"
    :elseif "foo" ==# "foo"
    :    echom "two"
    :endif

Vim displays `two` because `==#` is the "case-sensitive no matter what the user
has set" comparison operator.

The moral of this story is that you should *always* use explicit case sensitive
or insensitive comparisons.  Using the normal forms is *wrong* and it *will*
break at some point.  Save yourself the trouble and type the extra character.

When you're comparing integers this distinction obviously doesn't matter.
Still, I feel that it's better to use the case-sensitive comparisons everywhere
(even where they're not strictly needed), than to forget them in a place that
they *are* needed.

Using `==#` and `==?` with integers will work just fine, and if you change them
to strings in the future it will work correctly.  If you'd rather use `==` for
integers that's fine, just remember that you'll need to change the comparison if
you change them to strings in the future.

Exercises
---------

Play around with `:set ignorecase` and `:set noignorecase` and see how various
comparisons act.

Read `:help ignorecase` to see why someone might set that option.

Read `:help expr4` to see all the available comparison operators.