• Like
Scala Paradigms
Upcoming SlideShare
Loading in...5
×

Scala Paradigms

  • 2,458 views
Uploaded on

Getting to Know Scala …

Getting to Know Scala
What Makes Scala Unique for DSLs - Math DSL
Multiple Paradigms in One Language - Traits Mixins
Applying Scala In The Real World

More in: Technology , Business
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
2,458
On Slideshare
0
From Embeds
0
Number of Embeds
1

Actions

Shares
Downloads
111
Comments
0
Likes
9

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Axiom Architectures TOM FLAHERTY Scala Paradigms GETTING TO KNOW SCALA WHAT MAKES SCALA UNIQUE FOR DSLS MULTIPLE PARADIGMS IN ONE LANGUAGE APPLYING SCALA IN THE REAL WORLD 1
  • 2. GETTING TO KNOW SCALA • Martin Odersky • Java 1.3 compiler was based on his work • Since 2003 • Sponsored by EPFL • Friendly and supportive community • Production ready • Seamless Java interoperability • Performance within +- 5% of Java - JIT is the primary reason 2
  • 3. SCALA SYNTAX Syntax Highlighting blue - Scala keywords primitives, String, Array and List purple - Imported Scala and Java classes bold - Declared classes and methods green - Constants and string literals gray - Comments orange – Console output Scala keywords behave for the most part like their Java counterparts abstract case catch class def do else extends false final finally for forSome if implicit import lazy match new null object override package private protected requires return sealed super this throw trait try true type val var while with yield _ : = => <<: <% >: # @ 3
  • 4. CLASS DECLARATIONS Class Declarations with a parameterized type [ T ] trait Trait[T] {...} abstract class Abs[T]( i:Int ) extends Trait[T] {...} class Concrete[T]( i:Int ) extends Abs[T]( i:Int ) {...} case class Case[T]( i:Int ) extends Abs[T]( i:Int ) {...} class Mixin[T]( i:Int ) extends Abs[T]( i:Int ) with Trait1[T] with Trait2[T] {...} Class arguments specify the primary constructor • The class body is executed at instance creation. • Primary constructor arguments can be passed up to its super class • Primary constructor can declare fields with var and val • Other constructors are declared by def this( i:Int, ... ) = { ... } • Traits do not have constructors and therefore do not have arg lists 4
  • 5. DECLARATIONS LIST AND TUPLE def method( arg1:Int, ... ) : Int = { } // Method declaration var num:Int = 0 // Mutable field. Must be initialized val one:Int = iarg // Immutable initialized by constructor var sum:Int = _ // Let Int default to zero var ref:AnyRef = _ // Let class reference default to null // List[T] An immutable sequence of elements of the same type val a123 = List(1,2,3) // Type inferred by object List.apply() val b123 = 1 :: 2 :: 3 :: Nil // Nil empty list val aStr = List[String](“1”,”2",”3") // Parameterized // Tuple Immutable sequence of elements of the different types // Excellent for multi value returns // Often used to group elements for pattern matches val tup = (1,”two”,3.0) // Just enclose element in parentheses println( tup._1, tup._2, tup._3 ) // Element access 5
  • 6. XML Scala has intrinsic XML literals for markup Braces can include arbitrary Scala content class Person( var name:String, var age:Int ) { def toXML = <person> <name>{name}</name> <age>{age}</age> </person> def fromXML( node:scala.xml.Node ) : Unit node match { case <name>{namex}</name> => name = namex.toString case <age>{agex}</age> => age = agex.toString.toInt case _ => Error( “Bad XML Syntax”, node.toString ) } } 6
  • 7. OBJECT Classes in Scala cannot have static members. Instead Scala has object A class & its companion object become a Java class in byte code. class Elem[T] {...} // A parameterized Companion class class DblElem[T]( d:Double ) extends Elem[T] {} class IntElem[T]( i:Int ) extends Elem[T] {} class StrElem[T]( s:String ) extends Elem[T] {} object Elem // Factory object which hides Elem’s subclasses { // A factory method is called when its signature matches def apply[T]( d:Double ) : Elem[T] = new DblElem[T]( d ) def apply[T]( i:Int ) : Elem[T] = new IntElem[T]( I ) def apply[T]( s:String ) : Elem[T] = new StrElem[T]( s ) } // Elem.apply[T] method is called when its signature matches val elem1 = Elem[T]( 5.0 ) // new DblElem[T]( 5.0 ) val elem2 = Elem[T]( 5 ) // new IntElem[T]( 5 ) val elem3 = Elem[T]( “5” ) // new StrElem[T]( “5” ) 7
  • 8. CASE CLASSES • Case classes are regular classes that extract their constructor parameters • Extraction provides an interrogation mechanism that works particular well with recursion • Instances are constructed with the companion object apply() • Instances are deconstructed by extracting the fields with unapply() in pattern matching • Fields are then externally accessible for interrogation via the Option[T] wrapper - unapply : Option[(u,v)] is called in pattern matching - unapply evaluates to either Some[(u,v)] or None both subclasses of Option - unapply can be modified for custom matching - For multiple fields (u,v) T is a Tuple // Scala expands the case class Add( u:Exp, v:Exp ) to: class Add( val u:Exp, val v:Exp ) //Fields reset to immutable { def toString : String = {..} // Class and field name def equals : Boolean = {..} // Fields compared structurally def hashCode : Int = {..} // hashCode from fields } // Compiler creates a companion object with apply and unapply object Add { def apply( u:Exp, v:Exp ) : Add = new Add(u,v) def unapply( u:Exp, v:Exp ) : Option[(Exp,Exp)] = Some(u,v) } 8
  • 9. PATTERN MATCHING def matchAny( any:Any ) : String = any match { case 1 => “one” case i:Int => “i is an Int” // All ints except 1 case “two” => “2” case d:Double if d > 12.0 => “double > 12.0” case d:Double => “double <= 12.0” case Add(u,v) => (u+v).toString // Extract u,v case (i:Int,j:Int) => (i+j).toString // A tuple of 2 ints case (x,y) => x.toString + y.toString // A tuple of Anys case <tag>{ t }</tag> => t.toString // scala.xml.Node case head :: tail => head.toString // any is a List case _ => “no match” } val Split = """(d*):(S*)""".r // “”” raw string regex "12:test" match { case Split(id,name) => println( name + " = " + id ) case _ => println( "No match" ) } > test = 12 9
  • 10. CLOSURES // Closures declarations are strongly typed func1:(Int,Int) => Int // Two Int args. returns Int func2:(String) => Unit // String arg and returns nothing // Closure implementations can be assigned to variables. // Return types can be inferred val inc = (i:Int) => i + 1 // inc(1) returns 2 val add = (a:Int,b:Int) => a + b // add(2,3) returns 5 var mul = (a:Int) => a * n // n is defined outside val sum = ( nums:Int* ) => { var s=0; for( num <- nums ) { s+=num; } return s } // The map method applies the closure to every element // in a collection and returns a new collection List(1,2,3).map( (i:Int) => i + 1 ) // Returns List(2,3,4) List(1,2,3).map( _ => + 1 ) // Wildcard closure 10
  • 11. PARTIAL FUNCTIONS trait PartialFunction[-A,+B] extends (A) => B A partial function extends closure, by examining its arguments. Arguments are examined for completeness and multiple returns. Cases in curly braces are the easiest approach. Actors use partial functions for message dispatch. // Simple conversion val as:(String)=>Double = { case “a”=>6 case “b” =>3 } // Parsed Expression of a string value to a tuple in JSON { case s ~ v => (s,v) } // Strict type checking of arguments in a tuple in MathParser (u:Exp,v:Exp) => Add(u,v) 11
  • 12. ACTORS trait Actor extends Thread with MailBox // Simple Actor { def act() : unit // Abstract method def ! ( msg:Any ) : unit = send(msg) // “!” to send override def run() : unit = act() // overrides run() def react( f:PartialFunction[Any,Unit]) : Nothing = {…} } // Message ADTs for easy interrogation case class MsgOne( head:String, body:String ) case class MsgTwo( head:String, body:String ) class MessageHandler extends Actor // Extend Actor like Thread. { def act() // Implements act() from Actor instead of run() { react { // react makes actors event based case MsgOne( head, body ) => ... case MsgTwo( head, body ) => ... case _ => ... // Log error } } } // send (!) message asynchronously to the actor's mailbox messagehandler ! message 12
  • 13. A JSON PARSER P~Q sequential composition start = obj | array BNF ~> <~ sequential ignore obj = "{" pair {"," pair}* "}" P|Q alternative Scala Parsing array = "[" value {"," value}* "]" opt(P) optional ? Operators pair = str ":" value // Name value rep(P) repetition * (zero or more) str = StringLit rep1(P) repetition + (one or more) num = NumericLit repsep(P,Q) interleaved repetition * value = 0bj|array|str|num| repsep1(P,Q) interleaved repetition + "true"|"false"|"null" P^^F(R) apply closure F to result R P^^^ conversion class JSONParser extends StdTokenParsers with ImplicitConversions { val lex = new Lexer lex.reserved ++= List( "true", "false", "null" ) // Keywords lex.delimiters ++= List( "{", "}", "[", "]", ":", "," ) def start = obj | array def obj = "{" ~> repsep( pair, "," ) <~ "}" def array = "[" ~> repsep( value, "," ) <~ "]" def pair = str ~ (":" ~> value) ^^ { case s ~ v => (s,v) } def str = accept("string", { case lex.StringLit(s) => s } ) def num = accept("number", { case lex.NumericLit(n)=> n.toDouble }) def value : Parser[Any] = obj | arr | str | num | "true"^^^true | "false"^^^false | "null"^^^null } 13
  • 14. WHAT MAKES SCALA UNIQUE FOR DSLS • ADTS (ABSTRACT DATA TYPES) • OPERATORS & IMPLICIT TYPE CONVERSION FOR INTERNAL DSLS • BNF GRAMMAR BASED PARSING FOR EXTERNAL DSLS • FULL TRANSFORMATION WITH PATTERN MATCHING. 14
  • 15. A BASIC APPROACH TO DSLS WITH MATH ARITHMETIC EXAMPLES Transformation Parsing Input Representation Output 4. External DSL 1.Base 5. Pattern BNF Parser Expression Matching A full Language Defines an Internal Calculate Similar to Internal DSL DSL with Operators Differentiate MathParser Example and Conversions Example 2. ADTs Case Classes that define the DSL by extending Base Expression 3. AST Abstract Syntax Tree 15
  • 16. BASE MATH EXPRESSION WITH OPERATOR METHODS FOR SYMBOLIC MATH abstract class Exp extends with Calculate with Differentiate { // Convert Int and double to Num(n) & String to Var(s) implicit def int2Exp( i:Int ) : Exp = Num(i.toDouble) implicit def dbl2Exp( d:Double ) : Exp = Num(d) implicit def str2Exp( s:String ) : Exp = Var(s) // Infix operators from high to low using Scala precedence def ~^ ( v:Exp ) : Exp = Pow(this,v) // ~^ high precedence def / ( v:Exp ) : Exp = Div(this,v) def * ( v:Exp ) : Exp = Mul(this,v) def - ( v:Exp ) : Exp = Sub(this,v) def + ( v:Exp ) : Exp = Add(this,v) // Prefix operator for negation def unary_- : Exp = Neg(this) } 16
  • 17. CASE CLASSES FOR ADTS • On the surface these ADT case class declarations appear trivial • No further case class implementations. Scala does it for us. • The parser and pattern matchers assign meaning base on type • The arguments define the internal DSL expressions • Each ADT is a Lambda expression node that combines into an AST • Construction is done with the companion object apply(u,v) method • Pattern matching deconstructs ADTs with the object unapply(u,v) case class Num( n:double ) extends Exp // wrap double case class Var( s:String ) extends Exp // wrap String case class Add( u:Exp, v:Exp ) extends Exp // u + v infix case class Sub( u:Exp, v:Exp ) extends Exp // u – v infix case class Mul( u:Exp, v:Exp ) extends Exp // u * v infix case class Div( u:Exp, v:Exp ) extends Exp // u / v infix case class Pow( u:Exp, v:Exp ) extends Exp // u ^ v infix case class Neg( u:Exp ) extends Exp // -u prefix case class Par( u:Exp ) extends Exp // parentheses case class Dif( u:Exp ) extends Exp // Differential case class Err( e:String ) extends Exp // Error 17
  • 18. ABSTRACT SYNTAX TREES * + - “a” 2 “b” 3 • All leaf nodes are either Var(v:String) or Num(d:Double) • Branch nodes are ADTs that can be and infix “+” or the prefix Add • Extracted contents (u,v) of an ADT i.e. Add(u,v) are the child nodes • Branch child nodes are processed with a recursive method call • Operators cannot be used on pattern side, only processing side • Prefix form does not require Par(), but infix does. • ADT prefix and infix can be mixed and checked by the compiler (“a”+2)*(“b”-3) = Mul(Add(Var(“a”),Num(2)),Sub(Var(“b”),Num(3))) (“a”+2)*(“b”-3) = Mul(Add(“a”,2),Sub(“b”,3)) // Implicit (“a”+2)*(“b”-3) = Mul(“a”+2,“b”+3)) // Infix 18
  • 19. A MATH EXPRESSION PARSER object MathParser extends StdTokenParsers { val lex = new StdLexical; type E = Exp lex.delimiters ++= List( "(",")","+","-","^","/","*" ) def NUM:Parser[E] = numericLit ^^ { (s:String) => Num(s.toDouble)} def VAR:Parser[E] = ident ^^ { (s:String) => Var(s) } def par:Parser[E] = "(" ~> exp <~ ")" ^^ { (u:E) => Par(u) } def neg:Parser[E] = "-" ~ exp ^^ { case "-" ~ u => Neg(u)} def beg:Parser[E] = NUM | VAR | par | neg def pow:Parser[E] = beg * ( "^" ^^^ { (u:E,v:E) => Pow(u,v) } ) def mul:Parser[E] = pow * ( "*" ^^^ { (u:E,v:E) => Mul(u,v) } ) def div:Parser[E] = mul * ( "/" ^^^ { (u:E,v:E) => Div(u,v) } ) def add:Parser[E] = div * ( "+" ^^^ { (u:E,v:E) => Add(u,v) } ) def sub:Parser[E] = add * ( "-" ^^^ { (u:E,v:E) => Sub(u,v) } ) def exp:Parser[E] = sub | failure("exp") def parse( str:String ) : Exp = { … } } 19
  • 20. CALCULATION WITH RECURSIVE PATTERN MATCHING trait Calculate { this:Exp => // this is Exp val NaN : Double = Math.NaN_DOUBLE type Assign = (String) => Double // { “a”=>3.0, “b”=>6.0 } def calc( e:Exp, a:Assign ) : Double = e match { case Num(d) => d // Unwrap the double case Var(s) => a(s) // Return double assigned to variable case Add(u,v) => calc(u,a) + calc(v,a) // Recurse case Sub(u,v) => calc(u,a) - calc(v,a) // Recurse case Mul(u,v) => calc(u,a) * calc(v,a) // Recurse case Div(u,v)=>val d=calc(v,a) if d==0.0 NaN else calc(u,a)/d case Pow(u,v) => Math.pow( calc(u,a), calc(v,a) ) case Neg(u) => -calc(u,a) // Recurse case Par(u) => calc(u,a) // Strip off parentheses case Dif(u) => NaN case Err(u) => NaN case _ => NaN } } 20
  • 21. DIFFERENTIATION WITH PATTERN MATCHING trait Differentiate { this:Exp => // this is Exp with all its operators & implicits def d( e:Exp ) : Exp = e match { case Num(n) => 0 // diff of constant zero case Var(s) => Dif(Var(s)) // x becomes dx case Add(u,v) => d(u) + d(v) // Add(d(u),d(v)) case Sub(u,v) => d(u) - d(v) // Sub(d(u),d(v)) case Mul(u,v) => v*d(u)+u*d(v) case Div(u,v) => (v*d(u)-u*d(v))/(v~^2) case Pow(u,v) => v * u~^(v-1) * d(u) case Neg(u) => -d(u) // Neg(d(u)) case Par(u) => Par(d(u)) case Dif(u) => Dif(d(u)) // 2rd dif case Err(u) => Dif(Err(e)) case _ => Err(Dif(e)) } } 21
  • 22. RUNS val a=”a”; val b=”b”; val x=”x”; val y=”y”; val z=”z” val as:Assign = { case a=>6 case b =>3 } // Partial function val ea = a+b; val ca = calc(ea,as) // 9 val ed = a/0; val cd = calc(ed,as) // NaN val ep = a~^b; val cp = calc(ep,as) // 216 val xy = x*y; val dxy = d(xy) // y*dx+x*dx val x3 = x~^3; val dx3 = d(x3) // 3*x^(3-1)*dx val sx3 = sim(dx3) // 3*x^2dx val xy3 = (x+y)^3; val dxy3 = d(xy3) // 3*(x+y)^(3-1)*(dx+dy) val sxy3 = sim(dxy3) // 3*(x+y)^2*(dx+dy) val xyz = x*y*z; val dxyz = d(xyz) // z*(y*dx+x*dy)+x*y*dz val sxyz = sim(dxyx) // z*y*dx+z*x*dy+x*y*dz 22
  • 23. THE BEAUTY OF IMMUTABILITY Immutable vals are used in ADT arguments The use of val insures: • ADT contents are never copied, just re-referenced. • Safety because the references cannot change. • The identity of the contents is preserved. This is liberating because: The contents of ADTs be extracted at will to construct new ADTs that produce new represenentions and meaning by rewrapping the contents. This is the intent of transformation with pattern matching. 23
  • 24. MULTIPLE PARADIGMS Scala’s Uniform Class Hierarchy For Primitives as first class objects TRAITS – TAKE ONE – THE THICK & THIN FOR HIGH REUSE TRAITS – TAKE TWO – THE SELF TYPE FOR FREE DEPENDENCY INJECTION TRAITS - TAKE THREE – STACKABLE MODIFICATIONS FOR AOP INTERCEPTORS MIXINS WITH TRAITS FOR MULTIPLE VIEWS 24
  • 25. Scala’s Uniform Class Hierarchy Any AnyVal // Scala's base class for Java primitives and unit Double Float Long Int Short Char Byte Boolean Unit AnyRef // java.lang.Object String // java.lang.String (all other Java Classes ...) (all other Scala Classes ...) Iterable // base Class for all Scala collections Seq // base Class for all ordered collections Array // compiles to Java arrays [] List // Immutable list for pattern matching scala.Null // is a subtype of all AnyRef classes scala.Nothing // is a subtype of all Any classes • Primitives are treated as "first class objects" not wrapped into classes. • array:Array[Int](len) is mapped to Int[len] array in Java • Java's primitive class wrappers are not needed. • Scala intelligently applies base methods to primitives, even constants. • 5.toString "5".toInt 25
  • 26. TRAITS – TAKE ONE – THE THICK & THIN • Traits are similar to interfaces in Java • As with interfaces a Scala class can mix in any number of traits. • The mixin class can be assigned to or passed as any if its trait types. • Traits can not be constructed so traits do not have primary constructor arguments. • Traits with purely abstract methods map directly to Java interfaces. • Unlike Java interfaces, Scala traits have concrete implementations of methods. • The Thick and Thin Approach to Trait Design - Highest Reuse • First define a small number of abstract methods - the Thin part. • Then implement a potentially large number of concrete methods - the Thick part. • All concrete members implemented in terms of the abstract members. trait Ordered[A] // Parameterized with type [A] { // The Thin abstract part. Must implemented in base class def compare( a:A ) : Int // The Thick part. Concrete methods declared with operators. // All based on the abstract method compare(a) def < ( a:A ) : Boolean = compare(a) < 0 def > ( a:A ) : Boolean = compare(a) > 0 def <= ( a:A ) : Boolean = compare(a) <= 0 def >= ( a:A ) : Boolean = compare(a) >= 0 } 26
  • 27. TRAITS – TAKE TWO – THE SELF TYPE FOR FREE DEPENDENCY INJECTION Just add the self type to a trait to specify how it interprets this class Base {...} trait AddOn { this:Base => ... } trait More {...} trait AddOnOn { this:Base with More => ... } AddOn is a coupled facet of Base with access to Base fields and methods AddOn’s concrete methods builds on Base rather than abstract defs AddOn can be “injected” during construction val BaseAddOn = new Base with AddOn AddOn and BaseAddOn can defined outside of Base to access other packaged Jar files that you do not want incorporated with Base 27
  • 28. AOP WITH TRAITS - TAKE THREE – STACKABLE MODIFICATIONS trait Stuff { def doStuff : Unit } // doStuff abstract class Real { def doStuff=println("Real Stuff")} extends Stuff // abstract override tells the compiler that things are OK // The call to super will reach a concrete class trait Log extends Stuff { abstract override def doStuff : Unit = { println("Log enter"); super.doStuff; println("Log exit")}} trait Txn extends Stuff { abstract override def doStuff : Unit = { println("Txn start"); try { super.doStuff; println("Txn commit"); } catch { case e: Exception => println("Txn rollback") } } } val r2 = new Real with Log; r2.doStuff > 1.Log enter 2.Real stuff 3.Log Exit val r3 = new Real with Log with Txn; r3.doStuff > 1.Txn start 2.Log enter 3.Real stuff 4.Log exit 5.Txn commit val r4 = new Real with Txn with Log; r4.doStuff > 1.Log enter 2.Txn start 3.Real stuff 5.Txn commit 6.Log exit * From: http://jonasboner.com/2008/02/06/aop-style-mixin-composition-stacks-in-scala.html 28
  • 29. AOP – RETRY EXAMPLE class Except extends Stuff { def doStuff : Unit = { println(“Except”); throw new RuntimeException(“msg”)}} trait Retry extends Stuff { abstract override def doStuff : Unit = { var n = 0; var retry = true while( retry ) { try { super.doStuff; retry = false; } catch { case e: Exception => if( n < 3 ) { n += 1; println("Fail retry:" + n) } else { retry = false; throw e } } } } } val r5 = new Except with Retry with Txn with Log; r5.doStuff > 1.Log enter 2.Txn start 3.Except 4.Fail retry:1 5.Except 6.Fail retry:2 7.Except 8.Fail retry:3 9.Txn rollback 10.Log exit * From: http://jonasboner.com/2008/02/06/aop-style-mixin-composition-stacks-in-scala.html 29
  • 30. MIXINS WITH TRAITS – PROVIDES MULTIPLE VIEWS • A great design strategy for breaking up a big Class. • Mixins are type safe and checked by the compiler. • Methods are called in an orderly predicable fashion through linearization. • So the order of mixins is significant. • The secret is how Scala manages this and super • Clients only need to interface to a particular Trait. • Each mixin Trait then provides unique facet to the client. • Traits can be mixed in at runtime during construction. • Traits can be stacked and invoked like AOP interceptors. Stackable Modifications / AOP Trait Thin & Trait Class Thick Trait Trait Trait Self Type 30
  • 31. SCALA IN THE REAL WORLD • REFERENCES • THE FUTURE OF SCALA • MY EXPERIENCE • CONCLUSION 31
  • 32. REFERENCES URLs • Scala Community: www.scala-lang.org • Artima: www.artima.com • Planet Scala: www.planetscala.com IDEs – Netbeans IntelliJ Eclipse 32
  • 33. THE FUTURE OF SCALA Lift A unique web framework, with: Wicket like templates and actor concurrency Lift S Site Map SHTML Views Rules State Context Lift Core Lift Comet Response Mapper / Record HTTP JavaScript ORM Authentication API jQuery Utilities / Scala Platform / J2EE Web Container / JVM A stable foundation for dynamically type languages A new language foundation for the JVM • Scalahas implemented practically all of the new features being discussed for upgrading Java. • Closures, parameterized types done right, flexible packaging “If I were to pick a language to use today other than Java, it would be Scala” - James Gosling 33
  • 34. MY SCALA EXPERIENCES SO FAR My work in Scala so far has centered on symbolic mathematics I am currently converting my interactive drawing application to Scala • Visio and SVG shapes and connectors • Text editing • CSS and SVG styles I am experimenting with DSLs and ADTs for Enterprise Architecture 34
  • 35. CONCLUSION I want to express my appreciation to: Derek Chen-Becker Mathew McCullough Frederick Jean Daniel Glauser John Lowe Paul Gillen for stimulating emails, reviews, conversation and support Google code distribution for code, papers and presentations: http://code.google.com/p/axiom-architectures/ EMail: Thomas.EdmundFlaherty@gmail.com DOSUG Slideshare: 35