Scala Puzzlers

What's Scala?

Object-oriented and functional

“A drunken Martin Odersky sees a Reese's Peanut Butter Cup ad featuring somebody's peanut butter getting on somebody else's chocolate and has an idea.
He creates Scala, a language that unifies constructs from both object oriented and functional languages. This pisses off both groups and each promptly declares jihad.”
¹

¹ A Brief, Incomplete, and Mostly Wrong History of Programming Languages

What's Scala?

Statically typed with local type inference

What's Scala?

Class/trait-based inheritance and subtyping

What's Scala?

First-class functions/lambdas/methods

What's Scala?

  • Compiles to Java bytecode, runs on the JVM
  • A Java class is a Scala class, too

The Plan for Today

  • No introduction to the language …
  • … but all code snippets will be explained
  • Examples of small & huge simplifications
    • mostly in the language,
    • but also in the standard library
  • Lessons learned?

The Three Laws of
Programming Language Design

Joe Armstrong (creator of Erlang):

  1. What you get right nobody mentions
  2. What you get wrong, people bitch about
  3. What is difficult to understand you have
    to explain to people over and over again


We'll focus on 2. and 3. today.

Why isn't everyting dead-simple?

  • Expressivity and power come with a price
  • Unintended feature interactions
  • Feature & scope creep
  • Legacy issues and compatibility bloat

Simplicity

  • Simple to specify?
  • Simple to implement?
  • Simple to use?


Simplest solution which works consistently
(and still takes all known issues into account)?

Example I: Array Syntax

Scala's Approach

Works for all types which define apply or update!

Example II: Operators …

… because readability is not optional!

Scala's Solution in Theory

  • No operators, just methods
  • No restriction on method names
  • Binary calls can leave out . and ()
  • Precedence is determined by first char

Scala's Solution in Practice

The Past

Floating-Point Literals

Floating-point-literal-without-digit-after-dot

Floating-Point Literals

Floating-point-literal-without-digit-after-dot
(deprecated in 2.10)

Octal Literals

Octal numeric literal

Octal escape literal

Octal Literals

Octal numeric literal (deprecated in 2.10)

Octal escape literal (deprecated in 2.11)

Primitive Type Aliases

  • Pointless choices to achieve the same result

Type Hierarchy (2.9/2.10)

Type Hierarchy (2.10/2.11)

Library Clean-up I (2.10)

Library Clean-up I (2.11)

Library Clean-up II (2.9)

scala.mobile

Library Clean-up III (2.10)

scala.text

Library Clean-up IV (2.10)

scala.util.regex.automata

The Present

Procedures I

  • Special syntax for methods without return value
  • Return type of Unit (~ void)

  • Extremely error-prone and silent error path

Procedures I

Procedures II

  • Is foo
    • dynamically typed?
    • typed with global type inference?
    • using Top/Bottom types?

Procedures

Unit () Insertion

XML Literals

XML Literals

  • Unsolved implementation issues
  • Modularized in 2.11
  • Removed from "core Scala"
  • Hooks for third-party XML libraries

String Interpolation

  • New in 2.10

You know you need string interpolation,
when people start using XML literals as a replacement!

String Interpolation

  • Opportunity to remove dreaded
    "from everything to String"-conversion

String Interpolation

  • Extensible by design

  • Example: formatting interpolator

String Interpolation

  • Example: SQL interpolator

View Bounds

View Bounds

View Bounds

  • Limited usefulness and usage compared
    to Context Bounds (typeclasses)
  • <% syntax deprecated in 2.11

The Future

Constant Inlining

  • Swaps run-time for compile-time dependency
  • No performance benefit
  • Increased compile time

Default Imports

Types, members and packages from these
scopes are available without import:

  • scala.Predef
  • scala._
  • java.lang._

Default Imports: java.lang

Default Imports: java.lang

Useless types: Compiler, Enum, Number, Object, Void, ...

Shadowed types: Boolean, Byte, Double, Float, Long, ...

Default Imports: java.lang

Not importing java.lang._ by default:

  • Easier portability (think JS)
  • Less noise in the default namespace
  • Better average code quality

Implicit Widening Conversions

Implicit Widening Conversions

  • Complete change of semantics regarding
    • Precision
    • Division-By-Zero, error propagation
    • Overflow handling, infinity
  • Silent conversion inherently dangerous,
    not just for conversions which lose precision
    (e. g. Int to Float, Long to Float, Long to Double)

Enums

Current options in Scala:

  • scala.Enumeration
  • sealed trait + objects pattern
  • Use Java

Enums: scala.Enumeration

Enums: scala.Enumeration

Enums: trait/object pattern

Enums: trait/object pattern

  • Extremely verbose
  • Extremely powerful
  • Not compatible with Java's enums

Enums: Use Java

Enums: Use Java

  • Seriously?
  • That's embarrising!

Enums: @enum macro

Enums: @enum macro

  • Easy to use
  • Java compatible
  • Good replacement for scala.Enumeration

Enums

Future options in Scala:

  • scala.Enumeration
  • GADTs: sealed trait + objects
  • Use Java
  • Scala @enum

Union and Intersection Types

  • Computed type is correct, but … useful?

Union and Intersection Types

  • Native support for "Set" operations on types
  • Concise, precise and readable types

Union and Intersection Types

  • Scala already has some kind of union and intersection types …

  • … but lacks first-class support to reason about them in the type system

Union and Intersection Types

  • Native support for unions and intersection types in DOT, the formalization of Scala's next typesystem

  • Stay tuned!

Better VM Support

  • Generics
  • Value types
  • Proper tail calls
  • Delimited continuations

Lessons learned?

Basics

  • Distributed version control
  • Bug tracking
  • Test suites
  • Continuous Integration
  • Reviews and coding standards
  • Specification

Language/Code Evolution

Code/Features/Libraries need time to mature!

  • Mark as experimental to manage user expectations
  • Let different parts evolve at their own speed
  • When in doubt, keep things out

Language/Code Evolution

Example: Scala Macros

  • Experimental
  • Macro styles are promoted from incubator to mainline when they are ready
  • Not everything survives the incubator

Language/Code Evolution

Example: Modularization

  • 2.11 will ship modularized library
  • Deprecated parts moved to own JAR files
  • Libraries get own version number

Bug Fixes

Compatibility

Source or binary compatibility? Both?

  • Java: “Never change anything, ever!”
  • C#: “It depends”
  • Python: “Where code goes to die”
  • PHP: — No comment —

Compatibility

Scala:

  • Minor and update versions are source and binary compatible
  • Major Verions are not binary compatible
  • How to guarantee these rules?

Tooling

Deprecation Policy

  • Code/feature must be marked as "deprecated" for at least one major version
  • Example:
    • Issue is found in 2.9
    • Marked as deprecated in 2.10
    • Fixed/removed in 2.11

Evaluation Criteria

  • Quality of code/feature
  • Impact of change
  • Internal dependencies
  • Available alternatives

Language Deprecation

Requires modification of:

  • Compiler
  • Libraries
  • IDE
  • Specification
  • Style guide
  • Test suite

Code Deprecation

  • Versioning

Code Deprecation

  • Versioning
  • Precision
    • Inheritance

Code Deprecation

  • Versioning
  • Precision
    • Inheritance
    • Parameter naming

Code Deprecation

  • Versioning
  • Precision
    • Inheritance
    • Parameter naming

Code Deprecation

  • Versioning
  • Precision
    • Inheritance
    • Parameter naming
    • Overriding

Code Deprecation

  • Versioning
  • Precision
    • Inheritance
    • Parameter naming
    • Overriding

Results

  • Steady progress towards a smaller, more consistent Scala
  • Requirements for changes are growing (migration, tooling, ...)
  • Managing pressure to add new features (macros!)

Conclusion

  • Manage expectations!
  • Remove more things than you add!
  • Keep things small, simple and consistent!
  • Look out for UI/UX issues!
  • Listen to/watch new users!
  • Recognize common error patterns …
  • … and emit warnings/compiler errors!

Thanks!

Questions?

Bonus Slides

Optimistic APIs

  • What happens if the behavior in a case of error is left unspecified?
  • Example: Method remove takes two arguments
    • Position at which elements are removed
    • Amount of elements to remove

Parallel Nightmares

  • Data structures implement the collection API
  • The collection API supports sequential and parallel operations

Parallel Nightmares

  • Data structures implement the collection API
  • The collection API supports sequential and parallel operations

Parallel Nightmares

  • Parallel operations with multiple failures
    • Which and how many exceptions will be reported?

Parallel Nightmares

  • Parallel operations with multiple failures
    • Which and how many exceptions will be reported?

  • If more than one exception is encountered,
    exceptions will be wrapped in CompositeThrowable

Parallel Nightmares

  • Parallel operations with multiple failures
    • Which and how many exceptions will be reported?

  • If more than one exception is encountered,
    exceptions will be wrapped in CompositeThrowable
  • Sounds reasonable, but ...
    completely non-deterministic exception handling!

Parallele Albträume

  • Sounds reasonable, but ...
    completely non-deterministic exception handling!

  • Number of exceptions?
  • Type of exception?
  • Broken tests!
  • Non-reproducible behavior!

The thing with the double colon

  • A nethod naming ending with :
    • is right-associative …
    • but only in operator syntax!

The thing with the double colon

#

/