1 / 65

a Feature Comparison

vs. a Feature Comparison. Urs Peter upeter@xebia.com @ urs_peter. Some Facts about Scala. Born in 2003 – 10 years old Sponsored by EPFL ( École Polytechnique Fédérale de Lausanne – Switzerland). Some Facts about Scala. Creator: Martin Odersky.

naava
Télécharger la présentation

a Feature Comparison

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. vs a Feature Comparison Urs Peter upeter@xebia.com @urs_peter

  2. Some Facts about Scala Born in 2003 – 10 years old Sponsored by EPFL (ÉcolePolytechniqueFédérale de Lausanne – Switzerland)

  3. Some Facts about Scala • Creator: Martin Odersky Also co-designed Generic Java, and built the current generation of javac.

  4. Some Facts about Scala Scala is fully interoperable with Java

  5. Some Facts about Scala Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_35). Type in expressions to have them evaluated. Type :help for more information. scala> Scala has a REPL (Command line tool for Read-Eval-Print Loop)

  6. Some Facts about Scala Scala is used in many worldclass companies & applications

  7. Some Facts about Scala IDE’s are mature

  8. Some Facts about Scala There is a company behind Scala

  9. Some Facts about Scala …that offers a supported Stack

  10. Some Facts about Scala Recently joined Typesafe:

  11. Some Facts about Scala Thoughtworks Technology Radar October 2012 March 2012

  12. Java 8 • Major Language Improvements (JSR 335): • Lambda Expressions / Method References • Virtual Extension Methods • Schedule: • 2013/02/21 M7 • 2013/07/05 M8 (Final Release Candidate) • 2013/09/09 GA (General Availability)

  13. Java 8 Lambda’s versus Scala Functions • What’s so fun about Functional Programming anyway?

  14. From Imperative to Functional in Java List<Integer> numbers = Arrays.asList(1,2,3); Filter even numbers List<Integer> res = newArrayList<>(); for(Integeri : numbers) { if( i % 2 == 0 ) res.add(i); } return res; Variation Duplication Filter odd numbers List<Integer> res = newArrayList<>(); for (Integeri : numbers) { if( i % 2 != 0 ) res.add(i); } return res;

  15. From Imperative to Functional in Java List<Integer> res = newArrayList<>(); for (Integer i : numbers) { if( i % 2 == 0 ) res.add(i); } return res; interfacePredicate<T> { publicboolean op(T item); } The Function: Varying computation public List<T> filter(List<T> items, Predicate<? super T> predicate) { List<T> res = newArrayList<>(); for(T item : items) { if(predicate.op(item)){ res.add(item); } } returnres; } Generic Control Structure == Higher Order Function The Loop: Generic Control Structure

  16. From Imperative to Functional in Java List<Integer> numbers = Arrays.asList(1, 2, 3); Filter even numbers List<Integer> result = filter(numbers, newPredicate<Integer>() { publicboolean op(Integer item) { returnitem % 2 == 0; } }); Filter odd numbers List<Integer> result = filter(numbers, newPredicate<Integer>() { publicboolean op(Integer item) { returnitem % 2 != 0; } });

  17. Is the Functional Concept new in Java? Take Spring: jdbcTemplate.queryForObject("select * from student where id = ?", new Object[]{1212l}, newRowMapper() { public Object mapRow(ResultSetrs, introwNum) throwsSQLException { returnnew Student(rs.getString("name"), rs.getInt("age")); } }); Can you see it? Take Google Guava: Iterables.filter(persons, newPredicate<Person>() { publicbooleanapply(Person p) { returnp.getAge() > 18; } });

  18. Functional Programming with Lambda’s Before (< Java 8) • List<Integer> result = filter(numbers, new Predicate<Integer>() { • publicboolean op(Integer i) { • returni % 2 == 0; • } • }); Lambda Expression == Syntactic sugar After (>= Java 8) List<Integer> result = filter(numbers, (Integer i) -> i% 2 == 0 ); Lambda Expressions can be used for ‘Functional Interfaces’ (here Predicate) that have a single method (here: boolean op(T f)).

  19. Lambda Features at one Glance Java 8 Complete Lambda Expression Lambda Expression with Type Inference No need to define the type since it can be inferred by the compiler. List<Integer> result = filter(numbers, (Integer i) -> i% 2 == 0); List<Integer> result = filter(numbers, i-> i% 2 == 0);

  20. Method Reference at one Glance Java 8 Static Method References Instance Method References Turn an existing static method with the same signature as the functional interface into a closure, using :: publicclassNumUtils { publicstaticbooleanisEven(Integer i) { returni % 2 == 0; } } List<Integer> result = filter(numbers, NumUtils::isEven ); Boolean::booleanValue refers to the instance that the filter is iterating through. • (Integer i) -> NumUtils.isEven(i) List<Boolean> trueOrFalse = Arrays.asList(true, false); List<Boolean> trueOnly = filter(trueOrFalse, Boolean::booleanValue ); • (Boolean b) -> b.booleanValue()

  21. Java 8 Lambda Expressions versus Scala Functions Complete Lambda Expression Java 8 List<Integer> result = filter(numbers, (Integer i) -> i% 2 == 0); Scala val result = filter(numbers, (i:Int) => i % 2 == 0)

  22. Java 8 Lambda Expressions versus Scala Functions Lambda with type inference Java 8 List<Integer> result = filter(numbers, i -> i% 2 == 0); Scala val result = filter(numbers, i => i % 2 == 0)

  23. Java 8 Lambda Expressions versus Scala Functions Static Method References Java 8 List<Integer> result = filter(numbers, NumUtils::isEven); Every method that is not called with its arguments is automatically turned into a Function. Methods == Functions Scala val result = filter(numbers, NumUtils.isEven)

  24. Java 8 Lambda Expressions versus Scala Functions Instance Method References Java 8 List<Boolean> trueOnly = filter(trueOrFalse, Boolean::booleanValue); Scala uses the _ (underscore) to refer to the current instance that is iterated through Scala valtrueOnly = filter(trueOrFalse, _.booleanValue )

  25. So, what’s the difference? Every Higher Order Function needs aspecific Functional Interface in Java 8. Java 8 interface Collection<T> { publicCollection<T> filter(Predicate<T> p); ... interfacePredicate<T> { publicboolean op(T t); } • The compiler transforms this syntax to a generic Function object. Therefore, no Functional Interface needs to be defined. Scala traitSeq[T] { def filter(f:T=> Boolean):Seq[T] ... • class Function1[I, R] { • def apply(i:I): R • } • Scala has a function syntax. Higher Order Functions reveal the difference:

  26. So, what’s the difference? Using Lambda’s/Functions as Objects reveal the difference too: Java 8 A Lambda always needs to be assigned to amatching Functional Interface in Java 8. Predicate<Integer> evenFilter = (Integer i) -> i % 2 == 0; Predicate<Integer> evenFilter = NumUtils::isEven; numbers.filter(evenFilter); Due to Scala’s Type Inference combined with Functions as ‘First Class Citizens’ approach this is not necessary: Scala valevenFilter =(i:Int) => i % 2 == 0 //evenFilter has type: Int => Boolean numbers.filter(evenFilter)

  27. Detailed Comparison Java 8 Lambda Expressions Syntax is limited to calling Higher Order Functions Functions are interfaces with one method Scala Functions Have a syntax for defining and callingHigher Order Functions Functions are objects with methods Rich Function Features: • Function Composition • Currying • Call-by-name arguments • PartialFunctions • Pattern matching Functions are First Class Citizens fully supporting the Functional Programming Paradigm Lambda’s are Syntactic Sugar for Functional Interfaces

  28. Impressions of Functional Programming in Scala • Scala’sFunctions are composable: valadd = (i:Int) => (j:Int) => i + j val multiply = (x:Int) => (y:Int) => x * y valprettyPrint = (i:Int) => s"the result is $i" valcombi= add(5) compose multiply(2) andThenprettyPrint //combi has type: Int => String combi(10) > the result is 25 • compose and andThen are methods of the Scala Function object

  29. Impressions of Functional Programming in Scala Scalamethods and functions can be partially applied: • Java 8 supports only ‘full’ method references: Math::min vallimiter = Math.min(100, _:Int) //limiter has type: Int => Int limiter(200) > 100 Scala Call-by-name arguments allow you to add code blocks: • Java 8 always expects a lambda: • debug(() -> "a" + "b" ...) defdebug(msg: => String) = { if(isDebugEnabled) logger.debug(msg) } //The concatenation only takes place if debug is enabled debug("expensive concat" * 1000) Scala

  30. Taking off with Lambda’s

  31. Iterations in Java are ‘external’ by default… Java What is going on here? List<Student> students = ...; List<Student> topGrades= newArrayList<Student>(); List<String> result = newArrayList<String>(); for(Student student : students){ if(student.getGrade() >= 9) { topGrades.add(student); } } } Collections.sort(topGrades, new Comparator<Student>() { publicint compare(Student student1, Student student2) { return student1.getGrade().compareTo(student2.getGrade()); } }); for(Student student : topGrades){ result.add(student.getFirstName() + " " + student.getLastName()); }

  32. Internal Iteration: When Lambda’s/Functions start to shine Java 8 Ah, now I get it: List<Student> students = ... List<String> topGrades = students.filter(s -> s.getScore() >= 9) .sortedBy(Student::getLastName) .map(s -> s.getFirstName() + " " + s.getLastName()) .into(newArrayList<>()); • Advantages: • Re-use of generic, higher level control structures • Less error prone • More expressive and readable • Chainable

  33. Internal Iteration: When Lambda’s/Functions start to shine Java 8 List<Student> students = ... List<String> topGrades = students.filter(s -> s.getScore() >= 9) .sortedBy(Student::getLastName) .map(s -> s.getFirstName() + " " + s.getLastName()) .into(newArrayList<>()); No need to use the into() method. This happens in Scala ‘automagically’ Scala val students = ... valtopGrades = students.filter(_.score >= 9) .sortBy(_.name) .map(p => p.firstName+ " " + p.lastName)

  34. But wait: there is more Java Find longest word in a huuuuge text file List<String> lines= //get many many lines intlengthLongestWord= 0; for(String line : lines) { for(String word : line.split(" ")) { if(word.length() > lengthLongestWord) { lengthLongestWord= word.length(); } } } What’s the problem with the for loops ?

  35. But wait: there is more Java Find longest word in a huuuuge text file List<String> lines= //get many many lines intlengthLongestWord = 0; for(String line : lines) { for(String word : line.split(" ")) { if(word.length() > lengthLongestWord) { lengthLongestWord= word.length(); } } } they cannot be executed in parallel!

  36. But wait: there is more Find longest word in a huuuuge text file Pattern WORD_REGEX= java.util.regex.Pattern.compile("\\w+"); List<String> lines= //get many many lines intwordCount = 0; for(String line :lines) { Matcher matcher = WORD_REGEX.matcher(line); while(matcher.find()) wordCount++; } Sequential Thread 1 Parallel (assuming a quad core machine) Thread 1 Thread 2 Thread 3 Thread 4 Time t Done parallel Done sequential

  37. Parallel Collections to the rescue Java 8 Find longest word in a huuuuge text file List<String> lines = //get many many lines intlengthLongestWord= lines.parallel() .map(line -> line.split(" ") .map(String::length) .reduce(Math::max)) .reduce(Math::max); Scala val lines = //get many many lines vallengthLongestWord= lines.par .map(_.split(" ").map(_.length).max) .max

  38. Detailed Comparison: Collections & Lambda’s/Functions Scala Collections Java 8 Collections Higher Order Functions Parallelism Automatic collection conversion Fast immutable data structures Other Automatic conversion from Java to Scala collections

  39. Impressions of Scala’s Collection usage: Autoconversion AutomagicCollection Conversion valresult = BitSet(1,2,3).map(_.toString) > result: SortedSet("1", "2", "3") With start out with container: BitSet containg Bytes End up with container: SortedSet containing String

  40. Impressions of Scala’s Collection usage: Tuples A Tuple is generic datacontainer //a simple tuple valmyTuple = (1, “two”) Tuples are pattern matchable • //the match populates the variables ‘first’ and ‘second’ • val(first, second) = myTuple • > first = 1 • > second = “two”

  41. Impressions of Scala’s Collection usage: Tuples Tuples are widely used in Collections val zipped = List(1,2).zip(List(“one”, “two”)) > zipped: List((1, “one”), (2, “two”)) • val (topGrades, otherGrades) = student.partition(_.grade >= 9) • > topGrades: List(Student(“Joe”, 9), ...) • > otherGrades: List(Student(“Jack”, 7), ...)

  42. Back to Java 8:How to make it fit? How is it possible to add Higher Order Functions (e.g. filtermapforeachetc.) to the java.util.Collection interface without breaking backwards compatibility? Java 8 interface Collection<T> { publicCollection<T> filter(Predicate<T> p); public <R> Collection<R> map(Mapper<T, R> m); ... ‘Old’ Java code (prior Java 8) running in JRE 8 would have to implement all the new methods that offer ‘internal iteration’ with Lambda’s.

  43. Back to Java 8:How to make it fit? …with default implementations for interfaces aka Virtual Extension Methods! Java 8 interface Collection<T> { publicdefault Collection<T> filter(Predicate<? super T> p) { Collection<T> res = newArrayList<>(); for(T item : this) { if(p.test(item)) { res.add(item); } } return res; } ...

  44. A closer look at Java 8’Virtual Extension Methods • Primary motivator is API evolution (Backwards compatibility for Lambda’s in Collections) • Useful mechanism by itself: Enables Multiple Inheritance of behavior • Inspired by Scalatraits (among others)

  45. Do we need Multiple Inheritance? Let’s model the domain for a ‘futuristic’ game Ship health:Integer hit() health - 2 Possible characteristics of a Ship: Gun fireAt(s:Ship) Shield hit() //50% Medic repair(s:Ship) s.hit() health - 1 s.health = 10 repaired += 1

  46. The Limits of Single inheritance Possible Ship implementations: Commander Base Mechanic Fighter

  47. The Limits of Single inheritance Implementation Challenge: Single inheritance won’t work Gun Shield Medic Base Commander Fighter Mechanic

  48. ScalaMultiple Inheritance of Behavior Adding Behavior to a Ship (Scala) • A trait is an interface with an implementation (behavior and/or state) • traitGun { • deffireAt(s:Ship) = s.hit • } • class Ship(varhealth:Int = 0) { • def hit() = health -= 2 • } • It can be ‘mixed-in’ with a class using the keyword: with valgoodFighter= new Ship(10) withGun valevilFighter= new Ship(10) withGun goodFighter.fireAt(evilFighter) println(evilFighter.health) > 8

  49. Java 8Multiple Inheritance of Behavior Adding Behavior to a Ship (Java 8) • Works with Virtual Extension Methods • interfaceGun { • default voidfireAt(Ship s) { s.hit(); } • } • classShip { • int health = 0; • //constructor, getters, setters, hit method • } class Fighter extends Ship implements Gun {…} FightergoodFighter= new Fighter(10); FighterevilFighter = newFighter(10); goodFighter.fireAt(evilFighter); println(evilFighter.getHealth()); > 8

  50. ScalaMultiple Inheritance of Behavior • Trait’s can have a self-type. The self-type tells with which class this trait can be ‘mixed’. Change Behavior of Ship (Scala) • trait Shield { • self:Ship => • overridedefhit() = self.health -= 1 • } • The self-type provides access to the ‘mixed-in’ class • Traits can override methods of the ‘mixed-in’ class • class Ship(varhealth:Int = 0) { • def hit() = health -= 2 • } val commander = new Ship(10) withGun withShield valevilFighter = new Ship(10) withGun evilFighter.fireAt(commander) println(commander.health) > 9

More Related