Skip to content

style guide: revise sections on infix and postfix notation #716

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 2, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 40 additions & 79 deletions style/method-invocation.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,104 +54,65 @@ 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!

### Suffix Notation
## Infix notation

Scala allows methods of arity-0 to be invoked using suffix notation:
Scala has a special punctuation-free syntax for invoking methods that
take one argument. Many Scala programmers use this notation for
symbolic-named methods:

names.toList

// is the same as

names toList // Unsafe, don't use!

This style is unsafe, and should not be used. Since semicolons are
optional, the compiler will attempt to treat it as an infix method
if it can, potentially taking a term from the next line.

names toList
val answer = 42 // will not compile!

This may result in unexpected compile errors at best, and happily
compiled faulty code at worst. Although the syntax is used by some
DSLs, it should be considered deprecated, and avoided.
// recommended
a + b

As of Scala 2.10, using suffix operator notation will result in a compiler warning.
// legal, but less readable
a+b

## Arity-1
// legal, but definitely strange
a.+(b)

Scala has a special syntax for invoking methods of arity-1 (one
argument):
but avoid it for almost all alphabetic-named methods:

// recommended
names.mkString(",")

// is the same as

names mkString ","

This syntax is formally known as "infix notation". It should *only* be
used for purely-functional methods (methods with no side-effects) - such
as `mkString` -or methods which take functions as parameters - such as
`foreach`:

// right!
names foreach (n => println(n))
// also sometimes seen; controversial
names mkString ","
optStr getOrElse "<empty>"

// wrong!
javaList add item

### 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:

names.map (_.toUpperCase) // wrong!

This style is *not* the accepted standard! The reason to avoid this
style is for situations where more than one invocation must be chained
together:
A gray area is short, operator-like methods like `max`,
especially if commutative:

// wrong!
names.map (_.toUpperCase).filter (_.length > 5)
// fairly common
a max b

// right!
names map (_.toUpperCase) filter (_.length > 5)
Symbolic methods which take more than one parameter (they do exist!)
may still be invoked using infix notation, delimited by spaces:

Both of these work, but the former exploits an extremely unintuitive
wrinkle in Scala's grammar. The sub-expression
`(_.toUpperCase).filter` when taken in isolation looks for all the
world 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. This syntax is
confusing and often discouraged in Ruby, but it is shunned outright in
Scala.
foo ** (bar, baz)

## Symbolic methods/Operators
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 preference to their better-known names,
`foldLeft` and `foldRight`.

Methods with symbolic names should *always* be invoked using infix
notation with spaces separating the target, the symbolic method and the
parameter:
## Postfix Notation

// right!
"daniel" + " " + "Spiewak"
Scala allows methods that take no arguments to be invoked using postfix notation:

// wrong!
"daniel"+" "+"spiewak"
// recommended
names.toList

For the most part, this idiom follows Java and Haskell syntactic
conventions.
// discourage
names toList

Symbolic methods which take more than one parameter (they do exist!)
should still be invoked using infix notation, delimited by spaces:
This style is unsafe, and should not be used. Since semicolons are
optional, the compiler will attempt to treat it as an infix method
if it can, potentially taking a term from the next line.

foo ** (bar, baz)
names toList
val answer = 42 // will not compile!

Such methods are fairly rare, however, and should be avoided during API
design.
This may result in unexpected compile errors at best, and happily
compiled faulty code at worst. Although the syntax is used by some
DSLs, it should be considered deprecated, and avoided.

Finally, the use of the `/:` and `:\` should be avoided in preference to
the more explicit `foldLeft` and `foldRight` method of `Iterator`. The
right-associativity of the `/:` can lead to extremely confusing code, at
the benefit of saving a few characters.
Since Scala 2.10, using postfix operator notation will result in a
compiler warning.