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

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
 
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...Philip Schwarz
 

More from Philip Schwarz (20)

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
 
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...
 

Recently uploaded

(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...aditisharan08
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningVitsRangannavar
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 

Recently uploaded (20)

(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learning
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.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.