5 Bullets to Scala Adoption

Tomer Gabel
Tomer GabelConsulting Engineer at Substrate Software Services
5 Bullets to
Adoption	
  
	
  
Tomer	
  Gabel,	
  Wix	
  
May	
  2014	
  
WARMUP:	
  THE	
  BASICS	
  
This	
  is	
  Spar–	
  I	
  mean,	
  Java	
  
public class Person {!
private String name;!
private String surname;!
private int age;!
!
public Person( String name, String surname, int age ) {!
this.name = name;!
this.surname = surname;!
this.age = age;!
}!
!
public String getName() { return name; }!
public String getSurname() { return surname; }!
public int getAge() { return age; }!
!
@Override!
public String toString() { /* … */ }!
}	
  
Let’s	
  make	
  some	
  people!	
  
public class SimplePersonGenerator {!
!
// Prepare a bunch of useful constants…!
!
private static List<String> names;!
private static List<String> surnames;!
!
static {!
names = new ArrayList<>();!
names.add( "Jeffrey" );!
names.add( "Walter" );!
names.add( "Donald" );!
!
surnames = new ArrayList<>();!
surnames.add( "Lebowsky" );!
surnames.add( "Sobchak" );!
surnames.add( "Kerabatsos" );!
}!
IT’S	
  MADE	
  OF	
  PEOPLE!	
  
// Continued from previous slide!
!
private static Random random = new Random();!
!
public static Person generatePerson( int age ) {!
String name = names.get( random.nextInt( names.size() ) );!
String surname = surnames.get( random.nextInt( surnames.size() ) );!
return new Person( name, surname, age );!
}!
!
public List<Person> generatePeople( int count, int age ) {!
List<Person> people = new ArrayList<>( count );!
for ( int i = 0; i < count; i++ )!
people.add( generatePerson( age ) );!
return Collections.unmodifiableList( people );!
}!
Scala	
  syntax	
  101	
  
Java	
  
public class Person {!
private String name;!
private String surname;!
private int age;!
!
public Person( String name, String surname,!
int age ) {!
this.name = name;!
this.surname = surname;!
this.age = age;!
}!
!
public String getName() { return name; }!
public String getSurname() { return surname; }!
public int getAge() { return age; }!
!
@Override!
public String toString() { /* … */ }!
}	
  
	
  
Scala	
  syntax	
  101	
  
Java	
  
public class Person {!
private String name;!
private String surname;!
private int age;!
!
public Person( String name, String surname,!
int age ) {!
this.name = name;!
this.surname = surname;!
this.age = age;!
}!
!
public String getName() { return name; }!
public String getSurname() { return surname; }!
public int getAge() { return age; }!
!
@Override!
public String toString() { /* … */ }!
}	
  
	
  
Scala	
  
case class Person(!
name: String,!
surname: String,!
age: Int )!
	
  
	
  
Scala	
  syntax	
  101	
  
Java	
  
public class Person {!
private String name;!
private String surname;!
private int age;!
!
public Person( String name, String surname,!
int age ) {!
this.name = name;!
this.surname = surname;!
this.age = age;!
}!
!
public String getName() { return name; }!
public String getSurname() { return surname; }!
public int getAge() { return age; }!
!
@Override!
public String toString() { /* … */ }!
}	
  
	
  
Scala	
  
case class Person(!
name: String,!
surname: String,!
age: Int )!
	
  
Provides:	
  
–  Constructor	
  
–  Property	
  geOers	
  
–  hashCode/equals	
  
–  toString	
  
–  …	
  and	
  more	
  
	
  
Onwards…	
  
Java	
  
public class SimplePersonGenerator {!
!
// Prepare a bunch of useful constants…!
!
private static List<String> names;!
private static List<String> surnames;!
!
static {!
names = new ArrayList<>();!
names.add( "Jeffrey" );!
names.add( "Walter" );!
names.add( "Donald" );!
!
surnames = new ArrayList<>();!
surnames.add( "Lebowsky" );!
surnames.add( "Sobchak" );!
surnames.add( "Kerabatsos" );!
}!
Onwards…	
  
Java	
  
public class SimplePersonGenerator {!
!
// Prepare a bunch of useful constants…!
!
private static List<String> names;!
private static List<String> surnames;!
!
static {!
names = new ArrayList<>();!
names.add( "Jeffrey" );!
names.add( "Walter" );!
names.add( "Donald" );!
!
surnames = new ArrayList<>();!
surnames.add( "Lebowsky" );!
surnames.add( "Sobchak" );!
surnames.add( "Kerabatsos" );!
}!
Scala	
  
object NaiveScalaPersonGenerator {!
!
private val names: List[ String ] =!
List(!
"Jeffrey",!
"Walter",!
"Donald" !
)!
!
private val surnames: List[ String ] =!
List(!
"Lebowsky",!
"Sobchak",!
"Kerabatsos" !
)!
...	
  and	
  finally:	
  
Java	
  
private static Random random = new Random();!
!
public static Person generatePerson( int age ) {!
String name = names.get( !
random.nextInt( names.size() ) ); !
String surname = surnames.get( !
random.nextInt( surnames.size() ) );!
return new Person( name, surname, age );!
}!
!
public List<Person> generatePeople(!
int count, int age ) {!
List<Person> people = new ArrayList<>( count );!
for ( int i = 0; i < count; i++ )!
people.add( generatePerson( age ) );!
return Collections.unmodifiableList( people );!
}!
...	
  and	
  finally:	
  
Java	
  
private static Random random = new Random();!
!
public static Person generatePerson( int age ) {!
String name = names.get( !
random.nextInt( names.size() ) ); !
String surname = surnames.get( !
random.nextInt( surnames.size() ) );!
return new Person( name, surname, age );!
}!
!
public List<Person> generatePeople(!
int count, int age ) {!
List<Person> people = new ArrayList<>( count );!
for ( int i = 0; i < count; i++ )!
people.add( generatePerson( age ) );!
return Collections.unmodifiableList( people );!
}!
Scala	
  
private val random: Random = new Random!
!
def generatePerson( age: Int ): Person = {!
val name: String =!
names( random.nextInt( names.size ) )!
val surname: String =!
surnames( random.nextInt( surnames.size ) )!
new Person( name, surname, age )!
}!
!
!
...	
  and	
  finally:	
  
Java	
  
private static Random random = new Random();!
!
public static Person generatePerson( int age ) {!
String name = names.get( !
random.nextInt( names.size() ) ); !
String surname = surnames.get( !
random.nextInt( surnames.size() ) );!
return new Person( name, surname, age );!
}!
!
public List<Person> generatePeople(!
int count, int age ) {!
List<Person> people = new ArrayList<>( count );!
for ( int i = 0; i < count; i++ )!
people.add( generatePerson( age ) );!
return Collections.unmodifiableList( people );!
}!
Scala	
  
private val random: Random = new Random!
!
def generatePerson( age: Int ): Person = {!
val name: String =!
names( random.nextInt( names.size ) )!
val surname: String =!
surnames( random.nextInt( surnames.size ) )!
new Person( name, surname, age )!
}!
!
def generatePeople( count: Int, age: Int ):!
List[ Person ] = {!
val people: mutable.ListBuffer[ Person ] =!
mutable.ListBuffer.empty!
for ( i <- 0 until count ) {!
people.append( generatePerson( age ) )!
}!
people.result()!
}!
!
1.	
  TYPE	
  	
  
INFERENCE	
  
We	
  started	
  off	
  with:	
  
Java	
  
private static Random random = new Random();!
!
public static Person generatePerson( int age ) {!
String name = names.get( !
random.nextInt( names.size() ) ); !
String surname = surnames.get( !
random.nextInt( surnames.size() ) );!
return new Person( name, surname, age );!
}!
!
public static List<Person> generatePeople(!
int count, int age ) {!
List<Person> people = new ArrayList<>( count );!
for ( int i = 0; i < count; i++ )!
people.add( generatePerson( age ) );!
return Collections.unmodifiableList( people );!
}!
Scala	
  
private val random: Random = new Random!
!
def generatePerson( age: Int ): Person = {!
val name: String =!
names( random.nextInt( names.size ) )!
val surname: String =!
surnames( random.nextInt( surnames.size ) )!
new Person( name, surname, age )!
}!
!
def generatePeople( count: Int, age: Int ):!
List[ Person ] = {!
val people: mutable.ListBuffer[ Person ] =!
mutable.ListBuffer.empty!
for ( i <- 0 until count ) {!
people.append( generatePerson( age ) )!
}!
people.result()!
}!
!
Let’s	
  simplify!	
  
Java	
  
private static Random random = new Random();!
!
public static Person generatePerson( int age ) {!
String name = names.get( !
random.nextInt( names.size() ) ); !
String surname = surnames.get( !
random.nextInt( surnames.size() ) );!
return new Person( name, surname, age );!
}!
!
public static List<Person> generatePeople(!
int count, int age ) {!
List<Person> people = new ArrayList<>( count );!
for ( int i = 0; i < count; i++ )!
people.add( generatePerson( age ) );!
return Collections.unmodifiableList( people );!
}!
Scala	
  
private val random = new Random!
!
def generatePerson( age: Int ): Person = {!
val name =!
names( random.nextInt( names.size ) )!
val surname =!
surnames( random.nextInt( surnames.size ) )!
new Person( name, surname, age )!
}!
!
def generatePeople( count: Int, age: Int ):!
List[ Person ] = {!
val people =!
mutable.ListBuffer.empty[ Person ]!
for ( i <- 0 until count ) {!
people.append( generatePerson( age ) )!
}!
people.result()!
}!
!
Also	
  works	
  for	
  result	
  types:	
  
Java	
  
private static Random random = new Random();!
!
public static Person generatePerson( int age ) {!
String name = names.get( !
random.nextInt( names.size() ) ); !
String surname = surnames.get( !
random.nextInt( surnames.size() ) );!
return new Person( name, surname, age );!
}!
!
public static List<Person> generatePeople(!
int count, int age ) {!
List<Person> people = new ArrayList<>( count );!
for ( int i = 0; i < count; i++ )!
people.add( generatePerson( age ) );!
return Collections.unmodifiableList( people );!
}!
Scala	
  
private val random = new Random!
!
def generatePerson( age: Int ) = {!
val name =!
names( random.nextInt( names.size ) )!
val surname =!
surnames( random.nextInt( surnames.size ) )!
new Person( name, surname, age )!
}!
!
def generatePeople( count: Int, age: Int ) = {!
val people =!
mutable.ListBuffer.empty[ Person ]!
for ( i <- 0 until count ) {!
people.append( generatePerson( age ) )!
}!
people.result()!
}!
!
Also	
  works	
  for	
  result	
  types:	
  
Java	
  
private static Random random = new Random();!
!
public static Person generatePerson( int age ) {!
String name = names.get( !
random.nextInt( names.size() ) ); !
String surname = surnames.get( !
random.nextInt( surnames.size() ) );!
return new Person( name, surname, age );!
}!
!
public List<Person> generatePeople(!
int count, int age ) {!
List<Person> people = new ArrayList<>( count );!
for ( int i = 0; i < count; i++ )!
people.add( generatePerson( age ) );!
return Collections.unmodifiableList( people );!
}!
Scala	
  
private val random = new Random!
!
def generatePerson( age: Int ) = {!
val name =!
names( random.nextInt( names.size ) )!
val surname =!
surnames( random.nextInt( surnames.size ) )!
new Person( name, surname, age )!
}!
!
def generatePeople( count: Int, age: Int ) = {!
val people =!
mutable.ListBuffer.empty[ Person ]!
for ( i <- 0 until count ) {!
people.append( generatePerson( age ) )!
}!
people.result()!
}!
!
Not necessarily a good idea.
• Code readability
• Public APIs
• Compilation times
Bonus	
  points:	
  Named	
  arguments	
  
Java	
  
private static Random random = new Random();!
!
public static Person generatePerson( int age ) {!
String name = names.get( !
random.nextInt( names.size() ) ); !
String surname = surnames.get( !
random.nextInt( surnames.size() ) );!
return new Person( name, surname, age );!
}!
!
public static List<Person> generatePeople(!
int count, int age ) {!
List<Person> people = new ArrayList<>( count );!
for ( int i = 0; i < count; i++ )!
people.add( generatePerson( age ) );!
return Collections.unmodifiableList( people );!
}!
Scala	
  
private val random = new Random!
!
def generatePerson( age: Int ) = Person(!
name = names( random.nextInt( names.size ) )!
surname =

surnames( random.nextInt( surnames.size ) )!
age = age!
)!
!
def generatePeople( count: Int, age: Int ) = {!
val people =!
mutable.ListBuffer.empty[ Person ]!
for ( i <- 0 until count ) {!
people.append( generatePerson( age ) )!
}!
people.result()!
}!
!
2.	
  THE	
  COLLECTION	
  FRAMEWORK	
  
Quick	
  example	
  
Java	
  
private static Random random = new Random();!
!
public static Person generatePerson( int age ) {!
String name = names.get( !
random.nextInt( names.size() ) ); !
String surname = surnames.get( !
random.nextInt( surnames.size() ) );!
return new Person( name, surname, age );!
}!
!
public static List<Person> generatePeople(!
int count, int age ) {!
List<Person> people = new ArrayList<>( count );!
for ( int i = 0; i < count; i++ )!
people.add( generatePerson( age ) );!
return Collections.unmodifiableList( people );!
}!
Scala	
  
private val random = new Random!
!
def generatePerson( age: Int ) = Person(!
name = names( random.nextInt( names.size ) )!
surname =

surnames( random.nextInt( surnames.size ) )!
age = age!
)!
!
def generatePeople( count: Int, age: Int ) = {!
val people =!
mutable.ListBuffer.empty[ Person ]!
for ( i <- 0 until count ) {!
people.append( generatePerson( age ) )!
}!
people.result()!
}!
!
Quick	
  example	
  
Java	
  
private static Random random = new Random();!
!
public static Person generatePerson( int age ) {!
String name = names.get( !
random.nextInt( names.size() ) ); !
String surname = surnames.get( !
random.nextInt( surnames.size() ) );!
return new Person( name, surname, age );!
}!
!
public static List<Person> generatePeople(!
int count, int age ) {!
List<Person> people = new ArrayList<>( count );!
for ( int i = 0; i < count; i++ )!
people.add( generatePerson( age ) );!
return Collections.unmodifiableList( people );!
}!
Scala	
  
private val random = new Random!
!
def generatePerson( age: Int ) = Person(!
name = names( random.nextInt( names.size ) )!
surname =

surnames( random.nextInt( surnames.size ) )!
age = age!
)!
!
!
!
!
def generatePeople( count: Int, age: Int ) =!
List.fill( count ) { generatePerson( age ) }!
Scala	
  collec[ons	
  primer	
  
// Some data to start with…!
val people = generatePeople( 5 )!
!
val names = people.map( p => p.name )!
!
val adults = people.filter( p => p.age >= 18 )!
!
val averageAge = !
people.map( p => p.age ).sum / people.size!
!
// Functions are 1st class citizens!
def isAdult( p: Person ) = p.age >= 18!
val adults2 = people.filter( isAdult )!
assert( adults2 == adults )	
  
Maps,	
  too	
  
val trivial: Map[ String, String ] =!
Map( "name" -> "Jeffrey Lebowsky",!
"alias" -> "The Dude" )!
!
val directory: Map[ Char, List[ Person ] ] =!
people!
.groupBy( p => p.surname.head.toUpper )!
.withDefaultValue( List.empty )!
!
val beginningWithK: List[ Person ] =!
directory( 'K' )!
!
val countByFirstLetter: Map[ Char, Int ] = !
directory.mapValues( list => list.size )!
	
  
And	
  much,	
  much,	
  much	
  more	
  
!
val ( adults, minors ) = people.partition( p => p.age >= 18 )!
!
val randomPairs = Random.shuffle( people ).grouped( 2 )!
!
val youngest = people.minBy( p => p.age )!
!
val oldest = people.maxBy( p => p.age )!
!
val hasSeniorCitizens = people.exists( p => p.age >= 65 )	
  
Caveat	
  emptor	
  
•  Scala	
  is	
  flexible	
  
–  You	
  can	
  do	
  the	
  same	
  thing	
  in	
  mul[ple	
  ways:	
  
	
  
people.foreach( person => println( person ) ) !// "Normal"!
people.foreach { person => println( person ) } !// Block-style!
people.foreach { println(_) } ! ! !// Placeholder syntax!
people.foreach( println ) ! ! !// With function!
people foreach println ! ! ! !// Infix notation	
  
•  Stay	
  sane.	
  Stay	
  safe.	
  
–  Pick	
  a	
  style	
  and	
  s[ck	
  with	
  it	
  
	
  
3.	
  OPTIONS	
  
Back	
  in	
  Java-­‐Land	
  
public class Person {!
private String name;!
private String surname;!
private int age;!
!
public Person( String name, String surname, int age ) {!
this.name = name;!
this.surname = surname;!
this.age = age;!
}!
!
public String getName() { return name; }!
public String getSurname() { return surname; }!
public int getAge() { return age; }!
!
@Override!
public String toString() { /* … */ }!
}	
  
We want to make these
optional.
Typical	
  solu[on	
  in	
  Java	
  
public class PartiallyKnownPerson {!
private String name;!
private String surname;!
private Integer age;!
!
public PartiallyKnownPerson( String name, String surname, Integer age ) {!
this.name = name;!
this.surname = surname;!
this.age = age;!
}!
!
public String getName() { return name; }!
public String getSurname() { return surname; }!
public Integer getAge() { return age; }!
!
@Override!
public String toString() { /* … */ }!
}	
  
This	
  sucks	
  
public class PartiallyKnownPerson {!
private String name;!
private String surname;!
private Integer age;!
!
public PartiallyKnownPerson ( String name, String surname, Integer age ) {!
this.name = name;!
this.surname = surname;!
this.age = age;!
}!
!
public String getName() { return name; }!
public String getSurname() { return surname; }!
public Integer getAge() { return age; }!
!
@Override!
public String toString() { /* … */ }!
}	
  
Returned values
always need to be
checked.
Implicit; does not document intent.
Falling	
  back	
  to	
  JavaDocs	
  
/**!
* Creates a new person.!
* @param name The person's name (or {@literal null} if unknown).!
* @param surname The person's surname (or {@literal null} if unknown).!
* @param age The person's age (or {@literal null} if unknown).!
*/!
public PartiallyKnownPerson( String name, String surname, Integer age ) {!
this.name = name;!
this.surname = surname;!
this.age = age;!
}	
  
Falling	
  back	
  to	
  JavaDocs	
  
/**!
* Creates a new person.!
* @param name The person's name (or {@literal null} if unknown).!
* @param surname The person's surname (or {@literal null} if unknown).!
* @param age The person's age (or {@literal null} if unknown).!
*/!
public PartiallyKnownPerson( String name, String surname, Integer age ) {!
this.name = name;!
this.surname = surname;!
this.age = age;!
}!
This still sucks.
Falling	
  back	
  to	
  JavaDocs	
  
/**!
* Creates a new person.!
* @param name The person's name (or {@literal null} if unknown).!
* @param surname The person's surname (or {@literal null} if unknown).!
* @param age The person's age (or {@literal null} if unknown).!
*/!
public PartiallyKnownPerson( String name, String surname, Integer age ) {!
this.name = name;!
this.surname = surname;!
this.age = age;!
}!
!
boolean isAdult( Person p ) {!
return p.getAge() >= 18; // I love the smell of NPEs in the morning!
}	
  
This still sucks.Because:
Op[onal	
  arguments,	
  the	
  Scala	
  way	
  
case class PartiallyKnownPerson( name: Option[ String ] = None,!
surname: Option[ String ] = None,!
age: Option[ Int ] = None ) {!
!
def isAdult = age.map( _ > 18 )!
}!
!
val person = PartiallyKnownPerson( name = Some( "Brandt" ) )!
!
val explicitAccess = person.age.get // <-- NoSuchElementException thrown here!
!
val withDefault = person.name.getOrElse( "Anonymous" )!
println( "Hello " + withDefault + "!" )!
!
// Options are also zero- or single-element collections!!
def greet( whom: Iterable[ String ] ) =!
whom.foreach { name => println( "hello" + name ) }!
greet( person.name )	
  
4.	
  TRAITS	
  
Back	
  in	
  Java	
  land…	
  
import org.slf4j.Logger;!
import org.slf4j.LoggerFactory;!
!
public class ClassWithLogs {!
private static Logger log = LoggerFactory.getLogger( ClassWithLogs.class );!
!
public String getNormalizedName( Person person ) {!
log.info( "getNormalizedName called" );!
log.debug( "Normalizing " + person.toString() );!
String normalizedName = person.getName().toUpperCase().trim();!
log.debug( "Normalized name is: " + normalizedName );!
return normalizedName;!
}!
}	
  
…	
  boilerplate	
  is	
  king	
  
import org.slf4j.Logger;!
import org.slf4j.LoggerFactory;!
!
public class ClassWithLogs {!
private static Logger log = LoggerFactory.getLogger( ClassWithLogs.class );!
!
public String getNormalizedName( Person person ) {!
log.info( "getNormalizedName called" );!
log.debug( "Normalizing " + person.toString() );!
String normalizedName = person.getName().toUpperCase().trim();!
log.debug( "Normalized name is: " + normalizedName );!
return normalizedName;!
}!
}	
  
x1000 classes…
Eager evaluation
What	
  can	
  we	
  do	
  about	
  it?	
  
•  A	
  solu[on	
  should:	
  
–  Require	
  minimal	
  boilerplate	
  
–  Cause	
  few	
  or	
  no	
  side-­‐effects	
  
–  Be	
  composable	
  
–  Perform	
  well	
  
•  An	
  abstract	
  base	
  class	
  is	
  
useless	
  
–  Only	
  one	
  base	
  class	
  allowed	
  
–  No	
  way	
  to	
  do	
  lazy	
  evalua[on	
  
Enter:	
  Scala	
  traits	
  
trait Logging {!
private val log = LoggerFactory.getLogger( this.getClass )!
!
protected def logInfo( message: => String ) = !
if ( log.isInfoEnabled ) log.info ( message )!
!
protected def logDebug( message: => String ) = !
if ( log.isDebugEnabled ) log.debug( message )!
!
protected def logWarn( message: => String ) = !
if ( log.isWarnEnabled ) log.warn ( message )!
!
protected def logError( message: => String ) = !
if ( log.isErrorEnabled ) log.error( message )!
}!
!
Boilerplate	
  is	
  king	
  
Java	
  
public class ClassWithLogs {!
private static Logger log =!
LoggerFactory.getLogger(!
ClassWithLogs.class );!
!
public String getNormalizedName(!
Person person ) {!
log.info( "getNormalizedName called" );!
log.debug( "Normalizing " +!
person.toString() );!
String normalizedName =!
person.getName().toUpperCase().trim();!
log.debug( "Normalized name is: " +!
normalizedName );!
return normalizedName;!
}!
}	
  
Scala	
  
!
class ClassWithLogs extends Logging {!
!
!
!
def getNormalizedName( person: Person ) = {!
logInfo( "getNormalizedName called" )!
logDebug( "Normalizing " +!
person.toString )!
val normalizedName =!
person.name.toUpperCase.trim!
logDebug( "Normalized name is: " +!
normalizedName )!
normalizedName!
}!
}	
  
Not	
  convinced?	
  
•  Consider:	
  
trait Iterator[ T ] {!
def hasNext: Boolean!
def next: T 	
 	
 // Or throw NoSuchElementException!
}!
!
trait Iterable[ T ] {!
def getIterator: Iterator[ T ]!
def first: T // Or throw NoSuchElementException!
def firstOption: Option[ T ]!
def last: T // Or throw NoSuchElementException!
def lastOption: Option[ T ]!
def size: Int!
}	
  
	
  
•  What	
  if	
  you	
  need	
  to	
  implement	
  ArrayList,	
  HashSet,	
  LinkedList…?	
  
A	
  saner	
  op[on	
  
trait BaseIterable[ T ] extends Iterable[ T ] {!
!
def firstOption = {!
val it = getIterator!
if ( it.hasNext ) Some( it.next ) else None!
}!
!
def first = firstOption.getOrElse( throw new NoSuchElementException )!
!
def size = {!
val it = getIterator!
var count = 0!
while ( it.hasNext ) { count += 1; it.next }!
count!
}!
!
// …!
}	
  
Massive	
  win!	
  
case class ArrayList[ T ]( array: Array[ T ] )!
extends BaseIterable[ T ] {!
!
def getIterator = new Iterator[ T ] {!
var index = 0!
!
def hasNext = index < array.length!
!
def next =!
if ( hasNext ) {!
val value = array( index )!
index += 1!
value!
} else!
throw new NoSuchElementException!
}!
}	
  
•  No	
  boilerplate	
  
•  Implement	
  only	
  “missing	
  bits”	
  
•  Mix	
  and	
  match	
  mul[ple	
  traits!	
  
•  Need	
  features?	
  
–  Add	
  to	
  your	
  concrete	
  class	
  
•  Need	
  performance?	
  
–  Override	
  the	
  default	
  
implementa[on	
  
5.	
  PATTERN	
  MATCHING	
  
Enhancing	
  our	
  domain	
  model	
  
Java	
  
enum MaritalStatus { !
single, married, divorced, widowed !
}!
!
enum Gender { !
male, female !
}!
!
class Person {!
private String name;!
private String surname;!
private int age;!
private MaritalStatus maritalStatus;!
private Gender gender;!
// …!
}!
Enhancing	
  our	
  domain	
  model	
  
Java	
  
enum MaritalStatus { !
single, married, divorced, widowed !
}!
!
enum Gender { !
male, female !
}!
!
class Person {!
private String name;!
private String surname;!
private int age;!
private MaritalStatus maritalStatus;!
private Gender gender;!
// …!
}!
Scala	
  
sealed trait MaritalStatus!
case object Single extends MaritalStatus!
case object Married extends MaritalStatus!
case object Divorced extends MaritalStatus!
case object Widowed extends MaritalStatus!
!
sealed trait Gender!
case object Male extends Gender!
case object Female extends Gender!
!
case class Person(!
name: String, surname: String, age: Int,!
maritalStatus: Option[ MaritalStatus ],!
gender: Option[ Gender ] )!
	
  
Saluta[on	
  genera[on	
  
Java	
  
public String getSalutation() {!
if ( gender == null ) return null;!
switch( gender ) {!
case male:!
return "Mr.";!
!
case female:!
if ( maritalStatus == null )!
return "Ms.";!
switch( maritalStatus ) {!
case single:!
return "Miss";!
!
case married:!
case divorced:!
case widowed:!
return "Mrs.";!
}!
}!
Saluta[on	
  genera[on	
  
Java	
  
public String getSalutation() {!
if ( gender == null ) return null;!
switch( gender ) {!
case male:!
return "Mr.";!
!
case female:!
if ( maritalStatus == null )!
return "Ms.";!
switch( maritalStatus ) {!
case single:!
return "Miss";!
!
case married:!
case divorced:!
case widowed:!
return "Mrs.";!
}!
}!
Scala	
  
!
!
def salutation: Option[ String ] = !
( gender, maritalStatus ) match {!
case (Some(Male ), _ ) => Some("Mr.")!
case (Some(Female), Some(Single)) => Some("Miss")!
case (Some(Female), None ) => Some("Ms.")!
case (Some(Female), _ ) => Some("Mrs.")!
case (None , _ ) => None!
}	
  
Why	
  is	
  this	
  awesome?	
  
•  Other	
  use	
  cases	
  include:	
  
–  Reac[ng	
  to	
  objects	
  of	
  
unknown	
  type	
  
–  Decomposing	
  structures	
  
•  Extensible	
  via	
  extractor	
  
objects	
  
•  Compiler	
  performs	
  
exhaus0veness	
  check!	
  
WE’RE	
  ALMOST
DONE!	
  
What	
  about	
  Java	
  8,	
  you	
  ask?	
  
•  Java	
  8	
  is	
  awesome	
  
•  …	
  it	
  validates	
  Scala!	
  
•  But	
  it’s	
  not	
  up	
  to	
  par	
  
•  Closures/lambdas:	
  
–  Syntax	
  is	
  limited	
  
–  Func[ons	
  aren’t	
  1st	
  class	
  
•  Default	
  methods	
  aren’t	
  a	
  
subs[tute	
  for	
  traits	
  
–  No	
  self-­‐type	
  annota[on	
  
–  No	
  visibility	
  modifiers	
  (e.g.	
  
protected	
  members)	
  
Note	
  that	
  we	
  haven’t	
  covered…	
  
•  For	
  comprehensions	
  
•  Lazy	
  vals	
  
•  Tuples	
  
•  Generics	
  
–  Type	
  bounds	
  
–  Variance	
  
–  Higher-­‐kinded	
  types	
  
•  Implicits	
  
–  Type	
  classes	
  
–  Conversions	
  
–  Parameters	
  
•  Func[ons	
  and	
  par[al	
  func[ons	
  
•  Top	
  and	
  boOom	
  types	
  
•  Scoped	
  imports	
  
•  Extractor	
  objects	
  (unapply/-­‐seq)	
  
•  Structural	
  types	
  
•  Type	
  members	
  
–  …	
  and	
  path-­‐dependent	
  types	
  
•  Futures	
  and	
  promises	
  
•  Macros	
  
•  DSLs	
  
Thanks	
  you	
  for	
  listening!	
  
Ques[ons?	
  
Code	
  is	
  on	
  GitHub	
  
I	
  am	
  on	
  TwiOer	
  @tomerg	
  
Scala	
  is	
  on	
  the	
  internetz	
  
1 of 53

Recommended

Kotlin Programming Language. What it is all about. Roman Belov, PMM in Kotlin by
Kotlin Programming Language. What it is all about. Roman Belov, PMM in KotlinKotlin Programming Language. What it is all about. Roman Belov, PMM in Kotlin
Kotlin Programming Language. What it is all about. Roman Belov, PMM in KotlinJetBrains Russia
140 views83 slides
Snakes and ladders by
Snakes and laddersSnakes and ladders
Snakes and laddersRubén Berenguel
592 views41 slides
Scala in a Java 8 World by
Scala in a Java 8 WorldScala in a Java 8 World
Scala in a Java 8 WorldDaniel Blyth
146 views40 slides
There and Back Again by
There and Back AgainThere and Back Again
There and Back AgainMike Harris
1K views114 slides
Desarrollando aplicaciones web en minutos by
Desarrollando aplicaciones web en minutosDesarrollando aplicaciones web en minutos
Desarrollando aplicaciones web en minutosEdgar J. Suárez
756 views239 slides
Potential Friend Finder by
Potential Friend FinderPotential Friend Finder
Potential Friend FinderRichard Schneeman
1.1K views59 slides

More Related Content

Similar to 5 Bullets to Scala Adoption

Introduction to Groovy by
Introduction to GroovyIntroduction to Groovy
Introduction to GroovyAnton Arhipov
1.3K views55 slides
Features of Kotlin I find exciting by
Features of Kotlin I find excitingFeatures of Kotlin I find exciting
Features of Kotlin I find excitingRobert MacLean
4.1K views16 slides
CodeCamp Iasi 10 march 2012 - Practical Groovy by
CodeCamp Iasi 10 march 2012 - Practical GroovyCodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical GroovyCodecamp Romania
585 views18 slides
1.1 motivation by
1.1 motivation1.1 motivation
1.1 motivationfuturespective
346 views12 slides
Scala == Effective Java by
Scala == Effective JavaScala == Effective Java
Scala == Effective JavaScalac
2.3K views31 slides
Intermediate Swift Language by Apple by
Intermediate Swift Language by AppleIntermediate Swift Language by Apple
Intermediate Swift Language by Applejamesfeng2
2K views396 slides

Similar to 5 Bullets to Scala Adoption(20)

Introduction to Groovy by Anton Arhipov
Introduction to GroovyIntroduction to Groovy
Introduction to Groovy
Anton Arhipov1.3K views
Features of Kotlin I find exciting by Robert MacLean
Features of Kotlin I find excitingFeatures of Kotlin I find exciting
Features of Kotlin I find exciting
Robert MacLean4.1K views
CodeCamp Iasi 10 march 2012 - Practical Groovy by Codecamp Romania
CodeCamp Iasi 10 march 2012 - Practical GroovyCodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical Groovy
Codecamp Romania585 views
Scala == Effective Java by Scalac
Scala == Effective JavaScala == Effective Java
Scala == Effective Java
Scalac2.3K views
Intermediate Swift Language by Apple by jamesfeng2
Intermediate Swift Language by AppleIntermediate Swift Language by Apple
Intermediate Swift Language by Apple
jamesfeng22K views
BEKK Teknologiradar - Kotlin by Vegard Veiset
BEKK Teknologiradar - KotlinBEKK Teknologiradar - Kotlin
BEKK Teknologiradar - Kotlin
Vegard Veiset64 views
Scala - fra newbie til ninja på en time by karianneberg
Scala - fra newbie til ninja på en timeScala - fra newbie til ninja på en time
Scala - fra newbie til ninja på en time
karianneberg504 views
1.1 motivation by wpgreenway
1.1 motivation1.1 motivation
1.1 motivation
wpgreenway177 views
Swift Study #7 by chanju Jeon
Swift Study #7Swift Study #7
Swift Study #7
chanju Jeon1.7K views
No excuses, switch to kotlin by Thijs Suijten
No excuses, switch to kotlinNo excuses, switch to kotlin
No excuses, switch to kotlin
Thijs Suijten300 views
About java by Jay Xu
About javaAbout java
About java
Jay Xu636 views
Mobile Database Persistence by Eric Maxwell
Mobile Database PersistenceMobile Database Persistence
Mobile Database Persistence
Eric Maxwell222 views
Naïveté vs. Experience by Mike Fogus
Naïveté vs. ExperienceNaïveté vs. Experience
Naïveté vs. Experience
Mike Fogus7K views
Greach 2015 AST – Groovy Transformers: More than meets the eye! by Iván López Martín
Greach 2015   AST – Groovy Transformers: More than meets the eye!Greach 2015   AST – Groovy Transformers: More than meets the eye!
Greach 2015 AST – Groovy Transformers: More than meets the eye!

More from Tomer Gabel

How shit works: Time by
How shit works: TimeHow shit works: Time
How shit works: TimeTomer Gabel
342 views53 slides
Nondeterministic Software for the Rest of Us by
Nondeterministic Software for the Rest of UsNondeterministic Software for the Rest of Us
Nondeterministic Software for the Rest of UsTomer Gabel
329 views39 slides
Slaying Sacred Cows: Deconstructing Dependency Injection by
Slaying Sacred Cows: Deconstructing Dependency InjectionSlaying Sacred Cows: Deconstructing Dependency Injection
Slaying Sacred Cows: Deconstructing Dependency InjectionTomer Gabel
1.3K views34 slides
An Abridged Guide to Event Sourcing by
An Abridged Guide to Event SourcingAn Abridged Guide to Event Sourcing
An Abridged Guide to Event SourcingTomer Gabel
1K views32 slides
How shit works: the CPU by
How shit works: the CPUHow shit works: the CPU
How shit works: the CPUTomer Gabel
1.8K views38 slides
How Shit Works: Storage by
How Shit Works: StorageHow Shit Works: Storage
How Shit Works: StorageTomer Gabel
914 views44 slides

More from Tomer Gabel(20)

How shit works: Time by Tomer Gabel
How shit works: TimeHow shit works: Time
How shit works: Time
Tomer Gabel342 views
Nondeterministic Software for the Rest of Us by Tomer Gabel
Nondeterministic Software for the Rest of UsNondeterministic Software for the Rest of Us
Nondeterministic Software for the Rest of Us
Tomer Gabel329 views
Slaying Sacred Cows: Deconstructing Dependency Injection by Tomer Gabel
Slaying Sacred Cows: Deconstructing Dependency InjectionSlaying Sacred Cows: Deconstructing Dependency Injection
Slaying Sacred Cows: Deconstructing Dependency Injection
Tomer Gabel1.3K views
An Abridged Guide to Event Sourcing by Tomer Gabel
An Abridged Guide to Event SourcingAn Abridged Guide to Event Sourcing
An Abridged Guide to Event Sourcing
Tomer Gabel1K views
How shit works: the CPU by Tomer Gabel
How shit works: the CPUHow shit works: the CPU
How shit works: the CPU
Tomer Gabel1.8K views
How Shit Works: Storage by Tomer Gabel
How Shit Works: StorageHow Shit Works: Storage
How Shit Works: Storage
Tomer Gabel914 views
Java 8 and Beyond, a Scala Story by Tomer Gabel
Java 8 and Beyond, a Scala StoryJava 8 and Beyond, a Scala Story
Java 8 and Beyond, a Scala Story
Tomer Gabel747 views
The Wix Microservice Stack by Tomer Gabel
The Wix Microservice StackThe Wix Microservice Stack
The Wix Microservice Stack
Tomer Gabel1.7K views
Scala Refactoring for Fun and Profit (Japanese subtitles) by Tomer Gabel
Scala Refactoring for Fun and Profit (Japanese subtitles)Scala Refactoring for Fun and Profit (Japanese subtitles)
Scala Refactoring for Fun and Profit (Japanese subtitles)
Tomer Gabel6.6K views
Scala Refactoring for Fun and Profit by Tomer Gabel
Scala Refactoring for Fun and ProfitScala Refactoring for Fun and Profit
Scala Refactoring for Fun and Profit
Tomer Gabel985 views
Onboarding at Scale by Tomer Gabel
Onboarding at ScaleOnboarding at Scale
Onboarding at Scale
Tomer Gabel1.5K views
Scala in the Wild by Tomer Gabel
Scala in the WildScala in the Wild
Scala in the Wild
Tomer Gabel2.8K views
Speaking Scala: Refactoring for Fun and Profit (Workshop) by Tomer Gabel
Speaking Scala: Refactoring for Fun and Profit (Workshop)Speaking Scala: Refactoring for Fun and Profit (Workshop)
Speaking Scala: Refactoring for Fun and Profit (Workshop)
Tomer Gabel765 views
Put Your Thinking CAP On by Tomer Gabel
Put Your Thinking CAP OnPut Your Thinking CAP On
Put Your Thinking CAP On
Tomer Gabel3.5K views
Leveraging Scala Macros for Better Validation by Tomer Gabel
Leveraging Scala Macros for Better ValidationLeveraging Scala Macros for Better Validation
Leveraging Scala Macros for Better Validation
Tomer Gabel1.4K views
A Field Guide to DSL Design in Scala by Tomer Gabel
A Field Guide to DSL Design in ScalaA Field Guide to DSL Design in Scala
A Field Guide to DSL Design in Scala
Tomer Gabel6.5K views
Functional Leap of Faith (Keynote at JDay Lviv 2014) by Tomer Gabel
Functional Leap of Faith (Keynote at JDay Lviv 2014)Functional Leap of Faith (Keynote at JDay Lviv 2014)
Functional Leap of Faith (Keynote at JDay Lviv 2014)
Tomer Gabel1.5K views
Scala Back to Basics: Type Classes by Tomer Gabel
Scala Back to Basics: Type ClassesScala Back to Basics: Type Classes
Scala Back to Basics: Type Classes
Tomer Gabel3.7K views
Nashorn: JavaScript that doesn’t suck (ILJUG) by Tomer Gabel
Nashorn: JavaScript that doesn’t suck (ILJUG)Nashorn: JavaScript that doesn’t suck (ILJUG)
Nashorn: JavaScript that doesn’t suck (ILJUG)
Tomer Gabel5.9K views
Ponies and Unicorns With Scala by Tomer Gabel
Ponies and Unicorns With ScalaPonies and Unicorns With Scala
Ponies and Unicorns With Scala
Tomer Gabel961 views

Recently uploaded

Best Mics For Your Live Streaming by
Best Mics For Your Live StreamingBest Mics For Your Live Streaming
Best Mics For Your Live Streamingontheflystream
6 views6 slides
DSD-INT 2023 Next-Generation Flood Inundation Mapping for Taiwan - Delft3D FM... by
DSD-INT 2023 Next-Generation Flood Inundation Mapping for Taiwan - Delft3D FM...DSD-INT 2023 Next-Generation Flood Inundation Mapping for Taiwan - Delft3D FM...
DSD-INT 2023 Next-Generation Flood Inundation Mapping for Taiwan - Delft3D FM...Deltares
7 views40 slides
DSD-INT 2023 Baseline studies for Strategic Coastal protection for Long Islan... by
DSD-INT 2023 Baseline studies for Strategic Coastal protection for Long Islan...DSD-INT 2023 Baseline studies for Strategic Coastal protection for Long Islan...
DSD-INT 2023 Baseline studies for Strategic Coastal protection for Long Islan...Deltares
10 views30 slides
SUGCON ANZ Presentation V2.1 Final.pptx by
SUGCON ANZ Presentation V2.1 Final.pptxSUGCON ANZ Presentation V2.1 Final.pptx
SUGCON ANZ Presentation V2.1 Final.pptxJack Spektor
21 views34 slides
DSD-INT 2023 Simulating a falling apron in Delft3D 4 - Engineering Practice -... by
DSD-INT 2023 Simulating a falling apron in Delft3D 4 - Engineering Practice -...DSD-INT 2023 Simulating a falling apron in Delft3D 4 - Engineering Practice -...
DSD-INT 2023 Simulating a falling apron in Delft3D 4 - Engineering Practice -...Deltares
6 views15 slides
MariaDB stored procedures and why they should be improved by
MariaDB stored procedures and why they should be improvedMariaDB stored procedures and why they should be improved
MariaDB stored procedures and why they should be improvedFederico Razzoli
8 views32 slides

Recently uploaded(20)

DSD-INT 2023 Next-Generation Flood Inundation Mapping for Taiwan - Delft3D FM... by Deltares
DSD-INT 2023 Next-Generation Flood Inundation Mapping for Taiwan - Delft3D FM...DSD-INT 2023 Next-Generation Flood Inundation Mapping for Taiwan - Delft3D FM...
DSD-INT 2023 Next-Generation Flood Inundation Mapping for Taiwan - Delft3D FM...
Deltares7 views
DSD-INT 2023 Baseline studies for Strategic Coastal protection for Long Islan... by Deltares
DSD-INT 2023 Baseline studies for Strategic Coastal protection for Long Islan...DSD-INT 2023 Baseline studies for Strategic Coastal protection for Long Islan...
DSD-INT 2023 Baseline studies for Strategic Coastal protection for Long Islan...
Deltares10 views
SUGCON ANZ Presentation V2.1 Final.pptx by Jack Spektor
SUGCON ANZ Presentation V2.1 Final.pptxSUGCON ANZ Presentation V2.1 Final.pptx
SUGCON ANZ Presentation V2.1 Final.pptx
Jack Spektor21 views
DSD-INT 2023 Simulating a falling apron in Delft3D 4 - Engineering Practice -... by Deltares
DSD-INT 2023 Simulating a falling apron in Delft3D 4 - Engineering Practice -...DSD-INT 2023 Simulating a falling apron in Delft3D 4 - Engineering Practice -...
DSD-INT 2023 Simulating a falling apron in Delft3D 4 - Engineering Practice -...
Deltares6 views
MariaDB stored procedures and why they should be improved by Federico Razzoli
MariaDB stored procedures and why they should be improvedMariaDB stored procedures and why they should be improved
MariaDB stored procedures and why they should be improved
Mark Simpson - UKOUG23 - Refactoring Monolithic Oracle Database Applications ... by marksimpsongw
Mark Simpson - UKOUG23 - Refactoring Monolithic Oracle Database Applications ...Mark Simpson - UKOUG23 - Refactoring Monolithic Oracle Database Applications ...
Mark Simpson - UKOUG23 - Refactoring Monolithic Oracle Database Applications ...
marksimpsongw74 views
A first look at MariaDB 11.x features and ideas on how to use them by Federico Razzoli
A first look at MariaDB 11.x features and ideas on how to use themA first look at MariaDB 11.x features and ideas on how to use them
A first look at MariaDB 11.x features and ideas on how to use them
Federico Razzoli44 views
Upgrading Incident Management with Icinga - Icinga Camp Milan 2023 by Icinga
Upgrading Incident Management with Icinga - Icinga Camp Milan 2023Upgrading Incident Management with Icinga - Icinga Camp Milan 2023
Upgrading Incident Management with Icinga - Icinga Camp Milan 2023
Icinga36 views
DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge... by Deltares
DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge...DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge...
DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge...
Deltares16 views
Elevate your SAP landscape's efficiency and performance with HCL Workload Aut... by HCLSoftware
Elevate your SAP landscape's efficiency and performance with HCL Workload Aut...Elevate your SAP landscape's efficiency and performance with HCL Workload Aut...
Elevate your SAP landscape's efficiency and performance with HCL Workload Aut...
HCLSoftware6 views
How to Make the Most of Regression and Unit Testing.pdf by Abhay Kumar
How to Make the Most of Regression and Unit Testing.pdfHow to Make the Most of Regression and Unit Testing.pdf
How to Make the Most of Regression and Unit Testing.pdf
Abhay Kumar10 views
Geospatial Synergy: Amplifying Efficiency with FME & Esri ft. Peak Guest Spea... by Safe Software
Geospatial Synergy: Amplifying Efficiency with FME & Esri ft. Peak Guest Spea...Geospatial Synergy: Amplifying Efficiency with FME & Esri ft. Peak Guest Spea...
Geospatial Synergy: Amplifying Efficiency with FME & Esri ft. Peak Guest Spea...
Safe Software391 views
DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ... by Deltares
DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ...DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ...
DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ...
Deltares9 views
DSD-INT 2023 Delft3D FM Suite 2024.01 1D2D - Beta testing programme - Geertsema by Deltares
DSD-INT 2023 Delft3D FM Suite 2024.01 1D2D - Beta testing programme - GeertsemaDSD-INT 2023 Delft3D FM Suite 2024.01 1D2D - Beta testing programme - Geertsema
DSD-INT 2023 Delft3D FM Suite 2024.01 1D2D - Beta testing programme - Geertsema
Deltares12 views
Neo4j y GenAI by Neo4j
Neo4j y GenAI Neo4j y GenAI
Neo4j y GenAI
Neo4j35 views
Applying Platform Engineering Thinking to Observability.pdf by Natan Yellin
Applying Platform Engineering Thinking to Observability.pdfApplying Platform Engineering Thinking to Observability.pdf
Applying Platform Engineering Thinking to Observability.pdf
Natan Yellin12 views

5 Bullets to Scala Adoption

  • 1. 5 Bullets to Adoption     Tomer  Gabel,  Wix   May  2014  
  • 3. This  is  Spar–  I  mean,  Java   public class Person {! private String name;! private String surname;! private int age;! ! public Person( String name, String surname, int age ) {! this.name = name;! this.surname = surname;! this.age = age;! }! ! public String getName() { return name; }! public String getSurname() { return surname; }! public int getAge() { return age; }! ! @Override! public String toString() { /* … */ }! }  
  • 4. Let’s  make  some  people!   public class SimplePersonGenerator {! ! // Prepare a bunch of useful constants…! ! private static List<String> names;! private static List<String> surnames;! ! static {! names = new ArrayList<>();! names.add( "Jeffrey" );! names.add( "Walter" );! names.add( "Donald" );! ! surnames = new ArrayList<>();! surnames.add( "Lebowsky" );! surnames.add( "Sobchak" );! surnames.add( "Kerabatsos" );! }!
  • 5. IT’S  MADE  OF  PEOPLE!   // Continued from previous slide! ! private static Random random = new Random();! ! public static Person generatePerson( int age ) {! String name = names.get( random.nextInt( names.size() ) );! String surname = surnames.get( random.nextInt( surnames.size() ) );! return new Person( name, surname, age );! }! ! public List<Person> generatePeople( int count, int age ) {! List<Person> people = new ArrayList<>( count );! for ( int i = 0; i < count; i++ )! people.add( generatePerson( age ) );! return Collections.unmodifiableList( people );! }!
  • 6. Scala  syntax  101   Java   public class Person {! private String name;! private String surname;! private int age;! ! public Person( String name, String surname,! int age ) {! this.name = name;! this.surname = surname;! this.age = age;! }! ! public String getName() { return name; }! public String getSurname() { return surname; }! public int getAge() { return age; }! ! @Override! public String toString() { /* … */ }! }    
  • 7. Scala  syntax  101   Java   public class Person {! private String name;! private String surname;! private int age;! ! public Person( String name, String surname,! int age ) {! this.name = name;! this.surname = surname;! this.age = age;! }! ! public String getName() { return name; }! public String getSurname() { return surname; }! public int getAge() { return age; }! ! @Override! public String toString() { /* … */ }! }     Scala   case class Person(! name: String,! surname: String,! age: Int )!    
  • 8. Scala  syntax  101   Java   public class Person {! private String name;! private String surname;! private int age;! ! public Person( String name, String surname,! int age ) {! this.name = name;! this.surname = surname;! this.age = age;! }! ! public String getName() { return name; }! public String getSurname() { return surname; }! public int getAge() { return age; }! ! @Override! public String toString() { /* … */ }! }     Scala   case class Person(! name: String,! surname: String,! age: Int )!   Provides:   –  Constructor   –  Property  geOers   –  hashCode/equals   –  toString   –  …  and  more    
  • 9. Onwards…   Java   public class SimplePersonGenerator {! ! // Prepare a bunch of useful constants…! ! private static List<String> names;! private static List<String> surnames;! ! static {! names = new ArrayList<>();! names.add( "Jeffrey" );! names.add( "Walter" );! names.add( "Donald" );! ! surnames = new ArrayList<>();! surnames.add( "Lebowsky" );! surnames.add( "Sobchak" );! surnames.add( "Kerabatsos" );! }!
  • 10. Onwards…   Java   public class SimplePersonGenerator {! ! // Prepare a bunch of useful constants…! ! private static List<String> names;! private static List<String> surnames;! ! static {! names = new ArrayList<>();! names.add( "Jeffrey" );! names.add( "Walter" );! names.add( "Donald" );! ! surnames = new ArrayList<>();! surnames.add( "Lebowsky" );! surnames.add( "Sobchak" );! surnames.add( "Kerabatsos" );! }! Scala   object NaiveScalaPersonGenerator {! ! private val names: List[ String ] =! List(! "Jeffrey",! "Walter",! "Donald" ! )! ! private val surnames: List[ String ] =! List(! "Lebowsky",! "Sobchak",! "Kerabatsos" ! )!
  • 11. ...  and  finally:   Java   private static Random random = new Random();! ! public static Person generatePerson( int age ) {! String name = names.get( ! random.nextInt( names.size() ) ); ! String surname = surnames.get( ! random.nextInt( surnames.size() ) );! return new Person( name, surname, age );! }! ! public List<Person> generatePeople(! int count, int age ) {! List<Person> people = new ArrayList<>( count );! for ( int i = 0; i < count; i++ )! people.add( generatePerson( age ) );! return Collections.unmodifiableList( people );! }!
  • 12. ...  and  finally:   Java   private static Random random = new Random();! ! public static Person generatePerson( int age ) {! String name = names.get( ! random.nextInt( names.size() ) ); ! String surname = surnames.get( ! random.nextInt( surnames.size() ) );! return new Person( name, surname, age );! }! ! public List<Person> generatePeople(! int count, int age ) {! List<Person> people = new ArrayList<>( count );! for ( int i = 0; i < count; i++ )! people.add( generatePerson( age ) );! return Collections.unmodifiableList( people );! }! Scala   private val random: Random = new Random! ! def generatePerson( age: Int ): Person = {! val name: String =! names( random.nextInt( names.size ) )! val surname: String =! surnames( random.nextInt( surnames.size ) )! new Person( name, surname, age )! }! ! !
  • 13. ...  and  finally:   Java   private static Random random = new Random();! ! public static Person generatePerson( int age ) {! String name = names.get( ! random.nextInt( names.size() ) ); ! String surname = surnames.get( ! random.nextInt( surnames.size() ) );! return new Person( name, surname, age );! }! ! public List<Person> generatePeople(! int count, int age ) {! List<Person> people = new ArrayList<>( count );! for ( int i = 0; i < count; i++ )! people.add( generatePerson( age ) );! return Collections.unmodifiableList( people );! }! Scala   private val random: Random = new Random! ! def generatePerson( age: Int ): Person = {! val name: String =! names( random.nextInt( names.size ) )! val surname: String =! surnames( random.nextInt( surnames.size ) )! new Person( name, surname, age )! }! ! def generatePeople( count: Int, age: Int ):! List[ Person ] = {! val people: mutable.ListBuffer[ Person ] =! mutable.ListBuffer.empty! for ( i <- 0 until count ) {! people.append( generatePerson( age ) )! }! people.result()! }! !
  • 14. 1.  TYPE     INFERENCE  
  • 15. We  started  off  with:   Java   private static Random random = new Random();! ! public static Person generatePerson( int age ) {! String name = names.get( ! random.nextInt( names.size() ) ); ! String surname = surnames.get( ! random.nextInt( surnames.size() ) );! return new Person( name, surname, age );! }! ! public static List<Person> generatePeople(! int count, int age ) {! List<Person> people = new ArrayList<>( count );! for ( int i = 0; i < count; i++ )! people.add( generatePerson( age ) );! return Collections.unmodifiableList( people );! }! Scala   private val random: Random = new Random! ! def generatePerson( age: Int ): Person = {! val name: String =! names( random.nextInt( names.size ) )! val surname: String =! surnames( random.nextInt( surnames.size ) )! new Person( name, surname, age )! }! ! def generatePeople( count: Int, age: Int ):! List[ Person ] = {! val people: mutable.ListBuffer[ Person ] =! mutable.ListBuffer.empty! for ( i <- 0 until count ) {! people.append( generatePerson( age ) )! }! people.result()! }! !
  • 16. Let’s  simplify!   Java   private static Random random = new Random();! ! public static Person generatePerson( int age ) {! String name = names.get( ! random.nextInt( names.size() ) ); ! String surname = surnames.get( ! random.nextInt( surnames.size() ) );! return new Person( name, surname, age );! }! ! public static List<Person> generatePeople(! int count, int age ) {! List<Person> people = new ArrayList<>( count );! for ( int i = 0; i < count; i++ )! people.add( generatePerson( age ) );! return Collections.unmodifiableList( people );! }! Scala   private val random = new Random! ! def generatePerson( age: Int ): Person = {! val name =! names( random.nextInt( names.size ) )! val surname =! surnames( random.nextInt( surnames.size ) )! new Person( name, surname, age )! }! ! def generatePeople( count: Int, age: Int ):! List[ Person ] = {! val people =! mutable.ListBuffer.empty[ Person ]! for ( i <- 0 until count ) {! people.append( generatePerson( age ) )! }! people.result()! }! !
  • 17. Also  works  for  result  types:   Java   private static Random random = new Random();! ! public static Person generatePerson( int age ) {! String name = names.get( ! random.nextInt( names.size() ) ); ! String surname = surnames.get( ! random.nextInt( surnames.size() ) );! return new Person( name, surname, age );! }! ! public static List<Person> generatePeople(! int count, int age ) {! List<Person> people = new ArrayList<>( count );! for ( int i = 0; i < count; i++ )! people.add( generatePerson( age ) );! return Collections.unmodifiableList( people );! }! Scala   private val random = new Random! ! def generatePerson( age: Int ) = {! val name =! names( random.nextInt( names.size ) )! val surname =! surnames( random.nextInt( surnames.size ) )! new Person( name, surname, age )! }! ! def generatePeople( count: Int, age: Int ) = {! val people =! mutable.ListBuffer.empty[ Person ]! for ( i <- 0 until count ) {! people.append( generatePerson( age ) )! }! people.result()! }! !
  • 18. Also  works  for  result  types:   Java   private static Random random = new Random();! ! public static Person generatePerson( int age ) {! String name = names.get( ! random.nextInt( names.size() ) ); ! String surname = surnames.get( ! random.nextInt( surnames.size() ) );! return new Person( name, surname, age );! }! ! public List<Person> generatePeople(! int count, int age ) {! List<Person> people = new ArrayList<>( count );! for ( int i = 0; i < count; i++ )! people.add( generatePerson( age ) );! return Collections.unmodifiableList( people );! }! Scala   private val random = new Random! ! def generatePerson( age: Int ) = {! val name =! names( random.nextInt( names.size ) )! val surname =! surnames( random.nextInt( surnames.size ) )! new Person( name, surname, age )! }! ! def generatePeople( count: Int, age: Int ) = {! val people =! mutable.ListBuffer.empty[ Person ]! for ( i <- 0 until count ) {! people.append( generatePerson( age ) )! }! people.result()! }! ! Not necessarily a good idea. • Code readability • Public APIs • Compilation times
  • 19. Bonus  points:  Named  arguments   Java   private static Random random = new Random();! ! public static Person generatePerson( int age ) {! String name = names.get( ! random.nextInt( names.size() ) ); ! String surname = surnames.get( ! random.nextInt( surnames.size() ) );! return new Person( name, surname, age );! }! ! public static List<Person> generatePeople(! int count, int age ) {! List<Person> people = new ArrayList<>( count );! for ( int i = 0; i < count; i++ )! people.add( generatePerson( age ) );! return Collections.unmodifiableList( people );! }! Scala   private val random = new Random! ! def generatePerson( age: Int ) = Person(! name = names( random.nextInt( names.size ) )! surname =
 surnames( random.nextInt( surnames.size ) )! age = age! )! ! def generatePeople( count: Int, age: Int ) = {! val people =! mutable.ListBuffer.empty[ Person ]! for ( i <- 0 until count ) {! people.append( generatePerson( age ) )! }! people.result()! }! !
  • 20. 2.  THE  COLLECTION  FRAMEWORK  
  • 21. Quick  example   Java   private static Random random = new Random();! ! public static Person generatePerson( int age ) {! String name = names.get( ! random.nextInt( names.size() ) ); ! String surname = surnames.get( ! random.nextInt( surnames.size() ) );! return new Person( name, surname, age );! }! ! public static List<Person> generatePeople(! int count, int age ) {! List<Person> people = new ArrayList<>( count );! for ( int i = 0; i < count; i++ )! people.add( generatePerson( age ) );! return Collections.unmodifiableList( people );! }! Scala   private val random = new Random! ! def generatePerson( age: Int ) = Person(! name = names( random.nextInt( names.size ) )! surname =
 surnames( random.nextInt( surnames.size ) )! age = age! )! ! def generatePeople( count: Int, age: Int ) = {! val people =! mutable.ListBuffer.empty[ Person ]! for ( i <- 0 until count ) {! people.append( generatePerson( age ) )! }! people.result()! }! !
  • 22. Quick  example   Java   private static Random random = new Random();! ! public static Person generatePerson( int age ) {! String name = names.get( ! random.nextInt( names.size() ) ); ! String surname = surnames.get( ! random.nextInt( surnames.size() ) );! return new Person( name, surname, age );! }! ! public static List<Person> generatePeople(! int count, int age ) {! List<Person> people = new ArrayList<>( count );! for ( int i = 0; i < count; i++ )! people.add( generatePerson( age ) );! return Collections.unmodifiableList( people );! }! Scala   private val random = new Random! ! def generatePerson( age: Int ) = Person(! name = names( random.nextInt( names.size ) )! surname =
 surnames( random.nextInt( surnames.size ) )! age = age! )! ! ! ! ! def generatePeople( count: Int, age: Int ) =! List.fill( count ) { generatePerson( age ) }!
  • 23. Scala  collec[ons  primer   // Some data to start with…! val people = generatePeople( 5 )! ! val names = people.map( p => p.name )! ! val adults = people.filter( p => p.age >= 18 )! ! val averageAge = ! people.map( p => p.age ).sum / people.size! ! // Functions are 1st class citizens! def isAdult( p: Person ) = p.age >= 18! val adults2 = people.filter( isAdult )! assert( adults2 == adults )  
  • 24. Maps,  too   val trivial: Map[ String, String ] =! Map( "name" -> "Jeffrey Lebowsky",! "alias" -> "The Dude" )! ! val directory: Map[ Char, List[ Person ] ] =! people! .groupBy( p => p.surname.head.toUpper )! .withDefaultValue( List.empty )! ! val beginningWithK: List[ Person ] =! directory( 'K' )! ! val countByFirstLetter: Map[ Char, Int ] = ! directory.mapValues( list => list.size )!  
  • 25. And  much,  much,  much  more   ! val ( adults, minors ) = people.partition( p => p.age >= 18 )! ! val randomPairs = Random.shuffle( people ).grouped( 2 )! ! val youngest = people.minBy( p => p.age )! ! val oldest = people.maxBy( p => p.age )! ! val hasSeniorCitizens = people.exists( p => p.age >= 65 )  
  • 26. Caveat  emptor   •  Scala  is  flexible   –  You  can  do  the  same  thing  in  mul[ple  ways:     people.foreach( person => println( person ) ) !// "Normal"! people.foreach { person => println( person ) } !// Block-style! people.foreach { println(_) } ! ! !// Placeholder syntax! people.foreach( println ) ! ! !// With function! people foreach println ! ! ! !// Infix notation   •  Stay  sane.  Stay  safe.   –  Pick  a  style  and  s[ck  with  it    
  • 28. Back  in  Java-­‐Land   public class Person {! private String name;! private String surname;! private int age;! ! public Person( String name, String surname, int age ) {! this.name = name;! this.surname = surname;! this.age = age;! }! ! public String getName() { return name; }! public String getSurname() { return surname; }! public int getAge() { return age; }! ! @Override! public String toString() { /* … */ }! }   We want to make these optional.
  • 29. Typical  solu[on  in  Java   public class PartiallyKnownPerson {! private String name;! private String surname;! private Integer age;! ! public PartiallyKnownPerson( String name, String surname, Integer age ) {! this.name = name;! this.surname = surname;! this.age = age;! }! ! public String getName() { return name; }! public String getSurname() { return surname; }! public Integer getAge() { return age; }! ! @Override! public String toString() { /* … */ }! }  
  • 30. This  sucks   public class PartiallyKnownPerson {! private String name;! private String surname;! private Integer age;! ! public PartiallyKnownPerson ( String name, String surname, Integer age ) {! this.name = name;! this.surname = surname;! this.age = age;! }! ! public String getName() { return name; }! public String getSurname() { return surname; }! public Integer getAge() { return age; }! ! @Override! public String toString() { /* … */ }! }   Returned values always need to be checked. Implicit; does not document intent.
  • 31. Falling  back  to  JavaDocs   /**! * Creates a new person.! * @param name The person's name (or {@literal null} if unknown).! * @param surname The person's surname (or {@literal null} if unknown).! * @param age The person's age (or {@literal null} if unknown).! */! public PartiallyKnownPerson( String name, String surname, Integer age ) {! this.name = name;! this.surname = surname;! this.age = age;! }  
  • 32. Falling  back  to  JavaDocs   /**! * Creates a new person.! * @param name The person's name (or {@literal null} if unknown).! * @param surname The person's surname (or {@literal null} if unknown).! * @param age The person's age (or {@literal null} if unknown).! */! public PartiallyKnownPerson( String name, String surname, Integer age ) {! this.name = name;! this.surname = surname;! this.age = age;! }! This still sucks.
  • 33. Falling  back  to  JavaDocs   /**! * Creates a new person.! * @param name The person's name (or {@literal null} if unknown).! * @param surname The person's surname (or {@literal null} if unknown).! * @param age The person's age (or {@literal null} if unknown).! */! public PartiallyKnownPerson( String name, String surname, Integer age ) {! this.name = name;! this.surname = surname;! this.age = age;! }! ! boolean isAdult( Person p ) {! return p.getAge() >= 18; // I love the smell of NPEs in the morning! }   This still sucks.Because:
  • 34. Op[onal  arguments,  the  Scala  way   case class PartiallyKnownPerson( name: Option[ String ] = None,! surname: Option[ String ] = None,! age: Option[ Int ] = None ) {! ! def isAdult = age.map( _ > 18 )! }! ! val person = PartiallyKnownPerson( name = Some( "Brandt" ) )! ! val explicitAccess = person.age.get // <-- NoSuchElementException thrown here! ! val withDefault = person.name.getOrElse( "Anonymous" )! println( "Hello " + withDefault + "!" )! ! // Options are also zero- or single-element collections!! def greet( whom: Iterable[ String ] ) =! whom.foreach { name => println( "hello" + name ) }! greet( person.name )  
  • 36. Back  in  Java  land…   import org.slf4j.Logger;! import org.slf4j.LoggerFactory;! ! public class ClassWithLogs {! private static Logger log = LoggerFactory.getLogger( ClassWithLogs.class );! ! public String getNormalizedName( Person person ) {! log.info( "getNormalizedName called" );! log.debug( "Normalizing " + person.toString() );! String normalizedName = person.getName().toUpperCase().trim();! log.debug( "Normalized name is: " + normalizedName );! return normalizedName;! }! }  
  • 37. …  boilerplate  is  king   import org.slf4j.Logger;! import org.slf4j.LoggerFactory;! ! public class ClassWithLogs {! private static Logger log = LoggerFactory.getLogger( ClassWithLogs.class );! ! public String getNormalizedName( Person person ) {! log.info( "getNormalizedName called" );! log.debug( "Normalizing " + person.toString() );! String normalizedName = person.getName().toUpperCase().trim();! log.debug( "Normalized name is: " + normalizedName );! return normalizedName;! }! }   x1000 classes… Eager evaluation
  • 38. What  can  we  do  about  it?   •  A  solu[on  should:   –  Require  minimal  boilerplate   –  Cause  few  or  no  side-­‐effects   –  Be  composable   –  Perform  well   •  An  abstract  base  class  is   useless   –  Only  one  base  class  allowed   –  No  way  to  do  lazy  evalua[on  
  • 39. Enter:  Scala  traits   trait Logging {! private val log = LoggerFactory.getLogger( this.getClass )! ! protected def logInfo( message: => String ) = ! if ( log.isInfoEnabled ) log.info ( message )! ! protected def logDebug( message: => String ) = ! if ( log.isDebugEnabled ) log.debug( message )! ! protected def logWarn( message: => String ) = ! if ( log.isWarnEnabled ) log.warn ( message )! ! protected def logError( message: => String ) = ! if ( log.isErrorEnabled ) log.error( message )! }! !
  • 40. Boilerplate  is  king   Java   public class ClassWithLogs {! private static Logger log =! LoggerFactory.getLogger(! ClassWithLogs.class );! ! public String getNormalizedName(! Person person ) {! log.info( "getNormalizedName called" );! log.debug( "Normalizing " +! person.toString() );! String normalizedName =! person.getName().toUpperCase().trim();! log.debug( "Normalized name is: " +! normalizedName );! return normalizedName;! }! }   Scala   ! class ClassWithLogs extends Logging {! ! ! ! def getNormalizedName( person: Person ) = {! logInfo( "getNormalizedName called" )! logDebug( "Normalizing " +! person.toString )! val normalizedName =! person.name.toUpperCase.trim! logDebug( "Normalized name is: " +! normalizedName )! normalizedName! }! }  
  • 41. Not  convinced?   •  Consider:   trait Iterator[ T ] {! def hasNext: Boolean! def next: T // Or throw NoSuchElementException! }! ! trait Iterable[ T ] {! def getIterator: Iterator[ T ]! def first: T // Or throw NoSuchElementException! def firstOption: Option[ T ]! def last: T // Or throw NoSuchElementException! def lastOption: Option[ T ]! def size: Int! }     •  What  if  you  need  to  implement  ArrayList,  HashSet,  LinkedList…?  
  • 42. A  saner  op[on   trait BaseIterable[ T ] extends Iterable[ T ] {! ! def firstOption = {! val it = getIterator! if ( it.hasNext ) Some( it.next ) else None! }! ! def first = firstOption.getOrElse( throw new NoSuchElementException )! ! def size = {! val it = getIterator! var count = 0! while ( it.hasNext ) { count += 1; it.next }! count! }! ! // …! }  
  • 43. Massive  win!   case class ArrayList[ T ]( array: Array[ T ] )! extends BaseIterable[ T ] {! ! def getIterator = new Iterator[ T ] {! var index = 0! ! def hasNext = index < array.length! ! def next =! if ( hasNext ) {! val value = array( index )! index += 1! value! } else! throw new NoSuchElementException! }! }   •  No  boilerplate   •  Implement  only  “missing  bits”   •  Mix  and  match  mul[ple  traits!   •  Need  features?   –  Add  to  your  concrete  class   •  Need  performance?   –  Override  the  default   implementa[on  
  • 45. Enhancing  our  domain  model   Java   enum MaritalStatus { ! single, married, divorced, widowed ! }! ! enum Gender { ! male, female ! }! ! class Person {! private String name;! private String surname;! private int age;! private MaritalStatus maritalStatus;! private Gender gender;! // …! }!
  • 46. Enhancing  our  domain  model   Java   enum MaritalStatus { ! single, married, divorced, widowed ! }! ! enum Gender { ! male, female ! }! ! class Person {! private String name;! private String surname;! private int age;! private MaritalStatus maritalStatus;! private Gender gender;! // …! }! Scala   sealed trait MaritalStatus! case object Single extends MaritalStatus! case object Married extends MaritalStatus! case object Divorced extends MaritalStatus! case object Widowed extends MaritalStatus! ! sealed trait Gender! case object Male extends Gender! case object Female extends Gender! ! case class Person(! name: String, surname: String, age: Int,! maritalStatus: Option[ MaritalStatus ],! gender: Option[ Gender ] )!  
  • 47. Saluta[on  genera[on   Java   public String getSalutation() {! if ( gender == null ) return null;! switch( gender ) {! case male:! return "Mr.";! ! case female:! if ( maritalStatus == null )! return "Ms.";! switch( maritalStatus ) {! case single:! return "Miss";! ! case married:! case divorced:! case widowed:! return "Mrs.";! }! }!
  • 48. Saluta[on  genera[on   Java   public String getSalutation() {! if ( gender == null ) return null;! switch( gender ) {! case male:! return "Mr.";! ! case female:! if ( maritalStatus == null )! return "Ms.";! switch( maritalStatus ) {! case single:! return "Miss";! ! case married:! case divorced:! case widowed:! return "Mrs.";! }! }! Scala   ! ! def salutation: Option[ String ] = ! ( gender, maritalStatus ) match {! case (Some(Male ), _ ) => Some("Mr.")! case (Some(Female), Some(Single)) => Some("Miss")! case (Some(Female), None ) => Some("Ms.")! case (Some(Female), _ ) => Some("Mrs.")! case (None , _ ) => None! }  
  • 49. Why  is  this  awesome?   •  Other  use  cases  include:   –  Reac[ng  to  objects  of   unknown  type   –  Decomposing  structures   •  Extensible  via  extractor   objects   •  Compiler  performs   exhaus0veness  check!  
  • 51. What  about  Java  8,  you  ask?   •  Java  8  is  awesome   •  …  it  validates  Scala!   •  But  it’s  not  up  to  par   •  Closures/lambdas:   –  Syntax  is  limited   –  Func[ons  aren’t  1st  class   •  Default  methods  aren’t  a   subs[tute  for  traits   –  No  self-­‐type  annota[on   –  No  visibility  modifiers  (e.g.   protected  members)  
  • 52. Note  that  we  haven’t  covered…   •  For  comprehensions   •  Lazy  vals   •  Tuples   •  Generics   –  Type  bounds   –  Variance   –  Higher-­‐kinded  types   •  Implicits   –  Type  classes   –  Conversions   –  Parameters   •  Func[ons  and  par[al  func[ons   •  Top  and  boOom  types   •  Scoped  imports   •  Extractor  objects  (unapply/-­‐seq)   •  Structural  types   •  Type  members   –  …  and  path-­‐dependent  types   •  Futures  and  promises   •  Macros   •  DSLs  
  • 53. Thanks  you  for  listening!   Ques[ons?   Code  is  on  GitHub   I  am  on  TwiOer  @tomerg   Scala  is  on  the  internetz