Java 8 and beyond, a scala story

Post on 12-Apr-2017

211 views 0 download

Transcript of Java 8 and beyond, a scala story

Java 8 and Beyond,a Scala StoryIttai Zeidman, September 2016http://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-comprehensionsFlexible scopingBuilt-in tuplesHigher-kinded typesDeclaration-site variance

MacrosBottom typesStructural typesType membersPath-dependent typesImplicit conversions

RIGHT. WHY SHOULD YOU CARE?

#1: TRAITS

Ye Olde Loggingimport 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 Loggingimport 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 Loggingimport 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 Loggingimport 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 Traitstrait 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

@ittaizhttp://il.linkedin.com/in/ittaizSample Code:https://github.com/ittaiz/scala-and-java8