While I was answering a
question
from a user last week, I saw a piece of code that, in my opinion, could be
shortened. What it does is to set two chunk options, message and warning, to
NA or FALSE according the version of the evaluate package.
setHook(packageEvent("knitr", "onLoad"),
function(...) {
message_default <- FALSE
installed <- installed.packages()
if ("evaluate" %in% rownames(installed)) {
evaluate_installed <- installed["evaluate",]
evaluate_version <- evaluate_installed[["Version"]]
evaluate_version <- package_version(evaluate_version)
if (evaluate_version == package_version("0.19")) {
message("evaluate version 0.19 is broken - there is no way to get log messages out")
}
if (evaluate_version >= package_version("0.20")) {
message_default <- NA
}
}
knitr::opts_chunk$set(message = message_default, warning = message_default)
knitr::opts_hooks$set(message = function(options) {
options$message = message_default
options$warning = message_default
options
})
})
There is nothing wrong with the code. I’d actually call it professional. For example, it carefully checks if the evaluate package is installed, finds its version number, and sets options conditionally.
My own coding style is that I prefer using shorter variable names (single
letters if possible) inside a function if the function is relatively short. I
know most programmers would frown upon single-letter
variables, but I do
not think they are that bad when the context is short—you can quickly learn
what x or y is. In a short function, you will not have many variables.
In the above example, variable names are self-explanatory, such as
evaluate_installed, evaluate_version, and message_default. I’m a little
slow to read these verbose names, though. Here is how I’d write the code:
setHook(
packageEvent('knitr', 'onLoad'),
function(...) {
v = packageVersion('evaluate')
if (v == '0.19') message(
'evaluate v0.19 is broken - there is no way to get log messages out'
)
knitr::opts_hooks$set(message = function(options) {
options$message = options$warning = if (v >= '0.20') NA else FALSE
options
})
}
)
Inside the function, the key variable is the version number, which I named v.
I wonder if it is difficult for readers to remember that v denotes the version
number. It is the only variable inside this function.
However, the length of variable names is not the main factor that affects the length of the code. The code was shortened based on some assumptions and knowledge:
- There is no need to check if evaluate was installed, because it is a hard dependency of knitr. As long as knitr is installed and can be loaded, evaluate is guaranteed to be available.
- We can get the version number from
packageVersion()instead of retrieving it frominstalled.packages(). - A version number can be compared with a string directly if the string can be
coerced to a version number (e.g.,
v == '0.19'orv >= '0.20'). There is no need to coerce it explicitly withpackage_version(). R will try to coerce the string automatically when it is compared to a version number.
If you want to further shorten the code, it is definitely possible, but I’m afraid it will become “ninja code”, e.g.,
knitr::opts_hooks$set(message = function(o) {
o$message = o$warning = v >= '0.20' && NA
o
})
The variable options was renamed to a single-letter o above, and the
expression if (v >= '0.20') NA else FALSE was changed to v >= '0.20' && NA.
The latter change may take you a few seconds to digest (hint: FALSE && NA is
FALSE, and TRUE && NA is NA).
Donate
As a freelancer (currently working as a contractor) and a dad of three kids, I truly appreciate your donation to support my writing and open-source software development! Your contribution helps me cope with financial uncertainty better, so I can spend more time on producing high-quality content and software. You can make a donation through methods below.
-
Venmo:
@yihui_xie, or Zelle:xie@yihui.name -
Paypal
-
If you have a Paypal account, you can follow the link https://paypal.me/YihuiXie or find me on Paypal via my email
xie@yihui.name. Please choose the payment type as “Family and Friends” (instead of “Goods and Services”) to avoid extra fees. -
If you don’t have Paypal, you may donate through this link via your debit or credit card. Paypal will charge a fee on my side.
-
-
Other ways:
WeChat Pay (微信支付:谢益辉) Alipay (支付宝:谢益辉) 

When sending money, please be sure to add a note “gift” or “donation” if possible, so it won’t be treated as my taxable income but a genuine gift. Needless to say, donation is completely voluntary and I appreciate any amount you can give.
Please feel free to email me if you prefer a different way to give. Thank you very much!
I’ll give back a significant portion of the donations to the open-source community and charities. For the record, I received about $30,000 in total (before tax) in 2024-25, and gave back about $15,000 (after tax).