5 Bullets to Scala Adoption
-
Upload
tomer-gabel -
Category
Software
-
view
771 -
download
3
description
Transcript of 5 Bullets to Scala Adoption
![Page 1: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/1.jpg)
5 Bullets to
Adoption
Tomer Gabel, Wix May 2014
![Page 2: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/2.jpg)
WARMUP: THE BASICS
![Page 3: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/3.jpg)
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() { /* … */ }!}
![Page 4: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/4.jpg)
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" );! }!
![Page 5: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/5.jpg)
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 );! }!
![Page 6: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/6.jpg)
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() { /* … */ }!
}
![Page 7: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/7.jpg)
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 )!
![Page 8: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/8.jpg)
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
![Page 9: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/9.jpg)
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" );! }!
![Page 10: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/10.jpg)
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" !
)!
![Page 11: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/11.jpg)
... 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 );!}!
![Page 12: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/12.jpg)
... 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 )!}!!!
![Page 13: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/13.jpg)
... 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()!}!!
![Page 14: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/14.jpg)
1. TYPE INFERENCE
![Page 15: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/15.jpg)
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()!}!!
![Page 16: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/16.jpg)
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()!}!!
![Page 17: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/17.jpg)
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()!}!!
![Page 18: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/18.jpg)
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
![Page 19: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/19.jpg)
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()!}!
!
![Page 20: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/20.jpg)
2. THE COLLECTION FRAMEWORK
![Page 21: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/21.jpg)
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()!}!
!
![Page 22: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/22.jpg)
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 ) }!
![Page 23: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/23.jpg)
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 )
![Page 24: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/24.jpg)
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 )!
![Page 25: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/25.jpg)
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 )
![Page 26: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/26.jpg)
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
![Page 27: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/27.jpg)
3. OPTIONS
![Page 28: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/28.jpg)
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.
![Page 29: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/29.jpg)
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() { /* … */ }!}
![Page 30: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/30.jpg)
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.
![Page 31: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/31.jpg)
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;!}
![Page 32: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/32.jpg)
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.
![Page 33: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/33.jpg)
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:
![Page 34: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/34.jpg)
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 )
![Page 35: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/35.jpg)
4. TRAITS
![Page 36: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/36.jpg)
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;! }!}
![Page 37: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/37.jpg)
… 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
![Page 38: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/38.jpg)
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
![Page 39: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/39.jpg)
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 )!}!!
![Page 40: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/40.jpg)
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! }!}
![Page 41: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/41.jpg)
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…?
![Page 42: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/42.jpg)
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!
}!! // …! }
![Page 43: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/43.jpg)
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
![Page 44: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/44.jpg)
5. PATTERN MATCHING
![Page 45: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/45.jpg)
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;!
// …!}!
![Page 46: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/46.jpg)
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 ] )!
![Page 47: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/47.jpg)
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.";! }! }!
![Page 48: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/48.jpg)
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!
}
![Page 49: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/49.jpg)
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!
![Page 50: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/50.jpg)
WE’RE ALMOST���DONE!
![Page 51: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/51.jpg)
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)
![Page 52: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/52.jpg)
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
![Page 53: 5 Bullets to Scala Adoption](https://reader034.fdocuments.net/reader034/viewer/2022050918/53fdfb2e8d7f72a81c8b4c28/html5/thumbnails/53.jpg)
Thanks you for listening! Ques[ons?
Code is on GitHub I am on TwiOer @tomerg Scala is on the internetz