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.


This Code Jugalbandi melody is the expression problem. What is Code Jugalbandi? Check out

  • Login to see the comments

  • Be the first to like this


  1. 1. Healthy Code January - 2015 14 Code Jugalbandi Article Ryan Dhaval
  2. 2. Healthy Code January - 2015 15 Jugalbandi inspires and fuels our desire to learn by focusing on dialogue and exploration. More languages in the room meant more perspectives too. Exploring a paradigm through any single language could. Above all, Code Jugalbandi is a Creator and Listener We met regularly over a period of several months, exploring some key issues related to Functional Programming (FP). This culminated in a live Code Jugalbandi at the Functional Conference in Bengaluru, 2014. During the FP Code Jugalbandi, we explored nine themes, which became melodies. Similar to the musical Jugalbandi, there are two roles: creator and listener. We called the creator of the melody Bramha and the one who listens and responds Krishna explore one such melody: The Expression Problem. The Expression Problem The Expression Problem was coined by Philip Wadler. Wikipedia states that the goal of the Expression Problem is to cases to the datatype and new functions over the datatype, without recompiling existing code, and while retaining static type safety (e.g. no casts). According to Wadler, “Whether a language can solve the Expression Problem is a salient indicator of its capacity for expression.” The Expression Problem - Clojure BRAMHA: In OOP, we model our domain concepts by creating our own types i.e., using classes and interfaces. In a geometric shape, say the Circle, in Clojure. (defrecord Circle [radius]) (Circle. 11) (:radius (Circle. 11)) BRAMHA: Classes in OO act as containers for structured data, as well as behaviour acting on the structured data. In Clojure, records just take care of the structure. BRAMHA: In Clojure, the corollary of an Interface is a Protocol: (defprotocol Shape (area [shape]) (perimeter [shape])) BRAMHA: We can extend our Circle type to implement the Shape protocol, e.g. (extend-type Circle Shape (area [circle] (* (:r circle) (:r circle) Math/PI))) BRAMHA: At this stage we have a simple type-based dispatch for our protocol method area. Clojure is more powerful but less performant polymorphic dispatch through multimethods. (area (Circle. 10)) (area (Rect. 10 20)) BRAMHA something like this: (EP1) create a new type that implements an existing interface BRAMHA our existing Shape protocol: (defrecord Rect [length width] Shape (area [rect] (* (:length rect) (:width rect)))) KRISHNA allow you to create new classes to implement existing BRAMHA: Yes, agreed, but the second part of the Expression Problem is harder to solve in some OO languages: (EP2) implement a new interface for an existing type Moreover (EP1) and (EP2) should be possible without having in working with third party code that you cannot recompile. To achieve (EP2) with Clojure we can do this: (defprotocol Graphic (draw [this])) (extend-type Circle Graphic (draw [this] (puts “O”))) KRISHNA: Clojure fares well with both (EP1) and (EP2). Let me show you how Scala addresses the Expression Problem. The Expression Problem - Scala KRISHNA: We start by creating the Circle and Rectangle as data classes.
  3. 3. Healthy Code January - 2015 16 case class Circle(r: Int) case class Rectangle(l: Int, w: Int) KRISHNA Shape that I can perform on Circle and Rectangle. trait Shape[T] { def area(t: T): Double def perimeter(t: T): Double } Then I implement the trait for Circle, say, implicit object CircleOps extends Shape[Circle] { def area(c: Circle): Double = Math.PI * c.r * c.r def perimeter(c: Circle): Double = 2 * Math.PI * c.r } KRISHNA def area[T](t: T)(implicit s: Shape[T]): Double = s.area(t) def perimeter[T](t: T)(implicit s: Shape[T]): Double = s.perimeter(t) KRISHNA: Returning to the Expression Problem, we can solve (EP2) like this in Scala: trait Graphics[T] { def draw(t: T): Unit } implicit object CircleGraphics extends Graphics[Circle] { def draw(c: Circle) = println(“O”) } def draw[T](t: T)(implicit g: Graphics[T]) = g.draw(t) KRISHNA a new Right Triangle type and implement the existing interfaces. case class RTriangle(b: Int, h: Int) import Math._ implicit object RTriangleOps extends Shape[RTriangle] with Graphics[RTriangle] { def area(rt: RTriangle) = 0.5 * rt.b * rt.h def perimeter(rt: RTriangle) = rt.b + rt.h + (sqrt(pow(rt.b, 2) + pow(rt.h, 2)) def draw(rt: RTriangle) = println(rt) } BRAHMA: Scala solves both (EP1) and (EP2), albeit with some syntactic noise around the use of implicit objects. Let me show you how concise Haskell is at solving the Expression Problem. The Expression Problem - Haskell BRAMHA with a few sub-types: data Shape = Circle {radius :: Float} | Rect {length :: Float, width ::Float} deriving Show BRAMHA: To create an area method that is polymorphic over the Shape sub-types: area :: Shape -> Float area (Circle r) = 3.14 * r^2 area (Rect l w) = l * w BRAMHA In (EP1) adding a new sub-type to the Shape algebraic type would require adding a clause for the new subtype to each function I declared over the type (implying a recompile), In (EP2) adding a new function acting on existing algebraic types is trivial. The Expression Problem with TypeClasses Instead of unifying the concepts Circle and Rect as the Shape abstract data type, we could use Haskell typeclasses to unify to not name clash with the above code). data Circle_ = Circle_ {radius_ :: Float} data Rect_ = Rect_ {length_ :: Float, width_ :: Float} class Shape_ a where area_ :: a -> Float perimeter_ :: a -> Float
  4. 4. Healthy Code January - 2015 17 BRAMHA: Adding a new data type that implements an existing typeclass is easy (EP1): instance Shape_ Circle_ where area_ (Circle_ r) = pi * r^2 perimeter_(Circle_ r) = 2 * pi * r Extending an existing type with a new interface is simple too (EP2): class Graphics_ a where draw_ :: a -> IO () instance Graphics_ Circle_ where draw_ (Circle_ r) = putStrLn (show r) KRISHNA: In OOP classes, we can combine type with a clear separation between type and behaviour. BRAMHA is that objects contain mutable state. In FP languages, we use immutable values in place of mutable state. For example, the Circle and Rect in all three languages were some form of KRISHNA: The Expression Problem also asks that you can extend types with interfaces without needing to recompile the code you are extending. Our three languages are quite BRAMHA: Scala is more strictly typed, but also fares well by allowing extension of code without recompiling it. If we look, both the Scala and Clojure both resemble Haskell in the KRISHNA: Yes, and Haskell deals with types in a sophisticated yet simple way, but it is less dynamic and more limited in solving this aspect of the (EP). BRAMHA KRISHNA than traditional OO does, but then again, many OO languages have evolved and are much more dynamic these days. In fact, using Java Generics, the Expression Problem can be solved, except that it would be syntactically very noisy Ryan is a software developer, coach and advisor, based in Cape Town. He has been working with code for more than 15 years. Ryan assists individuals and teams to manage the evolution and complexity of their software systems. Ryan is a passionate learner and enjoys facilitating learning in others. Dhavalahands-ondeveloperand mentor, believes that software then a craft. For him writing software brings his creativity to the fore. His interests are in architecting applications ground up, estabilishing environments, transitioning and orienting teams to Agile way of working by embedding himself within teams. CodeJugalbandi object BRAHMA: True, and besides, there are very few purely FP or OO languages. Still, we can say that FP does have good answers to the (EP). References Learn more from