SlideShare a Scribd company logo
1 of 13
Download to read offline
Scala and Java Side by Side
The Result of Martin Fowler’s 1st Refactoring Example
Java’s records, sealed interfaces and text blocks are catching up with Scala’s case classes, sealed traits and multiline strings
Judge for yourself in this quick IDE-based visual comparison
of the Scala and Java translations of Martin Fowler’s refactored Javascript code
Martin Fowler
@martinfowler
@philip_schwarz
slides by https://www.slideshare.net/pjschwarz
@philip_schwarz
Java is in a constant process of catching up with some of the features found in other languages.
With this visual comparison of the Java and Scala translations of the refactored Javascript code from the 1st refactoring example of Martin Fowler’s
famous book, you can get some rapid and concrete evidence of some of the effects that Java’s evolution is having on programming in that language.
The code provides you with a simple example of the following Java features incorporated into long-term support (LTS) version JDK 17 (the previous
LTS version being JDK 11):
• Text blocks (JDK 15)
• Records (JDK 16)
• Sealed interfaces (JDK 17)
If you want to know how the Java and Scala translations of the Javascript code came about, see the following pair of slide decks and repositories
https://github.com/philipschwarz/refactoring-a-first-example-(java|scala)
https://www.slideshare.net/pjschwarz/refactoring-a-first-example-martin-fowlers-first-example-of-refactoring-adapted-to-(java|scala)
@main def main(): Unit =
assert(
statement(invoices(0), plays)
==
"""|Statement for BigCo
| Hamlet: $650.00 (55 seats)
| As You Like It: $580.00 (35 seats)
| Othello: $500.00 (40 seats)
|Amount owed is $1,730.00
|You earned 47 credits
|""".stripMargin
)
assert(
htmlStatement(invoices(0), plays)
==
"""|<h1>Statement for BigCo</h1>
|<table>
|<tr><th>play</th><th>seats</th><th>cost</th></tr>
|<tr><td>Hamlet</td><td>55</td><td>$650.00</td></tr>
|<tr><td>As You Like It</td><td>35</td><td>$580.00</td></tr>
|<tr><td>Othello</td><td>40</td><td>$500.00</td></tr>
|</table>
|<p>Amount owed is <em>$1,730.00</em></p>
|<p>You earned <em>47</em> credits</p>
|""".stripMargin
)
public static void main(String[] args) {
if (!Statement.statement(invoices.get(0), plays).equals(
"""
Statement for BigCo
Hamlet: $650.00 (55 seats)
As You Like It: $580.00 (35 seats)
Othello: $500.00 (40 seats)
Amount owed is $1,730.00
You earned 47 credits
"""
)) throw new AssertionError();
if (!Statement.htmlStatement(invoices.get(0), plays).equals(
"""
<h1>Statement for BigCo</h1>
<table>
<tr><th>play</th><th>seats</th><th>cost</th></tr>
<tr><td>Hamlet</td><td>55</td><td>$650.00</td></tr>
<tr><td>As You Like It</td><td>35</td><td>$580.00</td></tr>
<tr><td>Othello</td><td>40</td><td>$500.00</td></tr>
</table>
<p>Amount owed is <em>$1,730.00</em></p>
<p>You earned <em>47</em> credits</p>
"""
)) throw new AssertionError();
}
static final List<Invoice> invoices =
List.of(
new Invoice(
"BigCo",
List.of(new Performance( "hamlet", 55),
new Performance("as-like", 35),
new Performance("othello", 40))));
static final Map<String,Play> plays = Map.of(
"hamlet" , new Play("Hamlet", "tragedy"),
"as-like", new Play("As You Like It", "comedy"),
"othello", new Play("Othello", "tragedy"));
val invoices: List[Invoice] = List(
Invoice( customer = "BigCo",
performances = List(Performance(playID = "hamlet", audience = 55),
Performance(playID = "as-like", audience = 35),
Performance(playID = "othello", audience = 40)))
)
val plays = Map (
"hamlet" -> Play(name = "Hamlet", `type` = "tragedy"),
"as-like" -> Play(name = "As You Like It", `type` = "comedy"),
"othello" -> Play(name = "Othello", `type` = "tragedy")
)
Statement for BigCo
Hamlet: $650.00 (55 seats)
As You Like It: $580.00 (35 seats)
Othello: $500.00 (40 seats)
Amount owed is $1,730.00
You earned 47 credits
case class Play(
name: String,
`type`: String
)
case class Performance(
playID: String,
audience: Int
)
case class EnrichedPerformance(
playID: String,
play: Play,
audience: Int,
amount: Int,
volumeCredits: Int
)
case class Invoice(
customer: String,
performances: List[Performance]
)
case class StatementData(
customer: String,
performances: List[EnrichedPerformance],
totalAmount: Int,
totalVolumeCredits: Int
)
record Play(
String name,
String type
) { }
record Performance(
String playID,
int audience
) { }
record EnrichedPerformance(
String playID,
Play play,
int audience,
int amount,
int volumeCredits
) { }
record Invoice(
String customer,
List<Performance> performances
) { }
record StatementData(
String customer,
List<EnrichedPerformance> performances,
int totalAmount,
int totalVolumeCredits,
) { }
Statement for BigCo
Hamlet: $650.00 (55 seats)
As You Like It: $580.00 (35 seats)
Othello: $500.00 (40 seats)
Amount owed is $1,730.00
You earned 47 credits
def renderPlainText(data: StatementData): String =
s"Statement for ${data.customer}n" + (
for
perf <- data.performances
yield s" ${perf.play.name}: ${usd(perf.amount/100)} (${perf.audience} seats)n"
).mkString +
s"""|Amount owed is ${usd(data.totalAmount/100)}
|You earned ${data.totalVolumeCredits} credits
|""".stripMargin
def renderHtml(data: StatementData): String =
s"""|<h1>Statement for ${data.customer}</h1>
|<table>
|<tr><th>play</th><th>seats</th><th>cost</th></tr>
|""".stripMargin + (
for
perf <- data.performances
yield s"<tr><td>${perf.play.name}</td><td>${perf.audience}</td>" +
s"<td>${usd(perf.amount/100)}</td></tr>n"
).mkString +
s"""|</table>
|<p>Amount owed is <em>${usd(data.totalAmount/100)}</em></p>
|<p>You earned <em>${data.totalVolumeCredits}</em> credits</p>
|""".stripMargin
static String renderPlainText(StatementData data) {
return
"Statement for %sn".formatted(data.customer()) +
data.performances()
.stream()
.map(p ->
" %s: %s (%d seats)n”
.formatted(p.play().name(), usd(p.amount()/100), p.audience())
).collect(Collectors.joining()) +
"""
Amount owed is %s
You earned %d credits
""".formatted(usd(data.totalAmount()/100), data.totalVolumeCredits());
}
static String renderHtml(StatementData data) {
return
"""
<h1>Statement for %s</h1>
<table>
<tr><th>play</th><th>seats</th><th>cost</th></tr>
""".formatted(data.customer()) +
data
.performances()
.stream()
.map(p -> "<tr><td>%s</td><td>%d</td><td>%s</td></tr>n"
.formatted(p.play().name(),p.audience(),usd(p.amount()/100))
).collect(Collectors.joining()) +
"""
</table>
<p>Amount owed is <em>%s</em></p>
<p>You earned <em>%d</em> credits</p>
""".formatted(usd(data.totalAmount()/100), data.totalVolumeCredits());
}
<h1>Statement for BigCo</h1>
<table>
<tr><th>play</th><th>seats</th><th>cost</th></tr>
<tr><td>Hamlet</td><td>55</td><td>$650.00</td></tr>
<tr><td>As You Like It</td><td>35</td><td>$580.00</td></tr>
<tr><td>Othello</td><td>40</td><td>$500.00</td></tr>
</table>
<p>Amount owed is <em>$1,730.00</em></p>
<p>You earned <em>47</em> credits</p>
Statement for BigCo
Hamlet: $650.00 (55 seats)
As You Like It: $580.00 (35 seats)
Othello: $500.00 (40 seats)
Amount owed is $1,730.00
You earned 47 credits
public class Statement {
static String statement(Invoice invoice, Map<String, Play> plays) {
return renderPlainText(CreateStatementData.createStatementData(invoice,plays));
}
static String htmlStatement(Invoice invoice, Map<String, Play> plays) {
return renderHtml(CreateStatementData.createStatementData(invoice, plays));
}
static String usd(int aNumber) {
final var formatter = NumberFormat.getCurrencyInstance(Locale.US);
formatter.setCurrency(Currency.getInstance(Locale.US));
return formatter.format(aNumber);
}
…
def statement(invoice: Invoice, plays: Map[String, Play]): String =
renderPlainText(createStatementData(invoice,plays))
def htmlStatement(invoice: Invoice, plays: Map[String, Play]): String =
renderHtml(createStatementData(invoice,plays))
def usd(aNumber: Int): String =
val formatter = NumberFormat.getCurrencyInstance(Locale.US)
formatter.setCurrency(Currency.getInstance(Locale.US))
formatter.format(aNumber)
…
Statement for BigCo
Hamlet: $650.00 (55 seats)
As You Like It: $580.00 (35 seats)
Othello: $500.00 (40 seats)
Amount owed is $1,730.00
You earned 47 credits
<h1>Statement for BigCo</h1>
<table>
<tr><th>play</th><th>seats</th><th>cost</th></tr>
<tr><td>Hamlet</td><td>55</td><td>$650.00</td></tr>
<tr><td>As You Like It</td><td>35</td><td>$580.00</td></tr>
<tr><td>Othello</td><td>40</td><td>$500.00</td></tr>
</table>
<p>Amount owed is <em>$1,730.00</em></p>
<p>You earned <em>47</em> credits</p>
public class CreateStatementData {
static StatementData createStatementData(Invoice invoice, Map<String, Play> plays) {
Function<Performance, Play> playFor =
aPerformance -> plays.get(aPerformance.playID());
Function<List<EnrichedPerformance>, Integer> totalVolumeCredits = (performances) ->
performances.stream().mapToInt(EnrichedPerformance::volumeCredits).sum();
Function<List<EnrichedPerformance>, Integer> totalAmount = (performances) ->
performances.stream().mapToInt(EnrichedPerformance::amount).sum();
…
def createStatementData(invoice: Invoice, plays: Map[String,Play]): StatementData =
def playFor(aPerformance: Performance): Play =
plays(aPerformance.playID)
def totalVolumeCredits(performances: List[EnrichedPerformance]): Int =
performances.map(_.volumeCredits).sum
def totalAmount(performances: List[EnrichedPerformance]): Int =
performances.map(_.amount).sum
…
def enrichPerformance(aPerformance: Performance): EnrichedPerformance =
val calculator =
PerformanceCalculator(aPerformance,playFor(aPerformance))
EnrichedPerformance(
aPerformance.playID,
calculator.play,
aPerformance.audience,
calculator.amount,
calculator.volumeCredits)p(_.amount).sum
val enrichedPerformances =
invoice.performances.map(enrichPerformance)
StatementData(
invoice.customer,
enrichedPerformances,
totalAmount(enrichedPerformances),
totalVolumeCredits(enrichedPerformances))
Function<Performance, EnrichedPerformance> enrichPerformance = aPerformance -> {
final var calculator =
PerformanceCalculator.instance(aPerformance,playFor.apply(aPerformance));
return new EnrichedPerformance(
aPerformance.playID(),
calculator.play(),
aPerformance.audience(),
calculator.amount(),
calculator.volumeCredits());
};
final var enrichedPerformances =
invoice.performances().stream().map(enrichPerformance).collect(toList());
return new StatementData(
invoice.customer(),
enrichedPerformances,
totalAmount.apply(enrichedPerformances),
totalVolumeCredits.apply(enrichedPerformances));
}
}
sealed trait PerformanceCalculator:
def performance: Performance
def play: Play
def amount: Int
def volumeCredits: Int = math.max(performance.audience - 30, 0)
object PerformanceCalculator:
def apply(aPerformance: Performance, aPlay: Play): PerformanceCalculator =
aPlay.`type` match
case "tragedy" => TragedyCalculator(aPerformance, aPlay)
case "comedy" => ComedyCalculator(aPerformance, aPlay)
case other => throw IllegalArgumentException(s"unknown type ${aPlay.`type`}")
…
sealed interface PerformanceCalculator {
Performance performance();
Play play();
int amount();
default int volumeCredits() { return Math.max(performance().audience() - 30, 0); }
static PerformanceCalculator instance(Performance aPerformance, Play aPlay) {
return switch (aPlay.type()) {
case "tragedy" -> new TragedyCalculator(aPerformance, aPlay);
case "comedy" -> new ComedyCalculator(aPerformance, aPlay);
default -> throw new IllegalArgumentException(String.format("unknown type '%s'", aPlay.type()));
};
}
}
…
case class TragedyCalculator(performance: Performance, play: Play) extends PerformanceCalculator:
def amount: Int =
val basicAmount = 40_000
val largeAudiencePremiumAmount =
if performance.audience <= 30 then 0 else 1_000 * (performance.audience - 30)
basicAmount + largeAudiencePremiumAmount
…
record TragedyCalculator(Performance performance, Play play) implements PerformanceCalculator {
@Override public int amount() {
final var basicAmount = 40_000;
final var largeAudiencePremiumAmount =
performance.audience() <= 30 ? 0 : 1_000 * (performance.audience() - 30);
return basicAmount + largeAudiencePremiumAmount;
}
}
…
case class ComedyCalculator(performance: Performance, play: Play) extends PerformanceCalculator:
def amount: Int =
val basicAmount = 30_000
val largeAudiencePremiumAmount =
if performance.audience <= 20 then 0 else 10_000 + 500 * (performance.audience - 20)
val audienceSizeAmount = 300 * performance.audience
basicAmount + largeAudiencePremiumAmount + audienceSizeAmount
override def volumeCredits: Int =
super.volumeCredits + math.floor(performance.audience / 5).toInt
record ComedyCalculator(Performance performance, Play play) implements PerformanceCalculator {
@Override public int amount() {
final var basicAmount = 30_000;
final var largeAudiencePremiumAmount =
performance.audience() <= 20 ? 0 : 10_000 + 500 * (performance.audience() - 20);
final var audienceSizeAmount = 300 * performance.audience();
return basicAmount + largeAudiencePremiumAmount + audienceSizeAmount;
}
@Override public int volumeCredits() {
return PerformanceCalculator.super.volumeCredits() + (int) Math.floor(performance().audience() / 5);
}
}
That’s all.
I hope you found it useful.

More Related Content

What's hot

Testing in the World of Functional Programming
Testing in the World of Functional ProgrammingTesting in the World of Functional Programming
Testing in the World of Functional ProgrammingLuka Jacobowitz
 
One Monad to Rule Them All
One Monad to Rule Them AllOne Monad to Rule Them All
One Monad to Rule Them AllJohn De Goes
 
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018John De Goes
 
Post-Free: Life After Free Monads
Post-Free: Life After Free MonadsPost-Free: Life After Free Monads
Post-Free: Life After Free MonadsJohn De Goes
 
Advanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to FreeAdvanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to FreeLuka Jacobowitz
 
The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...
The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...
The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...John De Goes
 
Scala - where objects and functions meet
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meetMario Fusco
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The WildStackMob Inc
 
7 Habits For a More Functional Swift
7 Habits For a More Functional Swift7 Habits For a More Functional Swift
7 Habits For a More Functional SwiftJason Larsen
 
Building a Functional Stream in Scala
Building a Functional Stream in ScalaBuilding a Functional Stream in Scala
Building a Functional Stream in ScalaDerek Wyatt
 
Monoids, monoids, monoids
Monoids, monoids, monoidsMonoids, monoids, monoids
Monoids, monoids, monoidsLuka Jacobowitz
 
Munihac 2018 - Beautiful Template Haskell
Munihac 2018 - Beautiful Template HaskellMunihac 2018 - Beautiful Template Haskell
Munihac 2018 - Beautiful Template HaskellMatthew Pickering
 
Type classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritanceType classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritanceAlexey Raga
 
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kirill Rozov
 
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsQuark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsJohn De Goes
 
The Ring programming language version 1.9 book - Part 31 of 210
The Ring programming language version 1.9 book - Part 31 of 210The Ring programming language version 1.9 book - Part 31 of 210
The Ring programming language version 1.9 book - Part 31 of 210Mahmoud Samir Fayed
 

What's hot (20)

Testing in the World of Functional Programming
Testing in the World of Functional ProgrammingTesting in the World of Functional Programming
Testing in the World of Functional Programming
 
One Monad to Rule Them All
One Monad to Rule Them AllOne Monad to Rule Them All
One Monad to Rule Them All
 
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
 
Post-Free: Life After Free Monads
Post-Free: Life After Free MonadsPost-Free: Life After Free Monads
Post-Free: Life After Free Monads
 
Advanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to FreeAdvanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to Free
 
The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...
The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...
The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...
 
Hammurabi
HammurabiHammurabi
Hammurabi
 
Scala - where objects and functions meet
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meet
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The Wild
 
Lambdaconf2019 talk
Lambdaconf2019 talkLambdaconf2019 talk
Lambdaconf2019 talk
 
7 Habits For a More Functional Swift
7 Habits For a More Functional Swift7 Habits For a More Functional Swift
7 Habits For a More Functional Swift
 
Building a Functional Stream in Scala
Building a Functional Stream in ScalaBuilding a Functional Stream in Scala
Building a Functional Stream in Scala
 
Python : Dictionaries
Python : DictionariesPython : Dictionaries
Python : Dictionaries
 
Monoids, monoids, monoids
Monoids, monoids, monoidsMonoids, monoids, monoids
Monoids, monoids, monoids
 
Munihac 2018 - Beautiful Template Haskell
Munihac 2018 - Beautiful Template HaskellMunihac 2018 - Beautiful Template Haskell
Munihac 2018 - Beautiful Template Haskell
 
Type classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritanceType classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritance
 
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2
 
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsQuark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
 
Map, Reduce and Filter in Swift
Map, Reduce and Filter in SwiftMap, Reduce and Filter in Swift
Map, Reduce and Filter in Swift
 
The Ring programming language version 1.9 book - Part 31 of 210
The Ring programming language version 1.9 book - Part 31 of 210The Ring programming language version 1.9 book - Part 31 of 210
The Ring programming language version 1.9 book - Part 31 of 210
 

Similar to Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refactoring Example

Big Data Analytics with Scala at SCALA.IO 2013
Big Data Analytics with Scala at SCALA.IO 2013Big Data Analytics with Scala at SCALA.IO 2013
Big Data Analytics with Scala at SCALA.IO 2013Samir Bessalah
 
Idoc script beginner guide
Idoc script beginner guide Idoc script beginner guide
Idoc script beginner guide Vinay Kumar
 
Beginning Scala Svcc 2009
Beginning Scala Svcc 2009Beginning Scala Svcc 2009
Beginning Scala Svcc 2009David Pollak
 
Poetry with R -- Dissecting the code
Poetry with R -- Dissecting the codePoetry with R -- Dissecting the code
Poetry with R -- Dissecting the codePeter Solymos
 
My First Rails Plugin - Usertext
My First Rails Plugin - UsertextMy First Rails Plugin - Usertext
My First Rails Plugin - Usertextfrankieroberto
 
Scala 3camp 2011
Scala   3camp 2011Scala   3camp 2011
Scala 3camp 2011Scalac
 
Table of Useful R commands.
Table of Useful R commands.Table of Useful R commands.
Table of Useful R commands.Dr. Volkan OBAN
 
Scala + WattzOn, sitting in a tree....
Scala + WattzOn, sitting in a tree....Scala + WattzOn, sitting in a tree....
Scala + WattzOn, sitting in a tree....Raffi Krikorian
 
Contracts in-clojure-pete
Contracts in-clojure-peteContracts in-clojure-pete
Contracts in-clojure-petejessitron
 
How to Handle NoSQL with a Relational Database
How to Handle NoSQL with a Relational DatabaseHow to Handle NoSQL with a Relational Database
How to Handle NoSQL with a Relational DatabaseDATAVERSITY
 
Os Fetterupdated
Os FetterupdatedOs Fetterupdated
Os Fetterupdatedoscon2007
 
Casting for not so strange actors
Casting for not so strange actorsCasting for not so strange actors
Casting for not so strange actorszucaritask
 

Similar to Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refactoring Example (20)

Apache Velocity 1.6
Apache Velocity 1.6Apache Velocity 1.6
Apache Velocity 1.6
 
Lettering js
Lettering jsLettering js
Lettering js
 
Big Data Analytics with Scala at SCALA.IO 2013
Big Data Analytics with Scala at SCALA.IO 2013Big Data Analytics with Scala at SCALA.IO 2013
Big Data Analytics with Scala at SCALA.IO 2013
 
Idoc script beginner guide
Idoc script beginner guide Idoc script beginner guide
Idoc script beginner guide
 
vue-components.pdf
vue-components.pdfvue-components.pdf
vue-components.pdf
 
Beginning Scala Svcc 2009
Beginning Scala Svcc 2009Beginning Scala Svcc 2009
Beginning Scala Svcc 2009
 
Poetry with R -- Dissecting the code
Poetry with R -- Dissecting the codePoetry with R -- Dissecting the code
Poetry with R -- Dissecting the code
 
My First Rails Plugin - Usertext
My First Rails Plugin - UsertextMy First Rails Plugin - Usertext
My First Rails Plugin - Usertext
 
Lab final
Lab finalLab final
Lab final
 
Oscon 2010 Specs talk
Oscon 2010 Specs talkOscon 2010 Specs talk
Oscon 2010 Specs talk
 
Scala 3camp 2011
Scala   3camp 2011Scala   3camp 2011
Scala 3camp 2011
 
Table of Useful R commands.
Table of Useful R commands.Table of Useful R commands.
Table of Useful R commands.
 
Scala + WattzOn, sitting in a tree....
Scala + WattzOn, sitting in a tree....Scala + WattzOn, sitting in a tree....
Scala + WattzOn, sitting in a tree....
 
Contracts in-clojure-pete
Contracts in-clojure-peteContracts in-clojure-pete
Contracts in-clojure-pete
 
Scala 2 + 2 > 4
Scala 2 + 2 > 4Scala 2 + 2 > 4
Scala 2 + 2 > 4
 
How to Handle NoSQL with a Relational Database
How to Handle NoSQL with a Relational DatabaseHow to Handle NoSQL with a Relational Database
How to Handle NoSQL with a Relational Database
 
Os Fetterupdated
Os FetterupdatedOs Fetterupdated
Os Fetterupdated
 
Casting for not so strange actors
Casting for not so strange actorsCasting for not so strange actors
Casting for not so strange actors
 
Table and Form HTML&CSS
Table and Form HTML&CSSTable and Form HTML&CSS
Table and Form HTML&CSS
 
Php Sq Lite
Php Sq LitePhp Sq Lite
Php Sq Lite
 

More from Philip Schwarz

Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension AidPhilip Schwarz
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
Folding Cheat Sheet #3 - third in a series
Folding Cheat Sheet #3 - third in a seriesFolding Cheat Sheet #3 - third in a series
Folding Cheat Sheet #3 - third in a seriesPhilip Schwarz
 
Folding Cheat Sheet #2 - second in a series
Folding Cheat Sheet #2 - second in a seriesFolding Cheat Sheet #2 - second in a series
Folding Cheat Sheet #2 - second in a seriesPhilip Schwarz
 
Folding Cheat Sheet #1 - first in a series
Folding Cheat Sheet #1 - first in a seriesFolding Cheat Sheet #1 - first in a series
Folding Cheat Sheet #1 - first in a seriesPhilip Schwarz
 
Scala Left Fold Parallelisation - Three Approaches
Scala Left Fold Parallelisation- Three ApproachesScala Left Fold Parallelisation- Three Approaches
Scala Left Fold Parallelisation - Three ApproachesPhilip Schwarz
 
Tagless Final Encoding - Algebras and Interpreters and also Programs
Tagless Final Encoding - Algebras and Interpreters and also ProgramsTagless Final Encoding - Algebras and Interpreters and also Programs
Tagless Final Encoding - Algebras and Interpreters and also ProgramsPhilip Schwarz
 
Fusing Transformations of Strict Scala Collections with Views
Fusing Transformations of Strict Scala Collections with ViewsFusing Transformations of Strict Scala Collections with Views
Fusing Transformations of Strict Scala Collections with ViewsPhilip Schwarz
 
A sighting of traverse_ function in Practical FP in Scala
A sighting of traverse_ function in Practical FP in ScalaA sighting of traverse_ function in Practical FP in Scala
A sighting of traverse_ function in Practical FP in ScalaPhilip Schwarz
 
A sighting of traverseFilter and foldMap in Practical FP in Scala
A sighting of traverseFilter and foldMap in Practical FP in ScalaA sighting of traverseFilter and foldMap in Practical FP in Scala
A sighting of traverseFilter and foldMap in Practical FP in ScalaPhilip Schwarz
 
A sighting of sequence function in Practical FP in Scala
A sighting of sequence function in Practical FP in ScalaA sighting of sequence function in Practical FP in Scala
A sighting of sequence function in Practical FP in ScalaPhilip Schwarz
 
N-Queens Combinatorial Puzzle meets Cats
N-Queens Combinatorial Puzzle meets CatsN-Queens Combinatorial Puzzle meets Cats
N-Queens Combinatorial Puzzle meets CatsPhilip Schwarz
 
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...Philip Schwarz
 
The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...Philip Schwarz
 
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
Nat, List and Option Monoids -from scratch -Combining and Folding -an exampleNat, List and Option Monoids -from scratch -Combining and Folding -an example
Nat, List and Option Monoids - from scratch - Combining and Folding - an examplePhilip Schwarz
 
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
Nat, List and Option Monoids -from scratch -Combining and Folding -an exampleNat, List and Option Monoids -from scratch -Combining and Folding -an example
Nat, List and Option Monoids - from scratch - Combining and Folding - an examplePhilip Schwarz
 
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...Philip Schwarz
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...Philip Schwarz
 
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...
Algebraic Data Types forData Oriented Programming - From Haskell and Scala t...Algebraic Data Types forData Oriented Programming - From Haskell and Scala t...
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...Philip Schwarz
 
Jordan Peterson - The pursuit of meaning and related ethical axioms
Jordan Peterson - The pursuit of meaning and related ethical axiomsJordan Peterson - The pursuit of meaning and related ethical axioms
Jordan Peterson - The pursuit of meaning and related ethical axiomsPhilip Schwarz
 

More from Philip Schwarz (20)

Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
Folding Cheat Sheet #3 - third in a series
Folding Cheat Sheet #3 - third in a seriesFolding Cheat Sheet #3 - third in a series
Folding Cheat Sheet #3 - third in a series
 
Folding Cheat Sheet #2 - second in a series
Folding Cheat Sheet #2 - second in a seriesFolding Cheat Sheet #2 - second in a series
Folding Cheat Sheet #2 - second in a series
 
Folding Cheat Sheet #1 - first in a series
Folding Cheat Sheet #1 - first in a seriesFolding Cheat Sheet #1 - first in a series
Folding Cheat Sheet #1 - first in a series
 
Scala Left Fold Parallelisation - Three Approaches
Scala Left Fold Parallelisation- Three ApproachesScala Left Fold Parallelisation- Three Approaches
Scala Left Fold Parallelisation - Three Approaches
 
Tagless Final Encoding - Algebras and Interpreters and also Programs
Tagless Final Encoding - Algebras and Interpreters and also ProgramsTagless Final Encoding - Algebras and Interpreters and also Programs
Tagless Final Encoding - Algebras and Interpreters and also Programs
 
Fusing Transformations of Strict Scala Collections with Views
Fusing Transformations of Strict Scala Collections with ViewsFusing Transformations of Strict Scala Collections with Views
Fusing Transformations of Strict Scala Collections with Views
 
A sighting of traverse_ function in Practical FP in Scala
A sighting of traverse_ function in Practical FP in ScalaA sighting of traverse_ function in Practical FP in Scala
A sighting of traverse_ function in Practical FP in Scala
 
A sighting of traverseFilter and foldMap in Practical FP in Scala
A sighting of traverseFilter and foldMap in Practical FP in ScalaA sighting of traverseFilter and foldMap in Practical FP in Scala
A sighting of traverseFilter and foldMap in Practical FP in Scala
 
A sighting of sequence function in Practical FP in Scala
A sighting of sequence function in Practical FP in ScalaA sighting of sequence function in Practical FP in Scala
A sighting of sequence function in Practical FP in Scala
 
N-Queens Combinatorial Puzzle meets Cats
N-Queens Combinatorial Puzzle meets CatsN-Queens Combinatorial Puzzle meets Cats
N-Queens Combinatorial Puzzle meets Cats
 
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
 
The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...
 
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
Nat, List and Option Monoids -from scratch -Combining and Folding -an exampleNat, List and Option Monoids -from scratch -Combining and Folding -an example
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
 
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
Nat, List and Option Monoids -from scratch -Combining and Folding -an exampleNat, List and Option Monoids -from scratch -Combining and Folding -an example
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
 
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
 
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...
Algebraic Data Types forData Oriented Programming - From Haskell and Scala t...Algebraic Data Types forData Oriented Programming - From Haskell and Scala t...
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...
 
Jordan Peterson - The pursuit of meaning and related ethical axioms
Jordan Peterson - The pursuit of meaning and related ethical axiomsJordan Peterson - The pursuit of meaning and related ethical axioms
Jordan Peterson - The pursuit of meaning and related ethical axioms
 

Recently uploaded

The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfonteinmasabamasaba
 
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 ...harshavardhanraghave
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplatePresentation.STUDIO
 
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburgmasabamasaba
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrandmasabamasaba
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...masabamasaba
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrainmasabamasaba
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesVictorSzoltysek
 
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 GoalsJhone kinadey
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...Nitya salvi
 
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfThe Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfayushiqss
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park masabamasaba
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareJim McKeeth
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfonteinmasabamasaba
 
SHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions PresentationSHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions PresentationShrmpro
 
+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
 
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..pdfPearlKirahMaeRagusta1
 

Recently uploaded (20)

The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
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 ...
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
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
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
 
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfThe Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
SHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions PresentationSHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions Presentation
 
+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...
 
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
 

Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refactoring Example

  • 1. Scala and Java Side by Side The Result of Martin Fowler’s 1st Refactoring Example Java’s records, sealed interfaces and text blocks are catching up with Scala’s case classes, sealed traits and multiline strings Judge for yourself in this quick IDE-based visual comparison of the Scala and Java translations of Martin Fowler’s refactored Javascript code Martin Fowler @martinfowler @philip_schwarz slides by https://www.slideshare.net/pjschwarz
  • 2. @philip_schwarz Java is in a constant process of catching up with some of the features found in other languages. With this visual comparison of the Java and Scala translations of the refactored Javascript code from the 1st refactoring example of Martin Fowler’s famous book, you can get some rapid and concrete evidence of some of the effects that Java’s evolution is having on programming in that language. The code provides you with a simple example of the following Java features incorporated into long-term support (LTS) version JDK 17 (the previous LTS version being JDK 11): • Text blocks (JDK 15) • Records (JDK 16) • Sealed interfaces (JDK 17) If you want to know how the Java and Scala translations of the Javascript code came about, see the following pair of slide decks and repositories https://github.com/philipschwarz/refactoring-a-first-example-(java|scala) https://www.slideshare.net/pjschwarz/refactoring-a-first-example-martin-fowlers-first-example-of-refactoring-adapted-to-(java|scala)
  • 3. @main def main(): Unit = assert( statement(invoices(0), plays) == """|Statement for BigCo | Hamlet: $650.00 (55 seats) | As You Like It: $580.00 (35 seats) | Othello: $500.00 (40 seats) |Amount owed is $1,730.00 |You earned 47 credits |""".stripMargin ) assert( htmlStatement(invoices(0), plays) == """|<h1>Statement for BigCo</h1> |<table> |<tr><th>play</th><th>seats</th><th>cost</th></tr> |<tr><td>Hamlet</td><td>55</td><td>$650.00</td></tr> |<tr><td>As You Like It</td><td>35</td><td>$580.00</td></tr> |<tr><td>Othello</td><td>40</td><td>$500.00</td></tr> |</table> |<p>Amount owed is <em>$1,730.00</em></p> |<p>You earned <em>47</em> credits</p> |""".stripMargin ) public static void main(String[] args) { if (!Statement.statement(invoices.get(0), plays).equals( """ Statement for BigCo Hamlet: $650.00 (55 seats) As You Like It: $580.00 (35 seats) Othello: $500.00 (40 seats) Amount owed is $1,730.00 You earned 47 credits """ )) throw new AssertionError(); if (!Statement.htmlStatement(invoices.get(0), plays).equals( """ <h1>Statement for BigCo</h1> <table> <tr><th>play</th><th>seats</th><th>cost</th></tr> <tr><td>Hamlet</td><td>55</td><td>$650.00</td></tr> <tr><td>As You Like It</td><td>35</td><td>$580.00</td></tr> <tr><td>Othello</td><td>40</td><td>$500.00</td></tr> </table> <p>Amount owed is <em>$1,730.00</em></p> <p>You earned <em>47</em> credits</p> """ )) throw new AssertionError(); }
  • 4. static final List<Invoice> invoices = List.of( new Invoice( "BigCo", List.of(new Performance( "hamlet", 55), new Performance("as-like", 35), new Performance("othello", 40)))); static final Map<String,Play> plays = Map.of( "hamlet" , new Play("Hamlet", "tragedy"), "as-like", new Play("As You Like It", "comedy"), "othello", new Play("Othello", "tragedy")); val invoices: List[Invoice] = List( Invoice( customer = "BigCo", performances = List(Performance(playID = "hamlet", audience = 55), Performance(playID = "as-like", audience = 35), Performance(playID = "othello", audience = 40))) ) val plays = Map ( "hamlet" -> Play(name = "Hamlet", `type` = "tragedy"), "as-like" -> Play(name = "As You Like It", `type` = "comedy"), "othello" -> Play(name = "Othello", `type` = "tragedy") ) Statement for BigCo Hamlet: $650.00 (55 seats) As You Like It: $580.00 (35 seats) Othello: $500.00 (40 seats) Amount owed is $1,730.00 You earned 47 credits
  • 5. case class Play( name: String, `type`: String ) case class Performance( playID: String, audience: Int ) case class EnrichedPerformance( playID: String, play: Play, audience: Int, amount: Int, volumeCredits: Int ) case class Invoice( customer: String, performances: List[Performance] ) case class StatementData( customer: String, performances: List[EnrichedPerformance], totalAmount: Int, totalVolumeCredits: Int ) record Play( String name, String type ) { } record Performance( String playID, int audience ) { } record EnrichedPerformance( String playID, Play play, int audience, int amount, int volumeCredits ) { } record Invoice( String customer, List<Performance> performances ) { } record StatementData( String customer, List<EnrichedPerformance> performances, int totalAmount, int totalVolumeCredits, ) { } Statement for BigCo Hamlet: $650.00 (55 seats) As You Like It: $580.00 (35 seats) Othello: $500.00 (40 seats) Amount owed is $1,730.00 You earned 47 credits
  • 6. def renderPlainText(data: StatementData): String = s"Statement for ${data.customer}n" + ( for perf <- data.performances yield s" ${perf.play.name}: ${usd(perf.amount/100)} (${perf.audience} seats)n" ).mkString + s"""|Amount owed is ${usd(data.totalAmount/100)} |You earned ${data.totalVolumeCredits} credits |""".stripMargin def renderHtml(data: StatementData): String = s"""|<h1>Statement for ${data.customer}</h1> |<table> |<tr><th>play</th><th>seats</th><th>cost</th></tr> |""".stripMargin + ( for perf <- data.performances yield s"<tr><td>${perf.play.name}</td><td>${perf.audience}</td>" + s"<td>${usd(perf.amount/100)}</td></tr>n" ).mkString + s"""|</table> |<p>Amount owed is <em>${usd(data.totalAmount/100)}</em></p> |<p>You earned <em>${data.totalVolumeCredits}</em> credits</p> |""".stripMargin static String renderPlainText(StatementData data) { return "Statement for %sn".formatted(data.customer()) + data.performances() .stream() .map(p -> " %s: %s (%d seats)n” .formatted(p.play().name(), usd(p.amount()/100), p.audience()) ).collect(Collectors.joining()) + """ Amount owed is %s You earned %d credits """.formatted(usd(data.totalAmount()/100), data.totalVolumeCredits()); } static String renderHtml(StatementData data) { return """ <h1>Statement for %s</h1> <table> <tr><th>play</th><th>seats</th><th>cost</th></tr> """.formatted(data.customer()) + data .performances() .stream() .map(p -> "<tr><td>%s</td><td>%d</td><td>%s</td></tr>n" .formatted(p.play().name(),p.audience(),usd(p.amount()/100)) ).collect(Collectors.joining()) + """ </table> <p>Amount owed is <em>%s</em></p> <p>You earned <em>%d</em> credits</p> """.formatted(usd(data.totalAmount()/100), data.totalVolumeCredits()); } <h1>Statement for BigCo</h1> <table> <tr><th>play</th><th>seats</th><th>cost</th></tr> <tr><td>Hamlet</td><td>55</td><td>$650.00</td></tr> <tr><td>As You Like It</td><td>35</td><td>$580.00</td></tr> <tr><td>Othello</td><td>40</td><td>$500.00</td></tr> </table> <p>Amount owed is <em>$1,730.00</em></p> <p>You earned <em>47</em> credits</p> Statement for BigCo Hamlet: $650.00 (55 seats) As You Like It: $580.00 (35 seats) Othello: $500.00 (40 seats) Amount owed is $1,730.00 You earned 47 credits
  • 7. public class Statement { static String statement(Invoice invoice, Map<String, Play> plays) { return renderPlainText(CreateStatementData.createStatementData(invoice,plays)); } static String htmlStatement(Invoice invoice, Map<String, Play> plays) { return renderHtml(CreateStatementData.createStatementData(invoice, plays)); } static String usd(int aNumber) { final var formatter = NumberFormat.getCurrencyInstance(Locale.US); formatter.setCurrency(Currency.getInstance(Locale.US)); return formatter.format(aNumber); } … def statement(invoice: Invoice, plays: Map[String, Play]): String = renderPlainText(createStatementData(invoice,plays)) def htmlStatement(invoice: Invoice, plays: Map[String, Play]): String = renderHtml(createStatementData(invoice,plays)) def usd(aNumber: Int): String = val formatter = NumberFormat.getCurrencyInstance(Locale.US) formatter.setCurrency(Currency.getInstance(Locale.US)) formatter.format(aNumber) … Statement for BigCo Hamlet: $650.00 (55 seats) As You Like It: $580.00 (35 seats) Othello: $500.00 (40 seats) Amount owed is $1,730.00 You earned 47 credits <h1>Statement for BigCo</h1> <table> <tr><th>play</th><th>seats</th><th>cost</th></tr> <tr><td>Hamlet</td><td>55</td><td>$650.00</td></tr> <tr><td>As You Like It</td><td>35</td><td>$580.00</td></tr> <tr><td>Othello</td><td>40</td><td>$500.00</td></tr> </table> <p>Amount owed is <em>$1,730.00</em></p> <p>You earned <em>47</em> credits</p>
  • 8. public class CreateStatementData { static StatementData createStatementData(Invoice invoice, Map<String, Play> plays) { Function<Performance, Play> playFor = aPerformance -> plays.get(aPerformance.playID()); Function<List<EnrichedPerformance>, Integer> totalVolumeCredits = (performances) -> performances.stream().mapToInt(EnrichedPerformance::volumeCredits).sum(); Function<List<EnrichedPerformance>, Integer> totalAmount = (performances) -> performances.stream().mapToInt(EnrichedPerformance::amount).sum(); … def createStatementData(invoice: Invoice, plays: Map[String,Play]): StatementData = def playFor(aPerformance: Performance): Play = plays(aPerformance.playID) def totalVolumeCredits(performances: List[EnrichedPerformance]): Int = performances.map(_.volumeCredits).sum def totalAmount(performances: List[EnrichedPerformance]): Int = performances.map(_.amount).sum …
  • 9. def enrichPerformance(aPerformance: Performance): EnrichedPerformance = val calculator = PerformanceCalculator(aPerformance,playFor(aPerformance)) EnrichedPerformance( aPerformance.playID, calculator.play, aPerformance.audience, calculator.amount, calculator.volumeCredits)p(_.amount).sum val enrichedPerformances = invoice.performances.map(enrichPerformance) StatementData( invoice.customer, enrichedPerformances, totalAmount(enrichedPerformances), totalVolumeCredits(enrichedPerformances)) Function<Performance, EnrichedPerformance> enrichPerformance = aPerformance -> { final var calculator = PerformanceCalculator.instance(aPerformance,playFor.apply(aPerformance)); return new EnrichedPerformance( aPerformance.playID(), calculator.play(), aPerformance.audience(), calculator.amount(), calculator.volumeCredits()); }; final var enrichedPerformances = invoice.performances().stream().map(enrichPerformance).collect(toList()); return new StatementData( invoice.customer(), enrichedPerformances, totalAmount.apply(enrichedPerformances), totalVolumeCredits.apply(enrichedPerformances)); } }
  • 10. sealed trait PerformanceCalculator: def performance: Performance def play: Play def amount: Int def volumeCredits: Int = math.max(performance.audience - 30, 0) object PerformanceCalculator: def apply(aPerformance: Performance, aPlay: Play): PerformanceCalculator = aPlay.`type` match case "tragedy" => TragedyCalculator(aPerformance, aPlay) case "comedy" => ComedyCalculator(aPerformance, aPlay) case other => throw IllegalArgumentException(s"unknown type ${aPlay.`type`}") … sealed interface PerformanceCalculator { Performance performance(); Play play(); int amount(); default int volumeCredits() { return Math.max(performance().audience() - 30, 0); } static PerformanceCalculator instance(Performance aPerformance, Play aPlay) { return switch (aPlay.type()) { case "tragedy" -> new TragedyCalculator(aPerformance, aPlay); case "comedy" -> new ComedyCalculator(aPerformance, aPlay); default -> throw new IllegalArgumentException(String.format("unknown type '%s'", aPlay.type())); }; } } …
  • 11. case class TragedyCalculator(performance: Performance, play: Play) extends PerformanceCalculator: def amount: Int = val basicAmount = 40_000 val largeAudiencePremiumAmount = if performance.audience <= 30 then 0 else 1_000 * (performance.audience - 30) basicAmount + largeAudiencePremiumAmount … record TragedyCalculator(Performance performance, Play play) implements PerformanceCalculator { @Override public int amount() { final var basicAmount = 40_000; final var largeAudiencePremiumAmount = performance.audience() <= 30 ? 0 : 1_000 * (performance.audience() - 30); return basicAmount + largeAudiencePremiumAmount; } } …
  • 12. case class ComedyCalculator(performance: Performance, play: Play) extends PerformanceCalculator: def amount: Int = val basicAmount = 30_000 val largeAudiencePremiumAmount = if performance.audience <= 20 then 0 else 10_000 + 500 * (performance.audience - 20) val audienceSizeAmount = 300 * performance.audience basicAmount + largeAudiencePremiumAmount + audienceSizeAmount override def volumeCredits: Int = super.volumeCredits + math.floor(performance.audience / 5).toInt record ComedyCalculator(Performance performance, Play play) implements PerformanceCalculator { @Override public int amount() { final var basicAmount = 30_000; final var largeAudiencePremiumAmount = performance.audience() <= 20 ? 0 : 10_000 + 500 * (performance.audience() - 20); final var audienceSizeAmount = 300 * performance.audience(); return basicAmount + largeAudiencePremiumAmount + audienceSizeAmount; } @Override public int volumeCredits() { return PerformanceCalculator.super.volumeCredits() + (int) Math.floor(performance().audience() / 5); } }
  • 13. That’s all. I hope you found it useful.