I would like to add my thoughts to the ongoing style discussion, for i sadly lack the technical expertise to contribute in a more meaningful way, but would love to help nevertheless.
After comparing some style-guides (linux, gnu, K&R, âŚ) for curly braced languages like C, JavaScript, etc., and some common typographic practices i tried some variations and found some (imho) reasonable and readable solutions.
Most trivial functions (no arguments, no return value):
fn trivial() {
// no arguments, no return value -> K&R style as for control blocks
// function comments "python style" between function-"head" and -"body"
}
Simple functions (few arguments, no return value)
fn simple(arg1:u8, arg2:u8)
{
// arguments or return value -> K&R style for functions (as linux kernel)
//
// arguments on same line separated by comma+space, therefore no space
// between colon and type, to improve semantic visual contrast;
}
Regular function (few arguments, return value)
fn regular(arg1:u8, arg2:u8)
-> u8
{
// return value on separate line with same identation as function head
// rational: visual pattern allows direct association of name and type
}
Irregular long argument-list (factory function, etc.)
fn many_arguments(
arg1: u8, // incredible amount of space for comments for every ...
arg2: u8, // ... variable (but there's never enough)
...
argn: u8
)
-> u8
{
// argument identifiers are now in the same column as the function
// identifier, but it's still unmistakably clear that they are argument
// identifiers because of the leading whitespace.
// the closing parenthesis of the argument list gets its own line to
// visually segregate the argument list from the return type
// the opening brace is a strong visual pattern to separate function-head
// from function-body
// a logical conclusion of this style is, that a tab-width of
// three spaces *gasp*, *Blasphemy!* seems logical. It's clearly an
// unorthodox choice, but i found it quite easy on the eyes. And except
// breaking tradition i found no reasonable argument against three spaces.
}
Regular function with generic types
fn generics <T, U, V> (
a: &T,
b: &U
)
-> V
{
// function with generic types should add the generics on the same line,
// followed by the opening argument parenthesis and a newline with the
// short or long argument-list rules.
// "first-glance" rule reads:
// glance 1: "Generic function named 'generics' with 3 generic types."
// glance 2: "Return type is the generic type 'V' ."
// glance 3: "Two arguments."
// glance 4: "First argument 'a' with generic type 'T'."
// glance 5: "Second argument 'b' with generic type 'U'."
}
Short version:
fn generics_short <T> (
a:&T, b:u8)
{
// example of a short generic function.
}
Principles:
- do one thing per line or use perl
- try to stay inside typographic 60 glyphs per line, which is the suggested column width for e.g. newspapers.
- create visual patterns to facilitate easy semantic readings (e.g. function name and associated return value in same column)
- visually segregate unassociated units and couple associated units (e.g. no space between name and type in an one-line argument-list to improve visual distinction between arguments)
- try to uphold the âfirst-glanceâ rule: the reader should discern every line as one semantic/logical unit without the need to parse it, which essentially means reading it multiple times and searching for start and stop delimiters of every semeantic part. (e.g.: âWhere does the generic type list end, where are the arguments, where is the return type?â)
Example on servo-code:
original:
pub extern "C" fn android_start(argc: int, argv: **u8) -> int {
..
}
vs âfirst-glance-styleâ:
pub extern "C"
fn android_start(argc:int, argv:**u8)
-> int
{
..
}
Off-topic i would argue to separate function-prefixes like pub
and extern
on a separate line, like python decorators.:
pub extern "C"
fn many_arguments(
arg1: u8, // incredible amount of space for comments per variable
arg2: u8, // you can either use incredible long meaningful identifiers
...
argn: u8 // or write useful comments
)
-> u8
{
}