From e4d94715702b8a4e60fbb9fe29cac5d285a75be9 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Sat, 24 Jul 2021 07:37:26 -0700 Subject: [PATCH 1/4] style guide: discourage infix plus minor assorted copyedits --- _style/declarations.md | 11 ++++++----- _style/method-invocation.md | 25 +++++++++++++++++-------- _style/types.md | 2 +- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/_style/declarations.md b/_style/declarations.md index 85bcd995b4..06fbfadcb7 100644 --- a/_style/declarations.md +++ b/_style/declarations.md @@ -13,7 +13,7 @@ next-page: control-structures ## Classes -Class/Object/Trait constructors should be declared all on one line, +Class, object, and trait constructors should be declared all on one line, unless the line becomes "too long" (about 100 characters). In that case, put each constructor argument on its own line with [trailing commas](https://docs.scala-lang.org/sips/trailing-commas.html#motivation): @@ -102,7 +102,7 @@ Local methods or private methods may omit their return type: #### Procedure Syntax -Avoid the procedure syntax, as it tends to be confusing for very little gain in brevity. +Avoid the (now deprecated) procedure syntax, as it tends to be confusing for very little gain in brevity. // don't do this def printBar(bar: Baz) { @@ -160,7 +160,7 @@ or is of a non-functional nature (some mutable state, local or otherwise), the body must be enclosed in braces: def sum(ls: List[String]): Int = { - val ints = ls map (_.toInt) + val ints = ls.map(_.toInt) ints.foldLeft(0)(_ + _) } @@ -197,7 +197,8 @@ There are three main reasons you should do this: Multiple parameter lists allow you to create your own "control structures": - def unless(exp: Boolean)(code: => Unit): Unit = if (!exp) code + def unless(exp: Boolean)(code: => Unit): Unit = + if (!exp) code unless(x < 5) { println("x was not less than five") } @@ -223,7 +224,7 @@ There are three main reasons you should do this: List("").foldLeft(0, (b: Int, a: String) => b + a.length) List("").foldLeft[Int](0, _ + _.length) -For complex DSLs, or with type-names that are long, it can be difficult +For complex DSLs, or with type names that are long, it can be difficult to fit the entire signature on one line. For those cases there are several different styles in use: diff --git a/_style/method-invocation.md b/_style/method-invocation.md index 861d07dba6..99bde92259 100644 --- a/_style/method-invocation.md +++ b/_style/method-invocation.md @@ -51,7 +51,7 @@ acceptable to omit parentheses when calling `queue.size`, but not when calling `println()`. This convention mirrors the method declaration convention given above. -Religiously observing this convention will *dramatically* improve code +Religiously observing this convention will dramatically improve code readability and will make it much easier to understand at a glance the most basic operation of any given method. Resist the urge to omit parentheses simply to save two characters! @@ -92,25 +92,34 @@ gray area is short, operator-like methods like `max`, especially if commutative: // fairly common a max b -Symbolic methods which take more than one parameter (they do exist!) -may still be invoked using infix notation, delimited by spaces: +Symbolic methods which take more than one parameter are discouraged. +When they exist, they may still be invoked using infix notation, delimited by spaces: foo ** (bar, baz) Such methods are fairly rare, however, and should normally be avoided during API -design. For example, the use of the `/:` and `:\` methods should be avoided in +design. For example, the use of the (now deprecated) `/:` and `:\` methods should be avoided in preference to their better-known names, `foldLeft` and `foldRight`. ### Higher-Order Functions -As noted, methods which take functions as parameters (such as `map` or -`foreach`) should be invoked using infix notation. It is also *possible* to -invoke such methods in the following way: +Invoking higher-order functions may use parens or braces, but in +either case, use dot notation: + + names.map{ _.toUpperCase } + +Not infix: + + // wrong! + names map { _.toUpperCase } + +Any space after the method name should be omitted. Though it is +possible to invoke such methods in the following way, // wrong! names.map { _.toUpperCase } -This style is *not* the accepted standard! The reason to avoid this style is for +this is not the accepted standard! The reason to avoid this style is for situations where more than one invocation must be chained together: // wrong! diff --git a/_style/types.md b/_style/types.md index 87b9a1eb3d..67df05af71 100644 --- a/_style/types.md +++ b/_style/types.md @@ -38,7 +38,7 @@ Function values support a special case of type inference which is worth calling out on its own: val ls: List[String] = ... - ls map (str => str.toInt) + ls.map(str => str.toInt) In cases where Scala already knows the type of the function value we are declaring, there is no need to annotate the parameters (in this case, From 6ab2d76a5a4c36abdff0f860f78a75bf3c0dec39 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Sat, 24 Jul 2021 07:46:10 -0700 Subject: [PATCH 2/4] further adjust infix language --- _style/method-invocation.md | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/_style/method-invocation.md b/_style/method-invocation.md index 99bde92259..f8851c3452 100644 --- a/_style/method-invocation.md +++ b/_style/method-invocation.md @@ -104,32 +104,16 @@ preference to their better-known names, `foldLeft` and `foldRight`. ### Higher-Order Functions Invoking higher-order functions may use parens or braces, but in -either case, use dot notation: +either case, use dot notation and omit any space after the method name: names.map{ _.toUpperCase } -Not infix: +These are not recommended: // wrong! names map { _.toUpperCase } - -Any space after the method name should be omitted. Though it is -possible to invoke such methods in the following way, - // wrong! names.map { _.toUpperCase } -this is not the accepted standard! The reason to avoid this style is for -situations where more than one invocation must be chained together: - - // wrong! - names.map { _.toUpperCase }.filter { _.length > 5 } - - // right! - names map { _.toUpperCase } filter { _.length > 5 } - -Both of these work, but the former can easily lead to confusion. The -sub-expression `{ _.toUpperCase }.filter` when taken in isolation looks like we -are invoking the `filter` method on a function value. However, we are actually -invoking `filter` on the result of the `map` method, which takes the function -value as a parameter. +Experience has shown that these styles make code harder to read, +especially when multiple such method calls are chained. From ef43f6ecc5695b1bee6f6e847f35d7f9575d8764 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Sat, 24 Jul 2021 08:02:21 -0700 Subject: [PATCH 3/4] more infix adjustments --- _style/method-invocation.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/_style/method-invocation.md b/_style/method-invocation.md index f8851c3452..612b6554d1 100644 --- a/_style/method-invocation.md +++ b/_style/method-invocation.md @@ -106,14 +106,14 @@ preference to their better-known names, `foldLeft` and `foldRight`. Invoking higher-order functions may use parens or braces, but in either case, use dot notation and omit any space after the method name: - names.map{ _.toUpperCase } + names.map(_.toUpperCase) These are not recommended: - // wrong! - names map { _.toUpperCase } - // wrong! - names.map { _.toUpperCase } + // wrong! missing dot + names map (_.toUpperCase) + // wrong! extra space + names.map (_.toUpperCase) Experience has shown that these styles make code harder to read, especially when multiple such method calls are chained. From 33389ae1b5ed4970fc3168e7c454f4f95c9a178c Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Tue, 27 Jul 2021 14:17:05 -0700 Subject: [PATCH 4/4] one final style guide tweak based on review feedback from Bjorn --- _style/method-invocation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_style/method-invocation.md b/_style/method-invocation.md index 612b6554d1..eb1e548785 100644 --- a/_style/method-invocation.md +++ b/_style/method-invocation.md @@ -51,7 +51,7 @@ acceptable to omit parentheses when calling `queue.size`, but not when calling `println()`. This convention mirrors the method declaration convention given above. -Religiously observing this convention will dramatically improve code +Observing this convention improves code readability and will make it much easier to understand at a glance the most basic operation of any given method. Resist the urge to omit parentheses simply to save two characters!