SlideShare a Scribd company logo
JVM Languages – Performance
Comparing the performance of various JVM
languages and programming paradigms.
Corneil du Plessis
Introduction
● Programmer since 1985
● Smallest to very large systems.
● Cobol, Pascal, Algol, C/C++, Java, Scala, Groovy and
other JVM languages.
● Scientific instrumentation, Sports event management,
Mining, Banking, Treasury and Insurance.
● Software Architect (coding included)
Why a Comparison?
● Multi-paradigm programming
● Code complexity
● Runtime complexity
Challenge
● FizzBuzz
– Imperative
– Functional
● Languages
– Java
– Groovy
– Kotlin
– Scala
FizzBuzz
● Write a program that prints the numbers from 1 to 100.
● But for multiples of three print “Fizz” instead of the number and for the
multiples of five print “Buzz”.
● For numbers which are multiples of both three and five print “FizzBuzz”
● Pseudo Code
for i in 1 to 100
if i multiple of 15 print ‘FizzBuzz’
else if i multiple of 3 print ‘Fizz’
else if i multiple of 5 print ‘Buzz’
else print i
print newline
Imperative Code – Java
public static void imperative(PrintWriter writer) {
for(int i = 1; i <= 100; i++) {
if (i % 15 == 0) {
writer.println("FizzBuzz");
} else if (i % 3 == 0) {
writer.println("Fizz");
} else if (i % 5 == 0) {
writer.println("Buzz");
} else {
writer.println(i);
}
}
}
Imperative Code - Groovy
static imperative(PrintWriter writer) {
for(int i = 1; i <= 100; i++) {
if (i % 15 == 0) {
writer.println("FizzBuzz");
} else if (i % 3 == 0) {
writer.println("Fizz");
} else if (i % 5 == 0) {
writer.println("Buzz");
} else {
writer.println(i);
}
}
}
Imperative Code – Kotlin
@JvmStatic fun imperative(printWriter: PrintWriter) {
for (i in 1..100) {
when {
i % 15 == 0 -> printWriter.println("FizzBuzz")
i % 3 == 0 -> printWriter.println("Fizz")
i % 5 == 0 -> printWriter.println("Buzz")
else -> printWriter.println(i)
}
}
}
Imperative Code – Scala
def imperative(writer: PrintWriter): Unit = {
for (i <- 1 to 100) {
i match {
case x if x % 15 == 0 => writer.println("FizzBuzz")
case x if x % 5 == 0 => writer.println("Buzz")
case x if x % 3 == 0 => writer.println("Fizz")
case x => writer.println(x)
}
}
}
Imperative Performance
Language Ops / second % of best
Java 3470211.76 100.00%
Groovy 3457836.97 99.64%
Kotlin 3405441.23 98.13%
Scala 2444048.87 70.43%
Java Groovy Kotlin Scala
0
500000
1000000
1500000
2000000
2500000
3000000
3500000
4000000
Ops / second
Functional Code – Java
MapReduce
static class Replacement {
final Predicate<Integer> when;
final String output;
Replacement(Predicate<Integer> when, String output) {
this.output = output;
this.when = when;
}
}
static List<Replacement> fizzAndOrBuzz =
Collections.unmodifiableList(Arrays.asList(
new Replacement(i -> i % 3 == 0, "Fizz"),
new Replacement(i -> i % 5 == 0, "Buzz")
));
static String replace(final Integer i, final List<Replacement> rules) {
return rules.stream()
.filter(r -> r.when.test(i))
.map(r -> r.output)
.reduce(String::concat)
.orElse(Integer.toString(i));
}
static String fizzBuzz(final Integer i) {
return replace(i, fizzAndOrBuzz);
}
public static void functionalMapReduce(final PrintWriter writer) {
IntStream.range(1, 101)
.mapToObj(FizzBuzzFunctionalMapReduce::fizzBuzz)
.forEach((i) -> writer.println(i));
}
Functional Code – Java
static class Replacement {
final String output;
final Predicate<Integer> when;
Replacement(Predicate<Integer> when, String output) {
this.output = output;
this.when = when;
}
}
static final List<Replacement> fizzAndOrBuzz =
Collections.unmodifiableList(Arrays.asList(
new Replacement(i -> i % 15 == 0, "FizzBuzz"),
new Replacement(i -> i % 3 == 0, "Fizz"),
new Replacement(i -> i % 5 == 0, "Buzz")
));
static String replace(final Integer i, final List<Replacement> rules) {
final Optional<Replacement> replacement = rules.stream()
.filter(r -> r.when.test(i)).findFirst();
return replacement.isPresent() ? replacement.get().output : i.toString();
}
public static void functional(final PrintWriter writer) {
for (int i = 1; i <= 100; i++) {
writer.println(replace(i, fizzAndOrBuzz));
}
}
Functional Code – Groovy
static class Replacement {
Closure when
String output
Replacement(Closure when, String output) {
this.when = when
this.output = output
}
}
static replacements = [
new Replacement({it % 15 == 0}, "FizzBuzz"),
new Replacement({it % 5 == 0}, "Buzz"),
new Replacement({it % 3 == 0}, "Fizz")
]
static String replace(Integer i, List<Replacement> replacements) {
def replacement = replacements.find{ it.when(i) }
return replacement ? replacement.output : i.toString()
}
static functional(PrintWriter writer) {
for(int i = 1; i <= 100; i++) {
writer.println(replace(i, replacements))
}
}
Functional Code – Kotlin
class Replacement(r: (Int) -> Boolean, o: String) {
val rule: (Int) -> Boolean = r
val output: String = o
}
val fizzBuzzRules = listOf(
Replacement({ i -> i % 15 == 0 }, "FizzBuzz"),
Replacement({ i -> i % 3 == 0 }, "Fizz"),
Replacement({ i -> i % 5 == 0 }, "Buzz")
)
fun replace(i: Int, replacements: List<Replacement>): String {
val result: Replacement? = replacements.firstOrNull { r -> r.rule(i) }
return result?.output ?: i.toString()
}
@JvmStatic fun functional(printWriter: PrintWriter) {
for (i in 1..100) {
printWriter.println(replace(i, fizzBuzzRules))
}
}
Functional Code – Scala
case class Replacement(when: Int => Boolean, val output: String) {
}
val modulusCheck = (i: Int, div: Int) => i % div == 0
val fizzAndOrBuzz = List(
Replacement(i => i % 15 == 0, "FizzBuzz"),
Replacement(i => i % 3 == 0, "Fizz"),
Replacement(i => i % 5 == 0, "Buzz")
)
private def replace(i: Int, rules: List[Replacement]): String = {
rules.find(r => r.when(i)) match {
case Some(r) => r.output
case None => i.toString
}
}
def functional(writer: PrintWriter): Unit = {
for (i <- 1 to 100) {
writer.println(replace(i, fizzAndOrBuzz))
}
}
Functional Code – Scalaz
def fizz(n: Int): Option[String] = if (n % 3 == 0) some("Fizz") else None
def buzz(n: Int): Option[String] = if (n % 5 == 0) Some("Buzz") else None
def fizzbuzz(n: Int): String = (fizz(n) |+| buzz(n)).getOrElse(n.toString)
def functional(writer: PrintWriter): Unit = {
for (n <- 1 to 100) {
writer.println(fizzbuzz(n))
}
}
Functional Code – Scala Streams
val nones = Stream.continually(None)
val fizzes: Stream[Option[String]] = nones.take(2) ++ Some("Fizz") #:: fizzes
val buzzes: Stream[Option[String]] = nones.take(4) ++ Some("Buzz") #:: buzzes
def functional(writer: PrintWriter): Unit = {
for (((fizz, buzz), n) <- fizzes zip buzzes zip (1 to 100)) {
writer.println(fizz.map(_ + buzz.getOrElse("")).orElse(buzz).getOrElse(n))
}
}
Functional Performance
Language Ops / second % of Best
ScalaZ 277517.57 100.00%
Scala 276278.53 99.55%
Kotlin 266858.60 96.16%
Java 124968.78 45.03%
Java MapReduce 85608.05 30.85%
ScalaStreams 47997.63 17.30%
Groovy 13135.39 4.73%
ScalaZ
Scala
Kotlin
Java
Java MapReduce
ScalaStreams
Groovy
0
50000
100000
150000
200000
250000
300000
Ops / second
Imperative – Java Call
private static String replace(int i) {
if (i % 15 == 0) {
return "FizzBuzz";
} else if (i % 3 == 0) {
return "Fizz";
} else if (i % 5 == 0) {
return "Buzz";
} else {
return Integer.toString(i);
}
}
public static void imperative(PrintWriter writer) {
for(int i = 1; i <= 100; i++) {
writer.println(replace(i));
}
}
Imperative – Groovy Call
static String replace(int i) {
if (i % 15 == 0) {
return "FizzBuzz"
} else if (i % 3 == 0) {
return "Fizz"
} else if (i % 5 == 0) {
return "Buzz"
} else {
return Integer.toString(i)
}
}
static imperative(PrintWriter writer) {
for(int i = 1; i <= 100; i++) {
writer.println(replace(i))
}
}
Imperative – Kotlin Call
fun replace(i: Int): String {
when {
i % 15 == 0 -> return "FizzBuzz"
i % 3 == 0 -> return "Fizz"
i % 5 == 0 -> return "Buzz"
else -> return i.toString()
}
}
@JvmStatic fun imperative(printWriter: PrintWriter) {
for (i in 1..100) {
printWriter.println(replace(i))
}
}
Imperative – Scala Call
def replace(i: Int): String = {
return i match {
case x if x % 15 == 0 => "FizzBuzz"
case x if x % 5 == 0 => "Buzz"
case x if x % 3 == 0 => "Fizz"
case x => x.toString
}
}
def imperativeCall(writer: PrintWriter): Unit = {
for (i <- 1 to 100) {
writer.println(replace(i))
}
}
Comparing function optimization
Language Ops / second % of best
Java 667866.64 100.00%
Groovy 641418.92 96.04%
Kotlin 623649.03 93.38%
Scala 498185.74 74.59%
Java Groovy Kotlin Scala
0
100000
200000
300000
400000
500000
600000
700000
800000
Ops / second
Comparing Paradigms
Paradigm Ops / second % of Best
Imperative Inline 3194384.71 100.00%
Imperative Call 644311.53 20.17%
Functional Static 236405.87 7.40%
Functional Streams 66802.84 2.09%
Functional Dynamic 13135.39 0.41%
Imperative Inline
Functional Static
Functional Dynamic
0
500000
1000000
1500000
2000000
2500000
3000000
3500000
Ops / second
Summary
● A trivial example doesn’t always tell the whole story.
● Function call overhead cannot be discounted.
● Reducing Code Complexity is sometimes more important than
reducing Runtime Cost.
● Java Closures does not seem to perform as well as Kotlin or
Scala equivalents.
● Kotlin is a an awesome way to reduce complexity and
programmer errors.
● Groovy is a dynamic language.
● Scala was sent by ‘Aliens’.
Questions
● More information
– https://github.com/corneil/compare-fp
● Contact
– @corneil
– corneil@jumpco.io

More Related Content

What's hot

Are we ready to Go?
Are we ready to Go?Are we ready to Go?
Are we ready to Go?
Adam Dudczak
 
Goroutines and Channels in practice
Goroutines and Channels in practiceGoroutines and Channels in practice
Goroutines and Channels in practice
Guilherme Garnier
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my day
Tor Ivry
 
Introduction to go
Introduction to goIntroduction to go
Introduction to go
Jaehue Jang
 
Programming ppt files (final)
Programming ppt files (final)Programming ppt files (final)
Programming ppt files (final)
yap_raiza
 
Erlang bootstrap course
Erlang bootstrap courseErlang bootstrap course
Erlang bootstrap course
Martin Logan
 
Oops pramming with examples
Oops pramming with examplesOops pramming with examples
Oops pramming with examples
Syed Khaleel
 
Larry and Jen do Roman Numerals in C++
Larry and Jen do Roman Numerals in C++Larry and Jen do Roman Numerals in C++
Larry and Jen do Roman Numerals in C++
Jon Jagger
 
Asterisk: PVS-Studio Takes Up Telephony
Asterisk: PVS-Studio Takes Up TelephonyAsterisk: PVS-Studio Takes Up Telephony
Asterisk: PVS-Studio Takes Up Telephony
Andrey Karpov
 
Go Containers
Go ContainersGo Containers
Go Containers
jgrahamc
 
Python
PythonPython
Python
Wei-Bo Chen
 
Hacking Go Compiler Internals / GoCon 2014 Autumn
Hacking Go Compiler Internals / GoCon 2014 AutumnHacking Go Compiler Internals / GoCon 2014 Autumn
Hacking Go Compiler Internals / GoCon 2014 Autumn
Moriyoshi Koizumi
 
C++ How I learned to stop worrying and love metaprogramming
C++ How I learned to stop worrying and love metaprogrammingC++ How I learned to stop worrying and love metaprogramming
C++ How I learned to stop worrying and love metaprogramming
cppfrug
 
Golang design4concurrency
Golang design4concurrencyGolang design4concurrency
Golang design4concurrency
Eduardo Ferro Aldama
 
[SI] Ada Lovelace Day 2014 - Tampon Run
[SI] Ada Lovelace Day 2014  - Tampon Run[SI] Ada Lovelace Day 2014  - Tampon Run
[SI] Ada Lovelace Day 2014 - Tampon Run
Maja Kraljič
 
Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.
Platonov Sergey
 
Golang concurrency design
Golang concurrency designGolang concurrency design
Golang concurrency design
Hyejong
 
Vb.net programs
Vb.net programsVb.net programs
为什么 rust-lang 吸引我?
为什么 rust-lang 吸引我?为什么 rust-lang 吸引我?
为什么 rust-lang 吸引我?
勇浩 赖
 
Operator overloading2
Operator overloading2Operator overloading2
Operator overloading2
zindadili
 

What's hot (20)

Are we ready to Go?
Are we ready to Go?Are we ready to Go?
Are we ready to Go?
 
Goroutines and Channels in practice
Goroutines and Channels in practiceGoroutines and Channels in practice
Goroutines and Channels in practice
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my day
 
Introduction to go
Introduction to goIntroduction to go
Introduction to go
 
Programming ppt files (final)
Programming ppt files (final)Programming ppt files (final)
Programming ppt files (final)
 
Erlang bootstrap course
Erlang bootstrap courseErlang bootstrap course
Erlang bootstrap course
 
Oops pramming with examples
Oops pramming with examplesOops pramming with examples
Oops pramming with examples
 
Larry and Jen do Roman Numerals in C++
Larry and Jen do Roman Numerals in C++Larry and Jen do Roman Numerals in C++
Larry and Jen do Roman Numerals in C++
 
Asterisk: PVS-Studio Takes Up Telephony
Asterisk: PVS-Studio Takes Up TelephonyAsterisk: PVS-Studio Takes Up Telephony
Asterisk: PVS-Studio Takes Up Telephony
 
Go Containers
Go ContainersGo Containers
Go Containers
 
Python
PythonPython
Python
 
Hacking Go Compiler Internals / GoCon 2014 Autumn
Hacking Go Compiler Internals / GoCon 2014 AutumnHacking Go Compiler Internals / GoCon 2014 Autumn
Hacking Go Compiler Internals / GoCon 2014 Autumn
 
C++ How I learned to stop worrying and love metaprogramming
C++ How I learned to stop worrying and love metaprogrammingC++ How I learned to stop worrying and love metaprogramming
C++ How I learned to stop worrying and love metaprogramming
 
Golang design4concurrency
Golang design4concurrencyGolang design4concurrency
Golang design4concurrency
 
[SI] Ada Lovelace Day 2014 - Tampon Run
[SI] Ada Lovelace Day 2014  - Tampon Run[SI] Ada Lovelace Day 2014  - Tampon Run
[SI] Ada Lovelace Day 2014 - Tampon Run
 
Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.
 
Golang concurrency design
Golang concurrency designGolang concurrency design
Golang concurrency design
 
Vb.net programs
Vb.net programsVb.net programs
Vb.net programs
 
为什么 rust-lang 吸引我?
为什么 rust-lang 吸引我?为什么 rust-lang 吸引我?
为什么 rust-lang 吸引我?
 
Operator overloading2
Operator overloading2Operator overloading2
Operator overloading2
 

Viewers also liked

Microservices Patterns and Anti-Patterns
Microservices Patterns and Anti-PatternsMicroservices Patterns and Anti-Patterns
Microservices Patterns and Anti-Patterns
Corneil du Plessis
 
The Evolution of Java
The Evolution of JavaThe Evolution of Java
The Evolution of Java
Corneil du Plessis
 
Polyglot persistence with Spring Data
Polyglot persistence with Spring DataPolyglot persistence with Spring Data
Polyglot persistence with Spring Data
Corneil du Plessis
 
OWASP AppSecCali 2015 - Marshalling Pickles
OWASP AppSecCali 2015 - Marshalling PicklesOWASP AppSecCali 2015 - Marshalling Pickles
OWASP AppSecCali 2015 - Marshalling Pickles
Christopher Frohoff
 
Gradle: The Build System you have been waiting for!
Gradle: The Build System you have been waiting for!Gradle: The Build System you have been waiting for!
Gradle: The Build System you have been waiting for!
Corneil du Plessis
 
Giraph+Gora in ApacheCon14
Giraph+Gora in ApacheCon14Giraph+Gora in ApacheCon14
Giraph+Gora in ApacheCon14
Renato Javier Marroquín Mogrovejo
 
Thrift vs Protocol Buffers vs Avro - Biased Comparison
Thrift vs Protocol Buffers vs Avro - Biased ComparisonThrift vs Protocol Buffers vs Avro - Biased Comparison
Thrift vs Protocol Buffers vs Avro - Biased Comparison
Igor Anishchenko
 

Viewers also liked (7)

Microservices Patterns and Anti-Patterns
Microservices Patterns and Anti-PatternsMicroservices Patterns and Anti-Patterns
Microservices Patterns and Anti-Patterns
 
The Evolution of Java
The Evolution of JavaThe Evolution of Java
The Evolution of Java
 
Polyglot persistence with Spring Data
Polyglot persistence with Spring DataPolyglot persistence with Spring Data
Polyglot persistence with Spring Data
 
OWASP AppSecCali 2015 - Marshalling Pickles
OWASP AppSecCali 2015 - Marshalling PicklesOWASP AppSecCali 2015 - Marshalling Pickles
OWASP AppSecCali 2015 - Marshalling Pickles
 
Gradle: The Build System you have been waiting for!
Gradle: The Build System you have been waiting for!Gradle: The Build System you have been waiting for!
Gradle: The Build System you have been waiting for!
 
Giraph+Gora in ApacheCon14
Giraph+Gora in ApacheCon14Giraph+Gora in ApacheCon14
Giraph+Gora in ApacheCon14
 
Thrift vs Protocol Buffers vs Avro - Biased Comparison
Thrift vs Protocol Buffers vs Avro - Biased ComparisonThrift vs Protocol Buffers vs Avro - Biased Comparison
Thrift vs Protocol Buffers vs Avro - Biased Comparison
 

Similar to Performance Comparison JVM Languages

20180310 functional programming
20180310 functional programming20180310 functional programming
20180310 functional programming
Chiwon Song
 
Kotlin as a Better Java
Kotlin as a Better JavaKotlin as a Better Java
Kotlin as a Better Java
Garth Gilmour
 
01 Introduction to Kotlin - Programming in Kotlin.pptx
01 Introduction to Kotlin - Programming in Kotlin.pptx01 Introduction to Kotlin - Programming in Kotlin.pptx
01 Introduction to Kotlin - Programming in Kotlin.pptx
IvanZawPhyo
 
Introduction to Kotlin.pptx
Introduction to Kotlin.pptxIntroduction to Kotlin.pptx
Introduction to Kotlin.pptx
AzharFauzan9
 
Poly-paradigm Java
Poly-paradigm JavaPoly-paradigm Java
Poly-paradigm Java
Pavel Tcholakov
 
Introduction to F# for the C# developer
Introduction to F# for the C# developerIntroduction to F# for the C# developer
Introduction to F# for the C# developer
njpst8
 
Functional programming ii
Functional programming iiFunctional programming ii
Functional programming ii
Prashant Kalkar
 
Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014
Baruch Sadogursky
 
Fizz and buzz of computer programs in python.
Fizz and buzz of computer programs in python.Fizz and buzz of computer programs in python.
Fizz and buzz of computer programs in python.
Esehara Shigeo
 
Kotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functionsKotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functions
Franco Lombardo
 
ATS language overview
ATS language overviewATS language overview
ATS language overview
Kiwamu Okabe
 
Monadologie
MonadologieMonadologie
Monadologie
league
 
Generics and Inference
Generics and InferenceGenerics and Inference
Generics and Inference
Richard Fox
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and Cats
Philip Schwarz
 
Python
PythonPython
Python
대갑 김
 
Beware: Sharp Tools
Beware: Sharp ToolsBeware: Sharp Tools
Beware: Sharp Toolschrismdp
 
Python basic
Python basicPython basic
Python basic
Saifuddin Kaijar
 
Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015
Iran Entrepreneurship Association
 
A swift introduction to Swift
A swift introduction to SwiftA swift introduction to Swift
A swift introduction to Swift
Giordano Scalzo
 

Similar to Performance Comparison JVM Languages (20)

20180310 functional programming
20180310 functional programming20180310 functional programming
20180310 functional programming
 
Kotlin as a Better Java
Kotlin as a Better JavaKotlin as a Better Java
Kotlin as a Better Java
 
01 Introduction to Kotlin - Programming in Kotlin.pptx
01 Introduction to Kotlin - Programming in Kotlin.pptx01 Introduction to Kotlin - Programming in Kotlin.pptx
01 Introduction to Kotlin - Programming in Kotlin.pptx
 
Introduction to Kotlin.pptx
Introduction to Kotlin.pptxIntroduction to Kotlin.pptx
Introduction to Kotlin.pptx
 
Poly-paradigm Java
Poly-paradigm JavaPoly-paradigm Java
Poly-paradigm Java
 
Introduction to F# for the C# developer
Introduction to F# for the C# developerIntroduction to F# for the C# developer
Introduction to F# for the C# developer
 
Functional programming ii
Functional programming iiFunctional programming ii
Functional programming ii
 
Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014
 
Fizz and buzz of computer programs in python.
Fizz and buzz of computer programs in python.Fizz and buzz of computer programs in python.
Fizz and buzz of computer programs in python.
 
Kotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functionsKotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functions
 
Beware sharp tools
Beware sharp toolsBeware sharp tools
Beware sharp tools
 
ATS language overview
ATS language overviewATS language overview
ATS language overview
 
Monadologie
MonadologieMonadologie
Monadologie
 
Generics and Inference
Generics and InferenceGenerics and Inference
Generics and Inference
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and Cats
 
Python
PythonPython
Python
 
Beware: Sharp Tools
Beware: Sharp ToolsBeware: Sharp Tools
Beware: Sharp Tools
 
Python basic
Python basicPython basic
Python basic
 
Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015
 
A swift introduction to Swift
A swift introduction to SwiftA swift introduction to Swift
A swift introduction to Swift
 

More from Corneil du Plessis

Sweet Streams (Are made of this)
Sweet Streams (Are made of this)Sweet Streams (Are made of this)
Sweet Streams (Are made of this)
Corneil du Plessis
 
Cloud Native Applications for Cloud Foundry using Spring Cloud : A Workshop
Cloud Native Applications for Cloud Foundry using Spring Cloud : A WorkshopCloud Native Applications for Cloud Foundry using Spring Cloud : A Workshop
Cloud Native Applications for Cloud Foundry using Spring Cloud : A Workshop
Corneil du Plessis
 
QueryDSL - Lightning Talk
QueryDSL - Lightning TalkQueryDSL - Lightning Talk
QueryDSL - Lightning Talk
Corneil du Plessis
 
Enhancements in Java 9 Streams
Enhancements in Java 9 StreamsEnhancements in Java 9 Streams
Enhancements in Java 9 Streams
Corneil du Plessis
 
Reactive Spring 5
Reactive Spring 5Reactive Spring 5
Reactive Spring 5
Corneil du Plessis
 
Empathic API-Design
Empathic API-DesignEmpathic API-Design
Empathic API-Design
Corneil du Plessis
 
Consume Spring Data Rest with Angularjs
Consume Spring Data Rest with AngularjsConsume Spring Data Rest with Angularjs
Consume Spring Data Rest with Angularjs
Corneil du Plessis
 
Data repositories
Data repositoriesData repositories
Data repositories
Corneil du Plessis
 
Gradle: The Build system you have been waiting for
Gradle: The Build system you have been waiting forGradle: The Build system you have been waiting for
Gradle: The Build system you have been waiting for
Corneil du Plessis
 
Dependency Injection in Spring in 10min
Dependency Injection in Spring in 10minDependency Injection in Spring in 10min
Dependency Injection in Spring in 10minCorneil du Plessis
 

More from Corneil du Plessis (11)

Sweet Streams (Are made of this)
Sweet Streams (Are made of this)Sweet Streams (Are made of this)
Sweet Streams (Are made of this)
 
Cloud Native Applications for Cloud Foundry using Spring Cloud : A Workshop
Cloud Native Applications for Cloud Foundry using Spring Cloud : A WorkshopCloud Native Applications for Cloud Foundry using Spring Cloud : A Workshop
Cloud Native Applications for Cloud Foundry using Spring Cloud : A Workshop
 
QueryDSL - Lightning Talk
QueryDSL - Lightning TalkQueryDSL - Lightning Talk
QueryDSL - Lightning Talk
 
Enhancements in Java 9 Streams
Enhancements in Java 9 StreamsEnhancements in Java 9 Streams
Enhancements in Java 9 Streams
 
Reactive Spring 5
Reactive Spring 5Reactive Spring 5
Reactive Spring 5
 
Empathic API-Design
Empathic API-DesignEmpathic API-Design
Empathic API-Design
 
Consume Spring Data Rest with Angularjs
Consume Spring Data Rest with AngularjsConsume Spring Data Rest with Angularjs
Consume Spring Data Rest with Angularjs
 
Data repositories
Data repositoriesData repositories
Data repositories
 
Gradle: The Build system you have been waiting for
Gradle: The Build system you have been waiting forGradle: The Build system you have been waiting for
Gradle: The Build system you have been waiting for
 
Dependency Injection in Spring in 10min
Dependency Injection in Spring in 10minDependency Injection in Spring in 10min
Dependency Injection in Spring in 10min
 
Spring Data in 10 minutes
Spring Data in 10 minutesSpring Data in 10 minutes
Spring Data in 10 minutes
 

Recently uploaded

Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdfDominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
AMB-Review
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
Matt Welsh
 
GlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote sessionGlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote session
Globus
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
Juraj Vysvader
 
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Anthony Dahanne
 
Cyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdf
Cyanic lab
 
BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024
Ortus Solutions, Corp
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
Donna Lenk
 
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Globus
 
Understanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSageUnderstanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSage
Globus
 
top nidhi software solution freedownload
top nidhi software solution freedownloadtop nidhi software solution freedownload
top nidhi software solution freedownload
vrstrong314
 
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Mind IT Systems
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Globus
 
Vitthal Shirke Microservices Resume Montevideo
Vitthal Shirke Microservices Resume MontevideoVitthal Shirke Microservices Resume Montevideo
Vitthal Shirke Microservices Resume Montevideo
Vitthal Shirke
 
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.ILBeyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Natan Silnitsky
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
Ortus Solutions, Corp
 
First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
Globus
 
Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...
Globus
 
Lecture 1 Introduction to games development
Lecture 1 Introduction to games developmentLecture 1 Introduction to games development
Lecture 1 Introduction to games development
abdulrafaychaudhry
 
Corporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMSCorporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMS
Tendenci - The Open Source AMS (Association Management Software)
 

Recently uploaded (20)

Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdfDominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
 
GlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote sessionGlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote session
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
 
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
 
Cyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdf
 
BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
 
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
 
Understanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSageUnderstanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSage
 
top nidhi software solution freedownload
top nidhi software solution freedownloadtop nidhi software solution freedownload
top nidhi software solution freedownload
 
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
 
Vitthal Shirke Microservices Resume Montevideo
Vitthal Shirke Microservices Resume MontevideoVitthal Shirke Microservices Resume Montevideo
Vitthal Shirke Microservices Resume Montevideo
 
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.ILBeyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
 
First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
 
Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...
 
Lecture 1 Introduction to games development
Lecture 1 Introduction to games developmentLecture 1 Introduction to games development
Lecture 1 Introduction to games development
 
Corporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMSCorporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMS
 

Performance Comparison JVM Languages

  • 1. JVM Languages – Performance Comparing the performance of various JVM languages and programming paradigms. Corneil du Plessis
  • 2. Introduction ● Programmer since 1985 ● Smallest to very large systems. ● Cobol, Pascal, Algol, C/C++, Java, Scala, Groovy and other JVM languages. ● Scientific instrumentation, Sports event management, Mining, Banking, Treasury and Insurance. ● Software Architect (coding included)
  • 3. Why a Comparison? ● Multi-paradigm programming ● Code complexity ● Runtime complexity
  • 4. Challenge ● FizzBuzz – Imperative – Functional ● Languages – Java – Groovy – Kotlin – Scala
  • 5. FizzBuzz ● Write a program that prints the numbers from 1 to 100. ● But for multiples of three print “Fizz” instead of the number and for the multiples of five print “Buzz”. ● For numbers which are multiples of both three and five print “FizzBuzz” ● Pseudo Code for i in 1 to 100 if i multiple of 15 print ‘FizzBuzz’ else if i multiple of 3 print ‘Fizz’ else if i multiple of 5 print ‘Buzz’ else print i print newline
  • 6. Imperative Code – Java public static void imperative(PrintWriter writer) { for(int i = 1; i <= 100; i++) { if (i % 15 == 0) { writer.println("FizzBuzz"); } else if (i % 3 == 0) { writer.println("Fizz"); } else if (i % 5 == 0) { writer.println("Buzz"); } else { writer.println(i); } } }
  • 7. Imperative Code - Groovy static imperative(PrintWriter writer) { for(int i = 1; i <= 100; i++) { if (i % 15 == 0) { writer.println("FizzBuzz"); } else if (i % 3 == 0) { writer.println("Fizz"); } else if (i % 5 == 0) { writer.println("Buzz"); } else { writer.println(i); } } }
  • 8. Imperative Code – Kotlin @JvmStatic fun imperative(printWriter: PrintWriter) { for (i in 1..100) { when { i % 15 == 0 -> printWriter.println("FizzBuzz") i % 3 == 0 -> printWriter.println("Fizz") i % 5 == 0 -> printWriter.println("Buzz") else -> printWriter.println(i) } } }
  • 9. Imperative Code – Scala def imperative(writer: PrintWriter): Unit = { for (i <- 1 to 100) { i match { case x if x % 15 == 0 => writer.println("FizzBuzz") case x if x % 5 == 0 => writer.println("Buzz") case x if x % 3 == 0 => writer.println("Fizz") case x => writer.println(x) } } }
  • 10. Imperative Performance Language Ops / second % of best Java 3470211.76 100.00% Groovy 3457836.97 99.64% Kotlin 3405441.23 98.13% Scala 2444048.87 70.43% Java Groovy Kotlin Scala 0 500000 1000000 1500000 2000000 2500000 3000000 3500000 4000000 Ops / second
  • 11. Functional Code – Java MapReduce static class Replacement { final Predicate<Integer> when; final String output; Replacement(Predicate<Integer> when, String output) { this.output = output; this.when = when; } } static List<Replacement> fizzAndOrBuzz = Collections.unmodifiableList(Arrays.asList( new Replacement(i -> i % 3 == 0, "Fizz"), new Replacement(i -> i % 5 == 0, "Buzz") )); static String replace(final Integer i, final List<Replacement> rules) { return rules.stream() .filter(r -> r.when.test(i)) .map(r -> r.output) .reduce(String::concat) .orElse(Integer.toString(i)); } static String fizzBuzz(final Integer i) { return replace(i, fizzAndOrBuzz); } public static void functionalMapReduce(final PrintWriter writer) { IntStream.range(1, 101) .mapToObj(FizzBuzzFunctionalMapReduce::fizzBuzz) .forEach((i) -> writer.println(i)); }
  • 12. Functional Code – Java static class Replacement { final String output; final Predicate<Integer> when; Replacement(Predicate<Integer> when, String output) { this.output = output; this.when = when; } } static final List<Replacement> fizzAndOrBuzz = Collections.unmodifiableList(Arrays.asList( new Replacement(i -> i % 15 == 0, "FizzBuzz"), new Replacement(i -> i % 3 == 0, "Fizz"), new Replacement(i -> i % 5 == 0, "Buzz") )); static String replace(final Integer i, final List<Replacement> rules) { final Optional<Replacement> replacement = rules.stream() .filter(r -> r.when.test(i)).findFirst(); return replacement.isPresent() ? replacement.get().output : i.toString(); } public static void functional(final PrintWriter writer) { for (int i = 1; i <= 100; i++) { writer.println(replace(i, fizzAndOrBuzz)); } }
  • 13. Functional Code – Groovy static class Replacement { Closure when String output Replacement(Closure when, String output) { this.when = when this.output = output } } static replacements = [ new Replacement({it % 15 == 0}, "FizzBuzz"), new Replacement({it % 5 == 0}, "Buzz"), new Replacement({it % 3 == 0}, "Fizz") ] static String replace(Integer i, List<Replacement> replacements) { def replacement = replacements.find{ it.when(i) } return replacement ? replacement.output : i.toString() } static functional(PrintWriter writer) { for(int i = 1; i <= 100; i++) { writer.println(replace(i, replacements)) } }
  • 14. Functional Code – Kotlin class Replacement(r: (Int) -> Boolean, o: String) { val rule: (Int) -> Boolean = r val output: String = o } val fizzBuzzRules = listOf( Replacement({ i -> i % 15 == 0 }, "FizzBuzz"), Replacement({ i -> i % 3 == 0 }, "Fizz"), Replacement({ i -> i % 5 == 0 }, "Buzz") ) fun replace(i: Int, replacements: List<Replacement>): String { val result: Replacement? = replacements.firstOrNull { r -> r.rule(i) } return result?.output ?: i.toString() } @JvmStatic fun functional(printWriter: PrintWriter) { for (i in 1..100) { printWriter.println(replace(i, fizzBuzzRules)) } }
  • 15. Functional Code – Scala case class Replacement(when: Int => Boolean, val output: String) { } val modulusCheck = (i: Int, div: Int) => i % div == 0 val fizzAndOrBuzz = List( Replacement(i => i % 15 == 0, "FizzBuzz"), Replacement(i => i % 3 == 0, "Fizz"), Replacement(i => i % 5 == 0, "Buzz") ) private def replace(i: Int, rules: List[Replacement]): String = { rules.find(r => r.when(i)) match { case Some(r) => r.output case None => i.toString } } def functional(writer: PrintWriter): Unit = { for (i <- 1 to 100) { writer.println(replace(i, fizzAndOrBuzz)) } }
  • 16. Functional Code – Scalaz def fizz(n: Int): Option[String] = if (n % 3 == 0) some("Fizz") else None def buzz(n: Int): Option[String] = if (n % 5 == 0) Some("Buzz") else None def fizzbuzz(n: Int): String = (fizz(n) |+| buzz(n)).getOrElse(n.toString) def functional(writer: PrintWriter): Unit = { for (n <- 1 to 100) { writer.println(fizzbuzz(n)) } }
  • 17. Functional Code – Scala Streams val nones = Stream.continually(None) val fizzes: Stream[Option[String]] = nones.take(2) ++ Some("Fizz") #:: fizzes val buzzes: Stream[Option[String]] = nones.take(4) ++ Some("Buzz") #:: buzzes def functional(writer: PrintWriter): Unit = { for (((fizz, buzz), n) <- fizzes zip buzzes zip (1 to 100)) { writer.println(fizz.map(_ + buzz.getOrElse("")).orElse(buzz).getOrElse(n)) } }
  • 18. Functional Performance Language Ops / second % of Best ScalaZ 277517.57 100.00% Scala 276278.53 99.55% Kotlin 266858.60 96.16% Java 124968.78 45.03% Java MapReduce 85608.05 30.85% ScalaStreams 47997.63 17.30% Groovy 13135.39 4.73% ScalaZ Scala Kotlin Java Java MapReduce ScalaStreams Groovy 0 50000 100000 150000 200000 250000 300000 Ops / second
  • 19. Imperative – Java Call private static String replace(int i) { if (i % 15 == 0) { return "FizzBuzz"; } else if (i % 3 == 0) { return "Fizz"; } else if (i % 5 == 0) { return "Buzz"; } else { return Integer.toString(i); } } public static void imperative(PrintWriter writer) { for(int i = 1; i <= 100; i++) { writer.println(replace(i)); } }
  • 20. Imperative – Groovy Call static String replace(int i) { if (i % 15 == 0) { return "FizzBuzz" } else if (i % 3 == 0) { return "Fizz" } else if (i % 5 == 0) { return "Buzz" } else { return Integer.toString(i) } } static imperative(PrintWriter writer) { for(int i = 1; i <= 100; i++) { writer.println(replace(i)) } }
  • 21. Imperative – Kotlin Call fun replace(i: Int): String { when { i % 15 == 0 -> return "FizzBuzz" i % 3 == 0 -> return "Fizz" i % 5 == 0 -> return "Buzz" else -> return i.toString() } } @JvmStatic fun imperative(printWriter: PrintWriter) { for (i in 1..100) { printWriter.println(replace(i)) } }
  • 22. Imperative – Scala Call def replace(i: Int): String = { return i match { case x if x % 15 == 0 => "FizzBuzz" case x if x % 5 == 0 => "Buzz" case x if x % 3 == 0 => "Fizz" case x => x.toString } } def imperativeCall(writer: PrintWriter): Unit = { for (i <- 1 to 100) { writer.println(replace(i)) } }
  • 23. Comparing function optimization Language Ops / second % of best Java 667866.64 100.00% Groovy 641418.92 96.04% Kotlin 623649.03 93.38% Scala 498185.74 74.59% Java Groovy Kotlin Scala 0 100000 200000 300000 400000 500000 600000 700000 800000 Ops / second
  • 24. Comparing Paradigms Paradigm Ops / second % of Best Imperative Inline 3194384.71 100.00% Imperative Call 644311.53 20.17% Functional Static 236405.87 7.40% Functional Streams 66802.84 2.09% Functional Dynamic 13135.39 0.41% Imperative Inline Functional Static Functional Dynamic 0 500000 1000000 1500000 2000000 2500000 3000000 3500000 Ops / second
  • 25. Summary ● A trivial example doesn’t always tell the whole story. ● Function call overhead cannot be discounted. ● Reducing Code Complexity is sometimes more important than reducing Runtime Cost. ● Java Closures does not seem to perform as well as Kotlin or Scala equivalents. ● Kotlin is a an awesome way to reduce complexity and programmer errors. ● Groovy is a dynamic language. ● Scala was sent by ‘Aliens’.
  • 26. Questions ● More information – https://github.com/corneil/compare-fp ● Contact – @corneil – corneil@jumpco.io