SlideShare une entreprise Scribd logo
1  sur  53
Télécharger pour lire hors ligne
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	
  

Contenu connexe

Similaire à 5 Bullets to Scala Adoption

Introduction to Groovy
Introduction to GroovyIntroduction to Groovy
Introduction to Groovy
Anton Arhipov
 
CodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical GroovyCodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical Groovy
Codecamp Romania
 
Scala - fra newbie til ninja på en time
Scala - fra newbie til ninja på en timeScala - fra newbie til ninja på en time
Scala - fra newbie til ninja på en time
karianneberg
 
1.1 motivation
1.1 motivation1.1 motivation
1.1 motivation
wpgreenway
 
About java
About javaAbout java
About java
Jay Xu
 

Similaire à 5 Bullets to Scala Adoption (20)

Introduction to Groovy
Introduction to GroovyIntroduction to Groovy
Introduction to Groovy
 
Features of Kotlin I find exciting
Features of Kotlin I find excitingFeatures of Kotlin I find exciting
Features of Kotlin I find exciting
 
CodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical GroovyCodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical Groovy
 
1.1 motivation
1.1 motivation1.1 motivation
1.1 motivation
 
Scala == Effective Java
Scala == Effective JavaScala == Effective Java
Scala == Effective Java
 
Intermediate Swift Language by Apple
Intermediate Swift Language by AppleIntermediate Swift Language by Apple
Intermediate Swift Language by Apple
 
1.1 motivation
1.1 motivation1.1 motivation
1.1 motivation
 
1.1 motivation
1.1 motivation1.1 motivation
1.1 motivation
 
BEKK Teknologiradar - Kotlin
BEKK Teknologiradar - KotlinBEKK Teknologiradar - Kotlin
BEKK Teknologiradar - Kotlin
 
Scala - fra newbie til ninja på en time
Scala - fra newbie til ninja på en timeScala - fra newbie til ninja på en time
Scala - fra newbie til ninja på en time
 
1.1 motivation
1.1 motivation1.1 motivation
1.1 motivation
 
Swift Study #7
Swift Study #7Swift Study #7
Swift Study #7
 
No excuses, switch to kotlin
No excuses, switch to kotlinNo excuses, switch to kotlin
No excuses, switch to kotlin
 
Java 8 Examples
Java 8 ExamplesJava 8 Examples
Java 8 Examples
 
Scala introduction
Scala introductionScala introduction
Scala introduction
 
About java
About javaAbout java
About java
 
Benefits of Kotlin
Benefits of KotlinBenefits of Kotlin
Benefits of Kotlin
 
Mobile Database Persistence
Mobile Database PersistenceMobile Database Persistence
Mobile Database Persistence
 
Naïveté vs. Experience
Naïveté vs. ExperienceNaïveté vs. Experience
Naïveté vs. Experience
 
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!
Greach 2015 AST – Groovy Transformers: More than meets the eye!
 

Plus de Tomer Gabel

Plus de Tomer Gabel (20)

How shit works: Time
How shit works: TimeHow shit works: Time
How shit works: Time
 
Nondeterministic Software for the Rest of Us
Nondeterministic Software for the Rest of UsNondeterministic Software for the Rest of Us
Nondeterministic Software for the Rest of Us
 
Slaying Sacred Cows: Deconstructing Dependency Injection
Slaying Sacred Cows: Deconstructing Dependency InjectionSlaying Sacred Cows: Deconstructing Dependency Injection
Slaying Sacred Cows: Deconstructing Dependency Injection
 
An Abridged Guide to Event Sourcing
An Abridged Guide to Event SourcingAn Abridged Guide to Event Sourcing
An Abridged Guide to Event Sourcing
 
How shit works: the CPU
How shit works: the CPUHow shit works: the CPU
How shit works: the CPU
 
How Shit Works: Storage
How Shit Works: StorageHow Shit Works: Storage
How Shit Works: Storage
 
Java 8 and Beyond, a Scala Story
Java 8 and Beyond, a Scala StoryJava 8 and Beyond, a Scala Story
Java 8 and Beyond, a Scala Story
 
The Wix Microservice Stack
The Wix Microservice StackThe Wix Microservice Stack
The Wix Microservice Stack
 
Scala Refactoring for Fun and Profit (Japanese subtitles)
Scala Refactoring for Fun and Profit (Japanese subtitles)Scala Refactoring for Fun and Profit (Japanese subtitles)
Scala Refactoring for Fun and Profit (Japanese subtitles)
 
Scala Refactoring for Fun and Profit
Scala Refactoring for Fun and ProfitScala Refactoring for Fun and Profit
Scala Refactoring for Fun and Profit
 
Onboarding at Scale
Onboarding at ScaleOnboarding at Scale
Onboarding at Scale
 
Scala in the Wild
Scala in the WildScala in the Wild
Scala in the Wild
 
Speaking Scala: Refactoring for Fun and Profit (Workshop)
Speaking Scala: Refactoring for Fun and Profit (Workshop)Speaking Scala: Refactoring for Fun and Profit (Workshop)
Speaking Scala: Refactoring for Fun and Profit (Workshop)
 
Put Your Thinking CAP On
Put Your Thinking CAP OnPut Your Thinking CAP On
Put Your Thinking CAP On
 
Leveraging Scala Macros for Better Validation
Leveraging Scala Macros for Better ValidationLeveraging Scala Macros for Better Validation
Leveraging Scala Macros for Better Validation
 
A Field Guide to DSL Design in Scala
A Field Guide to DSL Design in ScalaA Field Guide to DSL Design in Scala
A Field Guide to DSL Design in Scala
 
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)
Functional Leap of Faith (Keynote at JDay Lviv 2014)
 
Scala Back to Basics: Type Classes
Scala Back to Basics: Type ClassesScala Back to Basics: Type Classes
Scala Back to Basics: Type Classes
 
Nashorn: JavaScript that doesn’t suck (ILJUG)
Nashorn: JavaScript that doesn’t suck (ILJUG)Nashorn: JavaScript that doesn’t suck (ILJUG)
Nashorn: JavaScript that doesn’t suck (ILJUG)
 
Ponies and Unicorns With Scala
Ponies and Unicorns With ScalaPonies and Unicorns With Scala
Ponies and Unicorns With Scala
 

Dernier

TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
mohitmore19
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 

Dernier (20)

How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 

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