Refactoring code with flir

A short description of the post.


Author

Affiliation

Etienne Bacher

 

Published

May 23, 2025

Citation

Bacher, 2025


Slightly less than a year ago, I created flir (named flint at the time). The objective was to have a tool to detect and automatically correct a set of “bad practices” in R code. Those “bad practices” do not necessarily mean the code is wrong, simply that it is possible to improve its readability, robustness, and performance. If you are already familiar with lintr, you could think of flir as an extension that is faster and apply automatic fixes (at the expense of not having coverage of the entire set of lintr’s rules).

Detecting and fixes bad practices

flir provides 3 types of functions: linter functions, fixer functions, and helper functions:

You might be worried about this “automatic fixing” feature. After all, what if the fix is wrong? What if I want to go back to the previous situation? In this case, you should read this vignette on the website that details a couple of actions you can take to be more confident about this.

I won’t repeat the package documentation and examples here. Rather, I’d like to explain how flir allows one to go further fixing “bad practices” and can be helpful when refactoring projects.

flir can rewrite (almost) anything

Originally, flir was created to be an extension of lintr, but it can do more than that. flir works by detecting specific code patterns (some examples below) and rewriting them using the Rust crate ast-grep. This isn’t limited to linter rules, it can be applied to any R code.

Let’s take an example.

dplyr contains several functions marked as “deprecated” or “superseded”. Deprecated means that those functions will be removed in a later version of the package because they have some weaknesses that cannot be easily fixed or because there are alternative functions that are always better to use. Those functions are not supported anymore, meaning that bugs won’t be fixed anymore so you should update your code if you use them. Superseded means that the function still works and is still supported in terms of fixing bugs, but there are better alternatives that are more performant or readable for instance.

Let’s say we have several occurrences of dplyr::sample_n() in our project. This function is superseded and we should use slice_sample() instead. First, after installing flir, we can create a flir folder with flir::setup_flir(). Then we add a new rule with flir::add_new_rule("superseded-sample-n).

This creates the file below (flir/rules/custom/superseded-sample-n.yml):

Footnotes

    Corrections

    If you see mistakes or want to suggest changes, please create an issue on the source repository.

    Reuse

    Text and figures are licensed under Creative Commons Attribution CC BY 4.0. Source code is available at https://github.com/etiennebacher/personal_website_distill, unless otherwise noted. The figures that have been reused from other sources don't fall under this license and can be recognized by a note in their caption: "Figure from ...".

    Citation

    For attribution, please cite this work as

    Bacher (2025, May 23). Etienne Bacher: Refactoring code with `flir`. Retrieved from https://www.etiennebacher.com/posts/2025-05-23-refactoring-code-with-flir/

    BibTeX citation

    @misc{bacher2025refactoring,
      author = {Bacher, Etienne},
      title = {Etienne Bacher: Refactoring code with `flir`},
      url = {https://www.etiennebacher.com/posts/2025-05-23-refactoring-code-with-flir/},
      year = {2025}
    }