Thursday, August 6, 2020

First Impressions of Rust

rustdoc

I categorize documentation generators into two basic groups:

  • First is the Sphinx group, which consumes prose and uses embedded pragmas to reference symbols of the library being documented. The output layout tends to be textbook-like, containing long "chapters" that might cover entire modules in one HTML file. Sphinx-style docs are popular among Python programmers.
  • Second is the Doxygen group, which consumes source code and generates a rigidly-structured catalog of symbols with optional attached prose. The output feels more like an encyclopedia or reference manual.

rustdoc is obviously in the second category. It is designed to consume doc comments, which are special-cased by the Rust compiler, and produces output closely matching the structure of the exported API. At this task rustdoc does a reasonable job: the page layout is navigable, the markup format (rustdoc uses Markdown) isn't great but it could be worse, and it doesn't hardcode absolute file paths into the output like Haddock.

Some of its annotations, like whether a symbol is OS-specific (rust-lang/rust#43781), are gated to the Nightly toolchain. It's not obvious to me why they do this – it's a documentation generator, why does it care what version of the Rust compiler I'm using? What's more, some of its functionality is reserved for the standard library only. I can't mark fields as unstable (subject to change in future library versions) because that annotation is based on the #[unstable] attribute, which the compiler reserves for its own use. Ditto for annotations about which version a symbol was added in. If I'm going to use a Doxygen-group tool then I don't want it to get too fussy about what libraries it's documenting.

rustfmt

Something like a cross between gofmt, clang-format, and GNU indent. It has a lot of configuration options but all the interesting ones are gated to Nightly, and most of those are much less useful than you might expect.

As a representative sample, consider rustfmt's handling of hard tabs. Given the following input there are two basic ways you might use hard tabs to indent it, depending on whether struct value alignment should apply to nested structs:

MyStruct{
  field_with_long_name: (some_big_complex_variable_name + another_big_complex_variable_name),
  another_field: 123,
  nested_struct: &NestedStruct{
    nested_struct_field: 456,
  },
  final_field: 123,
}

The first is to treat the nested struct as a "break" in the alignment (gofmt does this). I've drawn the tabs as ████ for clarity:

MyStruct{
████field_with_long_name: (some_big_complex_variable_name
████                       + another_big_complex_variable_name),
████another_field:        123,
████nested_struct: &NestedStruct{
████████nested_struct_field: 456,
████},
████final_field: 123,
}

The second is to align all the values, including the nested struct, and introduce a nested layer of tabs:

MyStruct{
████field_with_long_name: (some_big_complex_variable_name
████                       + another_big_complex_variable_name),
████another_field:        123,
████nested_struct:        &NestedStruct{
████                      ████nested_struct_field: 456,
████                      },
████final_field:          123,
}

But what rustfmt produces is an indecisive and poorly formatted combo of the two – it doesn't even properly align the parenthesized expression after line-breaking it:

MyStruct {
████field_with_long_name: (some_big_complex_variable_name
████████+ another_big_complex_variable_name),
████another_field:        123,
████nested_struct:        &NestedStruct {
████████nested_struct_field: 456,
████},
████final_field:          123,
}

I eventually gave up on trying to make the formatted rust-fuse code look pretty, and settled for "consistent".



from Hacker News https://ift.tt/33CyDEC

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.