Skip to content

allow optional programmer discretion on chain length/function arguments per line #4306

Open
@bcantrill

Description

@bcantrill

When lines hit max_width (or its derivatives), rustfmt will break chains and function calls with one call or argument per line. We have found this to result in code that is less clear, and no more consistent with Rust's style than the code that it replaces. We would like to see an option whereby these chains and function calls would be left to programmer discretion as long as they observe the constraints of indentation and max_width.

To make this more concrete, we have experienced this most recently in the embedded Rust world, where hardware-abstracting crates make extensive use of types to constrain context (viz. svd2rust's API).

The upshot of this is that we end up with long chains that are asymmetric in that different positions in the chain actually denote different states. Often, the programmer will use the line break to help clarify what's going on; some (real) examples:

fn func() {
    p.RCC.pllcfgr.modify(|_, w| {
        w.pll1vcosel().wide_vco()
            .pll1rge().range8()
            .divp1en().enabled()
            .divq1en().enabled()
            .divr1en().enabled()
    });

    p.RCC.d1cfgr.write(|w| {
        w.d1cpre().div1()
            .d1ppre().div1()
            .hpre().div1()
    });
}

In this case, the programmer has clearly grouped the chain to indicate the type states -- and to the reader, both uses are clear. rustfmt, however, doesn't like either of these expressions; they get reformatted as:

fn func() {
    p.RCC.pllcfgr.modify(|_, w| {
        w.pll1vcosel()
            .wide_vco()
            .pll1rge()
            .range8()
            .divp1en()
            .enabled()
            .divq1en()
            .enabled()
            .divr1en()
            .enabled()
    });

    p.RCC
        .d1cfgr
        .write(|w| w.d1cpre().div1().d1ppre().div1().hpre().div1());
}

In both cases, meaning has been lost -- even though the code as written is consistent with Rust's style. We can of course wrap these constructs in #[rustfmt skip] -- but they come up often enough that we would very much rather fix it in rustfmt. And to be clear, we don't want these to be compressed either (as raised in #4146 and #2010); we seek to have them be optionally left to the programmer's discretion, within the bounds of the configured style.

Thank you in advance for your consideration and your work on this essential (if underappreciated!) part of the Rust ecosystem!

cc: @cbiffle @steveklabnik @davepacheco @ahl

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions