Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Functional and reactive u is gwt.create 2015

1,716 views

Published on

Slides for the Functional and Reactive UIs talk presented in GWT.create 2015. Demo app available at https://github.com/hezamu/DungeonGame

Published in: Software
  • Be the first to comment

  • Be the first to like this

Functional and reactive u is gwt.create 2015

  1. 1. Functional and Reactive UIs Henri Muurimaa SVP of Engineering, Vaadin henri@vaadin.com @henrimuurimaa
  2. 2. Number of metal bands per capita
  3. 3. Functional programming Reactive programming Functional and reactive UI programming
  4. 4. A style of programming that expresses computation as the evaluation of mathematical functions
  5. 5. Recursion Lazy evaluation Lambda expressions Type theory Monads Referential transparency Currying Entscheidungsproblem Pattern matching Tuples
  6. 6. Something practical? Side effects? State? No Bad
  7. 7. Okay…
  8. 8. What instead of how
  9. 9. val square = (number: Int) => number * number Functional programming 101 val tenSquared = square(10) val nums = List(1,2,3) val squares = nums map square // List(1, 4, 9) val evenNums = nums filter { _ % 2 == 0 } // List(2) val letters = List("a", "b", "c") val numbersWithLetters = squares zip letters // List((1,a), (4,b), (9,c))
  10. 10. Null checks are a code smell
  11. 11. val presentNumber: Option[Int] = Some(10) Dealing with absent values on the type level val absentNumber: Option[Int] = None val wrappedNull: Option[Int] = Option(null) // None
  12. 12. Working with Option case class User(name: String, id: Int) trait UserRepository { def findById(i: Int): Option[User] } val user = userRepository.findById(1) // Option[User] if(user.isDefined) { println("User name: " + user.get.name) } user foreach { u => println("User name: " + u.name) } val nameOpt = user map { _.name } // Option[String] val name = user map { _.name } getOrElse "No user found"
  13. 13. Player Enemy Illuminated areaPlayer sight range github.com/hezamu/DungeonGame
  14. 14. case class Cell(x: Int, y: Int) { def +(other: Cell) = Cell(x + other.x, y + other.y) } class Dungeon { var floors: Set[Cell] = Set() var entities: Map[Entity, Cell] = Map() def visibleIlluminatedCells = ??? } Dungeon model
  15. 15. class Dungeon { var floors: Set[Cell] = Set() var entities: Map[Entity, Cell] = Map() def playerOpt = entities.keys collect { case p: Player => p } headOption def playerCellOpt = playerOpt map entities def playerSightRange = playerOpt map { _.sightRange } getOrElse 0 def inPlayerSightRange(cell: Cell) = playerCellOpt map { playerPos => MapLogic.distance(playerPos, cell) <= playerSightRange } getOrElse false def visibleIlluminatedCells = { val lightSources = entities map { case (entity, cell) => (cell, entity.illuminationRadius) } val visibles = lightSources flatMap MapLogic.area filter inPlayerSightRange floors intersect visibles.toSet } }
  16. 16. Functional summary Option lets you get rid of NPEs forever Use small functions with clear responsibilities Chaining functional operations is practically a superpower
  17. 17. What is Reactive Programming?
  18. 18. int a = b + 1; =B1+1 Spot the difference?
  19. 19. Vaadin ComboBox cities = new ComboBox(); Label selectedCity = new Label(); selectedCity.setPropertyDataSource(cities); Tessell void onInit() { employee.name.set(name); binder.bind(employee.name).to(textOf(view.employeeName())); } void someBusinessLogic() { // only have to set the name employee.name.set(newName); }
  20. 20. Listening to events is a code smell
  21. 21. val numbers = Observable.from(List(1, 2, 3)) numbers subscribe { n => println(n) } Observables to the rescue val squares = numbers map { num => num * num } val letters = Observable.from(List("a", "b", "c")) val numbersWithLetters = squares zip letters
  22. 22. RxVaadinwww.vaadin.com/blog/-/blogs/reactive-functional-ui-development-with-vaadin
  23. 23. val movesObserver = Vector( up.clickEvents map { e => tryMove(Cell(0, -1)) }, down.clickEvents map { e => tryMove(Cell(0, 1)) }, left.clickEvents map { e => tryMove(Cell(-1, 0)) }, right.clickEvents map { e => tryMove(Cell(1, 0)) } ) def tryMove(delta: Cell) = board.dungeon.playerPosition map { cell => cell + delta } filter board.dungeon.canMoveTo Observing player moves // Emit a Option[Cell] every time player tries to move val moveObserver = Observable from movesObserver flatten
  24. 24. // Map a legal destination cell to the set of visible cells after the move val visibleCellsObserver = moveObserver collect { case Some(cell) => board.dungeon.playerOpt foreach { board.dungeon.put(_, cell) } board.dungeon.visibleIlluminatedCells } // Subscribe the game board instance to the stream of legal moves. // This will call board.onNext() with a set of visible cells whenever // player performs a legal move. visibleCellsObserver subscribe board Handling legal moves
  25. 25. // Subscribe to the illegal move stream to show a notification every // time player tries an illegal move. moveObserver filter { _.isEmpty } subscribe { none => Notification.show("That direction is blocked", Notification.Type.Tray) } Handling illegal moves
  26. 26. Summary These techniques are very powerful and they can be learned gradually Both functional and reactive techniques are great with UIs Functional puts FUN back in programming!
  27. 27. Thank You! github.com/hezamu @henrimuurimaa henri@vaadin.com

×