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 { }