Scala 3: Infix Operator Notation

Dean Wampler
Scala 3
Published in
3 min readMar 28, 2021

For a long time, Scala has supported a useful “trick” called infix operator notation. If a method takes a single argument, you can call it without the period after the instance and without parentheses around the argument. This post describes changes in Scala 3.

Spring Equinox Sunset, Ohio St. Chicago, ©2021, Dean Wampler, All Rights Reserved

For example, if I have a Matrix class and a + method to add matrices, element by element, I can write matrix1.+(matrix2) or use the less cluttered and more intuitive syntax, matrix1 + matrix2. The intention was to support true operators, like + in intuitive contexts like this. However, there was no restriction on what methods applied in Scala 2, so if I also had a plus method, then matrix1 plus matrix2 was allowed.

Used judiciously, this is fine, but dropping the punctuation occasionally makes the expressions ambiguous for the compiler or worse, for the reader. Hence Scala 3 is tightening the rules a bit to encourage more limited use.

Let’s revisit an example I discussed in Scala 3: Contextual Abstractions, Part II:

In Scala 3, the <+> method can be used as is as an infix operator, because its name uses just operator characters instead of alphanumeric and _ characters. However, combine can’t be used as an operator in the old way, unless I use back ticks or wrap the the argument in {}:

The {} option supports common usage where a function literal is passed to a method. Also, for backwards compatibility, all the standard collection operations are allowed to be used in infix notation without back ticks or {}.

If I really want combine to be used with infix notation, I declare it infix:

I’ll explain @targetName in a moment. The new infix keyword tells the compiler to allow infix notation for combine in user code without restriction. Note that it is necessary to use infix in NumericMonoid's definition, too, even though the abstract declaration in Semigroup is declared infix.

The @targetName annotation is a new feature for specifying the alphanumeric name the compiler should use for the generated byte code for the <+> method. If I wanted to call this method from Java code, I would use plus. This name is not visible in Scala code. Also, I can’t use "combine" as the argument for the annotation, as that name would collide with the actual combine method name.

When I compile these definitions, then use javap to analyze the class file, I see that <+> has the full byte code signature public default T plus(T, T);. The default keyword comes from the fact that the Semigroup trait is implemented in byte code as a Java interface and the implementation of <+> is a default method implementation for <+>.

If I remove the @targetName annotation, recompile, and then run javap, then <+> has the signature, public default T $less$plus$greater(T, T);, using Scala’s default encoding for non-alphanumeric characters.

As for many breaking changes, these restrictions on infix notation will start with Scala 3.1 or when the -source:future compilation flag is used with Scala 3.0.

What about postfix notation?

For methods that take no arguments and they are not defined with empty parentheses, (), it’s been a common trick for DSLs to use postfix notation. For example, suppose I have an extension method to convert Double literals to some Dollars type in a financial application, 100.0 dollars.

Postfix expressions are even more ambiguous than infix expressions. They are not technically deprecated, but for a while it’s been necessary to enable the language feature for them, such as import scala.language.postfixOps. That remains true in Scala 3.0, but I’ve been told that a subsequent release of Scala 3 may finally, officially deprecate postfix expressions and remove them in a later release.

You can start reading the rough draft of Programming Scala, Third Edition on the O’Reilly Learning Platform. Most of the chapters are now available and the final release of the book will be coming soon!

--

--

Dean Wampler
Scala 3

The person who is wrong on the Internet. ML/AI and FP enthusiast. Lurks at the AI Alliance and IBM Research. Speaker, author, pretend photographer.