Vim: What's the difference between let and set?
What's the difference between let
and set
in the vim editor?
I've always wondered why both of them exist?
Also, I'd be interested to hear its historical background.
Solution 1:
:set
is for setting options, :let
for assigning a value to a variable.
It happens that the value for an option is linked to the name of the option prepended by a &
(the &option-name
construct then behaves very similar to "ordinary" variables). So, the following are equivalent:
:set tw=40
:let &tw=40
But, for example, assigning 50 to the global variable foo (:let g:foo=50
) cannot be achieved with a :set
command (because g:foo is a variable and not an option).
Some options are boolean like. When setting these, no value is needed (as in :set noic
and the opposite :set ic
).
Solution 2:
Set is a more user-friendly interface specialized for options
E.g.
:verbose set
to display all options in effect.
:set tw=40
Will work as a shorthand for set textwidth=40
:set wrap&
Will set the default value for option wrap
:set nowrap
Will unset the option
:set wrap!
Will toggle the option
Most importantly,
:set
Tab # to get tab completion!
Few of the above can (easily) be achieved with let
.
Solution 3:
:set
only works with options, and sehe's answer showcases some good usage examples.
:let
on the other hand can do almost everything that :set
can do, plus more. It can assign a value to
- a variable, e.g.
let vi = 'vim'
- an option, e.g.
let &tw = 40
- a register, e.g.
let @a = $HOME . '/vimfiles'
- an environment variable, e.g.
let $NOTHING = 'NOTHING'
Another major difference is that the right hand side of :let
is an expression, meaning you can do things like string concatenation (as seen in my register example above) and arithmetic operations (e.g. let &tw = 40 + 60
). This also means that you have to quote the value if it's a string. :set
on the other hand reads the value verbatim.
It's easier to use :set
with options even though :let
can also do most of it, Here are some comparison using sehe's examples ("n/a" means no way to do it with :let
)
-
:verbose set
vs n/a (don't think there's another way to list all options) -
:set tw=40
vs:let &tw = 40
(yes, you can use the same shorthand inlet
too) -
:set wrap&
vs n/a -
:set nowrap
vs:let &wrap = 0
(for boolean options, 0 is false and 1 is true) -
:set wrap!
vs:let &wrap = !&wrap
A few more examples
- print the value of an option:
:set formatoptions?
vs:echo &formatoptions
(let
doesn't print values, unlikeset
) -
assigning to multiple options at the same time:
:set et sw=4 sts=4
vs
:let [&et, &sw, &sts] = [0, 4, 4]
set global option:
setglobal et
vslet &g:et = 1
- set local option:
setlocal et
vslet &l:et = 1
See :h :set
and :h :let
for more details
tl;dr
:set
only works with options but the syntax is much simpler. :let
works with not just options but also variables, registers, and environment variables. Unlike :set
, the right hand side of :let
is an expression.
Solution 4:
Expanding on what people have written about :let
, I've noticed that it can be used to assign a value in a variable to an option, something :set
can't do. For example, this function uses let
to assign the value in the global variable orig_tw
to the textwidth
option:
" Toggle Autowrap
" Default of 72 but can be overridden by tw settings in other vimrc files
let g:orig_tw = 72
function Toggle_autowrap_mode()
if &textwidth == 0
" Must use let instead of set here in order for g:orig_tw to be
" evaluated properly
let &textwidth = g:orig_tw
echo "Autowrap mode on tw=" . &textwidth
else
let g:orig_tw = &textwidth
set textwidth=0
echo "Autowrap mode off tw=" . &textwidth
endif
endfunction
noremap _A :call Toggle_autowrap_mode()<CR>