Java 8 and Beyond,
a Scala Story
Ittai Zeidman, September 2016
http://searchengineland.com/figz/wp-content/seloads/2015/06/evolution-seo-marketer-ss-1920.jpg
Ittai Zeidman
• @ittaiz
• Backend Engineering Lead @
Wix
• Clean Code Fanatic
• Scala lover
• Proud spouse and father of 3
Ittai Zeidman
• @ittaiz
• Backend Engineering Lead @
Wix
• Clean Code Fanatic
• Scala lover
• Proud spouse and father of 3
Preface
Preface
• Java 8 was released
in 2014
Preface
• Java 8 was released
in 2014
• Which begs the
question…
• Is Scala still relevant?
Preface
• Java 8 was released
in 2014
• Which begs the
question…
• Is Scala still relevant?
– Yes.
Preface
• Java 8 was released
in 2014
• Which begs the
question…
• Is Scala still relevant?
– Yes.
Preface
• Java 8 was released
in 2014
• Which begs the
question…
• Is Scala still relevant?
– Yes.
– This talk is about
convincing you!
Quick Agenda
• A bit of history
– The Java-Scala gap
– How Java 8 reduces it
– Remaining gaps
• A deeper dive into:
– Traits
– Type Inference
– Pattern matching
– Implicits
The Java-Scala gap (pre Java
8)Scala’s big selling
points:
• Lambdas
• Collections library
• Traits
• Type inference
• DSLs
• Implicits
The Java-Scala gap
(currently)Scala’s big selling
points:
• Lambdas
• Collections library
• Traits
• Type inference
• DSLs
• Implicits
There’s So Much More…
There’s So Much More…
For-comprehensions
Flexible scoping
Built-in tuples
Higher-kinded types
Declaration-site
variance
Macros
Bottom types
Structural types
Type members
Path-dependent types
Implicit conversions
RIGHT.
WHY SHOULD YOU CARE?
#1: TRAITS
Ye Olde Logging
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;
}
}
Ye Olde Logging
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
Ye Olde Logging
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;
}
}
Eager
Evaluation
Boilerplate
Ye Olde Logging
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;
}
}
Eager
Evaluation
Boilerplate
Improvement?
public class LoggingSample implements Logging {
public String getNormalizedName(Person person) {
logInfo("getNormalizedName called");
logDebug("Normalizing " + person.toString());
String normalizedName =
person.getName().toUpperCase().trim();
logDebug("Normalized name is: " +
normalizedName);
return normalizedName;
}
}
Improvement?
public class LoggingSample implements Logging {
public String getNormalizedName(Person person) {
logInfo("getNormalizedName called");
logDebug("Normalizing " + person.toString());
String normalizedName =
person.getName().toUpperCase().trim();
logDebug("Normalized name is: " +
normalizedName);
return normalizedName;
}
}
Improvement?
public class LoggingSample implements Logging {
public String getNormalizedName(Person person) {
logInfo("getNormalizedName called");
logDebug("Normalizing " + person.toString());
String normalizedName =
person.getName().toUpperCase().trim();
logDebug("Normalized name is: " +
normalizedName);
return normalizedName;
}
}
Java Interface Limitations
Java Interface Limitations
• No fields allowed
Java Interface Limitations
• No fields allowed
– Need Logger instance
Java Interface Limitations
• No fields allowed
– Need Logger instance
– Workaround: getter
public interface Logging {
Logger logger();
default void logDebug(String msg)
{
if (logger().isDebugEnabled())
logger().debug(msg);
}
default void logInfo(String msg) {
if (logger().isInfoEnabled())
logger().info(msg);
}
}
Java Interface Limitations
• No fields allowed
– Need Logger instance
– Workaround: getter
– But... boilerplate :-(
public interface Logging {
Logger logger();
default void logDebug(String msg)
{
if (logger().isDebugEnabled())
logger().debug(msg);
}
default void logInfo(String msg) {
if (logger().isInfoEnabled())
logger().info(msg);
}
}
Java Interface Limitations
• No fields allowed
– Need Logger instance
– Workaround: getter
– But... boilerplate :-(
• Only public methods
– Logging APIs visible!
– … as is logger()
public interface Logging {
Logger logger();
default void logDebug(String msg)
{
if (logger().isDebugEnabled())
logger().debug(msg);
}
default void logInfo(String msg) {
if (logger().isInfoEnabled())
logger().info(msg);
}
}
And Lazy Evaluation?
And Lazy Evaluation?
• Can be implemented with a lambda:
import java.util.function.Supplier;
default void logDebug(Supplier<String> message) {
if (getLogger().isDebugEnabled())
getLogger().debug(message.get());
}
And Lazy Evaluation?
• Can be implemented with a lambda:
import java.util.function.Supplier;
default void logDebug(Supplier<String> message) {
if (getLogger().isDebugEnabled())
getLogger().debug(message.get());
}
• But there’s boilerplate at the call site:
logDebug(() -> "Normalizing " +
person.toString());
Scala Traits
trait Logging {
private val logger =
LoggerFactory.getLogger(getClass)
protected def logWarn(msg: => String) =
if (logger.isWarnEnabled)
logger.warn(msg)
protected def logDebug(msg: => String) =
if (logger.isDebugEnabled)
logger.debug(msg)
}
Scala Traits
• Allow fields
trait Logging {
private val logger =
LoggerFactory.getLogger(getClass)
protected def logWarn(msg: => String) =
if (logger.isWarnEnabled)
logger.warn(msg)
protected def logDebug(msg: => String) =
if (logger.isDebugEnabled)
logger.debug(msg)
}
Scala Traits
• Allow fields
• Participate in
lifecycle
trait Logging {
private val logger =
LoggerFactory.getLogger(getClass)
protected def logWarn(msg: => String) =
if (logger.isWarnEnabled)
logger.warn(msg)
protected def logDebug(msg: => String) =
if (logger.isDebugEnabled)
logger.debug(msg)
}
Scala Traits
• Allow fields
• Participate in
lifecycle
• Support
visibility
trait Logging {
private val logger =
LoggerFactory.getLogger(getClass)
protected def logWarn(msg: => String) =
if (logger.isWarnEnabled)
logger.warn(msg)
protected def logDebug(msg: => String) =
if (logger.isDebugEnabled)
logger.debug(msg)
}
Scala Traits
• Allow fields
• Participate in
lifecycle
• Support
visibility
• Multiple
inheritance!
trait Logging {
private val logger =
LoggerFactory.getLogger(getClass)
protected def logWarn(msg: => String) =
if (logger.isWarnEnabled)
logger.warn(msg)
protected def logDebug(msg: => String) =
if (logger.isDebugEnabled)
logger.debug(msg)
}
Scala Traits
• Allow fields
• Participate in
lifecycle
• Support
visibility
• Multiple
inheritance!
• By Name
eval
trait Logging {
private val logger =
LoggerFactory.getLogger(getClass)
protected def logWarn(msg: => String) =
if (logger.isWarnEnabled)
logger.warn(msg)
protected def logDebug(msg: => String) =
if (logger.isDebugEnabled)
logger.debug(msg)
}
#2: TYPE INFERENCE
*https://visualizingreading.wikispaces.com/file/view/Detective2.gif/214220534/358x190/Detective2.gif
Type Inference
Type Inference
• …the analysis of a program to infer the
types of some or all expressions, usually
at compile time…
Type Inference
• …the analysis of a program to infer the
types of some or all expressions, usually
at compile time…
• A balance between Compile Time Safety
and Verbosity
Java’s Type Inference
Java’s Type Inference
• Generics class ClassWithGenerics {
<T> void generic(T param) {
println(someParameter);
}
}
...
generic(“some param”)
generic(5)
Java’s Type Inference
• Generics
• Project Coin
class ClassWithGenerics {
<T> void generic(T param) {
println(someParameter);
}
}
...
generic(“some param”)
generic(5)
Map<String, Int> keyCounter =
new HashMap<>();
Scala’s Type Inference
Scala’s Type Inference
• Generics
Scala’s Type Inference
• Generics
• Local variables
Scala’s Type Inference
• Generics
• Local variables
• Method return values
LET’S DIVE INTO SOME CODE
#3: PATTERN MATCHING
Java’s Switch Statement
Java’s Switch Statement
• Switch statement is incredibly limited
– Only supports primitives (and strings)
– No arbitrary expressions (e.g. guards)
– No result values
Java’s Switch Statement
• Switch statement is incredibly limited
– Only supports primitives (and strings)
– No arbitrary expressions (e.g. guards)
– No result values
• Workarounds are ugly
– Nested control structures
– Encoding enums instead of using types
Pattern Matching
• Pattern matching in
Scala:
Pattern Matching
• Pattern matching in
Scala:
– Allows arbitrary types
Pattern Matching
• Pattern matching in
Scala:
– Allows arbitrary types
– Supports guards
Pattern Matching
• Pattern matching in
Scala:
– Allows arbitrary types
– Supports guards
– Checks for
exhaustiveness
Pattern Matching
• Pattern matching in
Scala:
– Allows arbitrary types
– Supports guards
– Checks for
exhaustiveness
– User-extensible
Pattern Matching
• Pattern matching in
Scala:
– Allows arbitrary types
– Supports guards
– Checks for
exhaustiveness
– User-extensible
– Ubiquitous
LET’S DIVE INTO SOME CODE
#4: IMPLICITS
Passing Class info (generics)
Passing Class info (generics)
• Java’s idiom is passing Class<T> clazz
around
Passing Class info (generics)
• Java’s idiom is passing Class<T> clazz
around
• Scala supports implicit parameters
– These are filled in by the compiler
– Well-defined rules for implicit search
Enhancing third party code
Enhancing third party code
• Java’s idiom is verbose wrapper methods
Enhancing third party code
• Java’s idiom is verbose wrapper methods
• Scala supports implicit methods
– Verified at compile time
LET’S DIVE INTO SOME CODE
Scala’s Relevance
Scala’s Relevance
• Post Java 8
Scala’s Relevance
• Post Java 8 ✔
Scala’s Relevance
• Post Java 8
• Towards Java 9
✔
Scala’s Relevance
• Post Java 8
• Towards Java 9
✔
✔
Scala’s Relevance
• Post Java 8
• Towards Java 9
• Java 10
✔
✔
Scala’s Relevance
• Post Java 8
• Towards Java 9
• Java 10
✔
✔
?
QUESTIONS?
?
?
?
?
?
?
?
?
?
?
WE’RE DONE
HERE!
Thank you for listening
@ittaiz
http://il.linkedin.com/in/ittaiz
Sample Code:
https://github.com/ittaiz/scala-and-java8

Java 8 and beyond, a scala story

  • 1.
    Java 8 andBeyond, a Scala Story Ittai Zeidman, September 2016 http://searchengineland.com/figz/wp-content/seloads/2015/06/evolution-seo-marketer-ss-1920.jpg
  • 2.
    Ittai Zeidman • @ittaiz •Backend Engineering Lead @ Wix • Clean Code Fanatic • Scala lover • Proud spouse and father of 3
  • 3.
    Ittai Zeidman • @ittaiz •Backend Engineering Lead @ Wix • Clean Code Fanatic • Scala lover • Proud spouse and father of 3
  • 4.
  • 5.
    Preface • Java 8was released in 2014
  • 6.
    Preface • Java 8was released in 2014 • Which begs the question… • Is Scala still relevant?
  • 7.
    Preface • Java 8was released in 2014 • Which begs the question… • Is Scala still relevant? – Yes.
  • 8.
    Preface • Java 8was released in 2014 • Which begs the question… • Is Scala still relevant? – Yes.
  • 9.
    Preface • Java 8was released in 2014 • Which begs the question… • Is Scala still relevant? – Yes. – This talk is about convincing you!
  • 10.
    Quick Agenda • Abit of history – The Java-Scala gap – How Java 8 reduces it – Remaining gaps • A deeper dive into: – Traits – Type Inference – Pattern matching – Implicits
  • 11.
    The Java-Scala gap(pre Java 8)Scala’s big selling points: • Lambdas • Collections library • Traits • Type inference • DSLs • Implicits
  • 12.
    The Java-Scala gap (currently)Scala’sbig selling points: • Lambdas • Collections library • Traits • Type inference • DSLs • Implicits
  • 13.
  • 14.
    There’s So MuchMore… For-comprehensions Flexible scoping Built-in tuples Higher-kinded types Declaration-site variance Macros Bottom types Structural types Type members Path-dependent types Implicit conversions
  • 15.
  • 16.
  • 17.
    Ye Olde Logging importorg.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; } }
  • 18.
    Ye Olde Logging importorg.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
  • 19.
    Ye Olde Logging importorg.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; } } Eager Evaluation Boilerplate
  • 20.
    Ye Olde Logging importorg.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; } } Eager Evaluation Boilerplate
  • 21.
    Improvement? public class LoggingSampleimplements Logging { public String getNormalizedName(Person person) { logInfo("getNormalizedName called"); logDebug("Normalizing " + person.toString()); String normalizedName = person.getName().toUpperCase().trim(); logDebug("Normalized name is: " + normalizedName); return normalizedName; } }
  • 22.
    Improvement? public class LoggingSampleimplements Logging { public String getNormalizedName(Person person) { logInfo("getNormalizedName called"); logDebug("Normalizing " + person.toString()); String normalizedName = person.getName().toUpperCase().trim(); logDebug("Normalized name is: " + normalizedName); return normalizedName; } }
  • 23.
    Improvement? public class LoggingSampleimplements Logging { public String getNormalizedName(Person person) { logInfo("getNormalizedName called"); logDebug("Normalizing " + person.toString()); String normalizedName = person.getName().toUpperCase().trim(); logDebug("Normalized name is: " + normalizedName); return normalizedName; } }
  • 24.
  • 25.
  • 26.
    Java Interface Limitations •No fields allowed – Need Logger instance
  • 27.
    Java Interface Limitations •No fields allowed – Need Logger instance – Workaround: getter public interface Logging { Logger logger(); default void logDebug(String msg) { if (logger().isDebugEnabled()) logger().debug(msg); } default void logInfo(String msg) { if (logger().isInfoEnabled()) logger().info(msg); } }
  • 28.
    Java Interface Limitations •No fields allowed – Need Logger instance – Workaround: getter – But... boilerplate :-( public interface Logging { Logger logger(); default void logDebug(String msg) { if (logger().isDebugEnabled()) logger().debug(msg); } default void logInfo(String msg) { if (logger().isInfoEnabled()) logger().info(msg); } }
  • 29.
    Java Interface Limitations •No fields allowed – Need Logger instance – Workaround: getter – But... boilerplate :-( • Only public methods – Logging APIs visible! – … as is logger() public interface Logging { Logger logger(); default void logDebug(String msg) { if (logger().isDebugEnabled()) logger().debug(msg); } default void logInfo(String msg) { if (logger().isInfoEnabled()) logger().info(msg); } }
  • 30.
  • 31.
    And Lazy Evaluation? •Can be implemented with a lambda: import java.util.function.Supplier; default void logDebug(Supplier<String> message) { if (getLogger().isDebugEnabled()) getLogger().debug(message.get()); }
  • 32.
    And Lazy Evaluation? •Can be implemented with a lambda: import java.util.function.Supplier; default void logDebug(Supplier<String> message) { if (getLogger().isDebugEnabled()) getLogger().debug(message.get()); } • But there’s boilerplate at the call site: logDebug(() -> "Normalizing " + person.toString());
  • 33.
    Scala Traits trait Logging{ private val logger = LoggerFactory.getLogger(getClass) protected def logWarn(msg: => String) = if (logger.isWarnEnabled) logger.warn(msg) protected def logDebug(msg: => String) = if (logger.isDebugEnabled) logger.debug(msg) }
  • 34.
    Scala Traits • Allowfields trait Logging { private val logger = LoggerFactory.getLogger(getClass) protected def logWarn(msg: => String) = if (logger.isWarnEnabled) logger.warn(msg) protected def logDebug(msg: => String) = if (logger.isDebugEnabled) logger.debug(msg) }
  • 35.
    Scala Traits • Allowfields • Participate in lifecycle trait Logging { private val logger = LoggerFactory.getLogger(getClass) protected def logWarn(msg: => String) = if (logger.isWarnEnabled) logger.warn(msg) protected def logDebug(msg: => String) = if (logger.isDebugEnabled) logger.debug(msg) }
  • 36.
    Scala Traits • Allowfields • Participate in lifecycle • Support visibility trait Logging { private val logger = LoggerFactory.getLogger(getClass) protected def logWarn(msg: => String) = if (logger.isWarnEnabled) logger.warn(msg) protected def logDebug(msg: => String) = if (logger.isDebugEnabled) logger.debug(msg) }
  • 37.
    Scala Traits • Allowfields • Participate in lifecycle • Support visibility • Multiple inheritance! trait Logging { private val logger = LoggerFactory.getLogger(getClass) protected def logWarn(msg: => String) = if (logger.isWarnEnabled) logger.warn(msg) protected def logDebug(msg: => String) = if (logger.isDebugEnabled) logger.debug(msg) }
  • 38.
    Scala Traits • Allowfields • Participate in lifecycle • Support visibility • Multiple inheritance! • By Name eval trait Logging { private val logger = LoggerFactory.getLogger(getClass) protected def logWarn(msg: => String) = if (logger.isWarnEnabled) logger.warn(msg) protected def logDebug(msg: => String) = if (logger.isDebugEnabled) logger.debug(msg) }
  • 39.
  • 40.
  • 41.
    Type Inference • …theanalysis of a program to infer the types of some or all expressions, usually at compile time…
  • 42.
    Type Inference • …theanalysis of a program to infer the types of some or all expressions, usually at compile time… • A balance between Compile Time Safety and Verbosity
  • 43.
  • 44.
    Java’s Type Inference •Generics class ClassWithGenerics { <T> void generic(T param) { println(someParameter); } } ... generic(“some param”) generic(5)
  • 45.
    Java’s Type Inference •Generics • Project Coin class ClassWithGenerics { <T> void generic(T param) { println(someParameter); } } ... generic(“some param”) generic(5) Map<String, Int> keyCounter = new HashMap<>();
  • 46.
  • 47.
  • 48.
    Scala’s Type Inference •Generics • Local variables
  • 49.
    Scala’s Type Inference •Generics • Local variables • Method return values
  • 50.
  • 51.
  • 52.
  • 53.
    Java’s Switch Statement •Switch statement is incredibly limited – Only supports primitives (and strings) – No arbitrary expressions (e.g. guards) – No result values
  • 54.
    Java’s Switch Statement •Switch statement is incredibly limited – Only supports primitives (and strings) – No arbitrary expressions (e.g. guards) – No result values • Workarounds are ugly – Nested control structures – Encoding enums instead of using types
  • 55.
    Pattern Matching • Patternmatching in Scala:
  • 56.
    Pattern Matching • Patternmatching in Scala: – Allows arbitrary types
  • 57.
    Pattern Matching • Patternmatching in Scala: – Allows arbitrary types – Supports guards
  • 58.
    Pattern Matching • Patternmatching in Scala: – Allows arbitrary types – Supports guards – Checks for exhaustiveness
  • 59.
    Pattern Matching • Patternmatching in Scala: – Allows arbitrary types – Supports guards – Checks for exhaustiveness – User-extensible
  • 60.
    Pattern Matching • Patternmatching in Scala: – Allows arbitrary types – Supports guards – Checks for exhaustiveness – User-extensible – Ubiquitous
  • 61.
  • 62.
  • 63.
  • 64.
    Passing Class info(generics) • Java’s idiom is passing Class<T> clazz around
  • 65.
    Passing Class info(generics) • Java’s idiom is passing Class<T> clazz around • Scala supports implicit parameters – These are filled in by the compiler – Well-defined rules for implicit search
  • 66.
  • 67.
    Enhancing third partycode • Java’s idiom is verbose wrapper methods
  • 68.
    Enhancing third partycode • Java’s idiom is verbose wrapper methods • Scala supports implicit methods – Verified at compile time
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
    Scala’s Relevance • PostJava 8 • Towards Java 9 ✔
  • 74.
    Scala’s Relevance • PostJava 8 • Towards Java 9 ✔ ✔
  • 75.
    Scala’s Relevance • PostJava 8 • Towards Java 9 • Java 10 ✔ ✔
  • 76.
    Scala’s Relevance • PostJava 8 • Towards Java 9 • Java 10 ✔ ✔ ?
  • 77.
  • 78.
    WE’RE DONE HERE! Thank youfor listening @ittaiz http://il.linkedin.com/in/ittaiz Sample Code: https://github.com/ittaiz/scala-and-java8

Editor's Notes

  • #2 Image: http://searchengineland.com/figz/wp-content/seloads/2015/06/evolution-seo-marketer-ss-1920.jpg
  • #51 Photo source: https://flic.kr/p/3xcrQG
  • #62 Photo source: https://flic.kr/p/3xcrQG
  • #70 Photo source: https://flic.kr/p/3xcrQG
  • #78 Photo source: https://flic.kr/p/3xcrQG