Java 8 and beyond, a scala story
-
Upload
ittaiz -
Category
Technology
-
view
211 -
download
0
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