Recent Posts
Archives

PostHeaderIcon [ScalaDays 2019] Scala Best Practices Unveiled

At ScalaDays Lausanne 2019, Nicolas Rinaudo, CTO of Besedo, delivered a candid and insightful talk on Scala best practices, drawing from his experience merging Node, Java, and Scala teams. Speaking at EPFL’s 10th anniversary conference, Nicolas shared pitfalls he wished he’d known as a beginner, from array comparisons to exceptions, offering practical solutions. His interactive approach—challenging the audience to spot code issues—drew laughter, applause, and questions on tools like Scalafix, making his session a highlight for developers seeking to write robust Scala code.

Array Comparisons and Type Annotations

Nicolas began with a deceptive array comparison using ==, which fails due to arrays’ reference equality on the JVM, unlike other Scala collections. Beginners from Java or JavaScript backgrounds often stumble here, expecting value equality. The fix, sameElements, ensures correct comparisons, while Scala 3’s immutable arrays behave sanely. Another common error is omitting type annotations on public methods. Without explicit types, the compiler may infer overly broad types like Some instead of Option, risking binary compatibility issues in libraries. Nicolas advised always annotating public members, noting Scala 3’s requirement for implicit members, though the core issue persists, emphasizing vigilance for maintainable code.

Sealed Traits and Case Classes

Enumerations in Scala, Nicolas warned, are treacherous, allowing non-exhaustive pattern matches that compile but crash at runtime. Sealed traits, with subtypes declared in the same file, enable the compiler to enforce exhaustive matching, preventing such failures. He recommended enabling fatal warnings to catch these issues. Similarly, non-final case classes can be extended, leading to unexpected equality behaviors, like two distinct objects comparing equal due to inherited methods. Making case classes final avoids this, though Scala’s default remains unchanged even in Scala 3. Nicolas also noted that sealed traits aren’t foolproof—subtypes can be extended unless final, a subtlety that surprises learners but is manageable with disciplined design.

Exceptions and Referential Transparency

Exceptions, common in Java, disrupt Scala’s referential transparency, where expressions should be replaceable with their values without altering behavior. Nicolas likened exceptions to goto statements, as their origin is untraceable, and Scala’s unchecked exceptions evade compile-time checks. For instance, parsing a string to an integer may throw a NumberFormatException, but most inputs fail, making it a common case unsuitable for exceptions. Instead, use Option for absent values, Either for errors with context, or Try for Java interop. These encode errors in return types, enhancing predictability. Scala 3 offers no changes here, so Nicolas’s advice remains critical for writing transparent, robust code.

Enforcing Best Practices

To prevent these pitfalls, Nicolas advocated rigorous code reviews, citing research showing reduced defects. Automated tools like WartRemover, Scalafix, Scapegoat, and Scalastyle detect issues during builds, though some, like WartRemover’s strict defaults, may need tuning. Migrating to Scala 3 addresses many problems, such as implicit conversions and enumeration ambiguities, with features like the enum keyword and explicit import rules. Nicolas invited the audience to share additional practices, pointing to his companion website for detailed articles. His acknowledgment of Scala contributors, especially for Scala 3 insights, underscored the community’s role in evolving best practices, making his talk a call to action for cleaner coding.

Hashtags: #ScalaDays2019 #Scala #BestPractices #FunctionalProgramming

Leave a Reply