In pursuit of expressivity:Groovy and Scala compared          Chris Richardson     Author of POJOs in Action   Founder of ...
Overall presentation goal Examine the good, the bad and the ugly      aspects of    developing with   Groovy and Scala    ...
About Chris              •    Grew up in England and live in Oakland, CA              •    Over 25+ years of software deve...
Agendao  Evolution of programming   languageso  Favorite Groovy featureso  The frustration of using Groovyo  Scala: expres...
Lots of programming languages This site lists 8512 languages, complete with 17837 bibliographic records featuring 11064 ex...
The Elite v. The MassesThe Elite                                             Mainstreamo  Lisp                            ...
LISP/CLOS – an early (late 1980s)dynamic language (defclass Account ()   ((account-id :accessor account-id :initarg :accou...
… a very dynamic language  (defclass Account ()    ((account-id :accessor account-id :initarg :account-id)                ...
Along came Javao  Provided the masses with:  n  Garbage collection  n  Safety, reliability and securityo  And 10+ years ...
Ruby on Rails woke up the Javacommunityo  Ruby on Rails:  n  Significantly more productive  n  Simplicity of Convention ...
…Highlighted Problems with Javao  Tedious collection processingo  Painful object construction code   n  No literals for c...
Dynamic languages on the JVMo  JRuby   n  http://jruby.codehaus.org   n  Ruby on the JVMo  Jython   n  http://www.jytho...
Small but growing     4/3/11   Copyright (c) 2011 Chris Richardson. All rights reserved.                                  ...
Static languages on the JVM   o  (Java)   o  Fortress   o  Gosu   o  Scala   o  …http://www.is-research.de/info/vmlanguage...
Scala and Gosu adoption – Smallerbut growing     4/3/11   Copyright (c) 2011 Chris Richardson. All rights reserved.       ...
Agendao  Evolution of programming languageso  Favorite Groovy featureso  The frustration of using Groovyo  Scala: expressi...
About Groovyo  Object-oriented, dynamic languageo  Made popular by the Grails   framework:  n  Rails-like productivity  n...
The good newso  Easy to learn  n  Designed to be Java compatible  n  Interactive Shello  Great support for DSLso  Closur...
Intentionally compatible with Javao  Groovy objects are Java objectso  Groovy collections are Java collectionso  Groovy ca...
Groovy can look like Javaimport javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;class EC2RequestExecutor {        ...
Groovy is concise and expressivedef configureAsMaster() {      writeFile fileName: "/etc/my.cnf", templateName: "/template...
An interactive shell     Great for experimentation and learning      4/3/11     Copyright (c) 2011 Chris Richardson. All r...
Literals for lists and mapsdef myList = ["a", "b", "c"]def params = [Action: RunInstances,       MinCount: n.toString(), M...
GStringso  Templating mechanismo  Embedded Groovy expressionso  Multi-line stringsdef schemaScript = """  DROP SCHEMA IF E...
Closures – collection processing public EC2Server findInstance(String instanceId) {   def server = servers.find {instanceI...
Closures – new control structurespublic class Ssh {def withTunnel(String publicDnsName, int localPort, int remotePort, Clo...
Closures detailsgroovy:000> x = { println z }===> groovysh_evaluate$_run_closure1@658ba380groovy:000> x.delegate = [z: 99]...
Simple reusable codeinterface Quackable {  void quack();                                                                  ...
Method Missingpublic class ClassWithMissingMethods {    def methodMissing(String name, args) {       Closure method = make...
Groovy metaclassespublic class StringMetaclassExampleTest extends GroovyTestCase {    void testAddMethodToString() {      ...
XML and GPath expressions                                                            <RunInstancesResponse>               ...
Metaclasses enhance JDK classesgroovy:000> new File("/Users/cer/.bashrc").text===> export PATH=/Users/cer/tools/apache-mav...
Buildersdef report(String path, hosts, cpuCount, threadCount) {  def builder = new groovy.xml.MarkupBuilder(new OutputStre...
Grails plugins use metaclasseso  Key part of the Grails pluginso  Plugins can dynamically add methods,   e.g. GORM persist...
Grails/GORM persistence methods class Customer {                                            Implemented using    String na...
Commentable plugin exampleclass CommentableGrailsPlugin { def doWithDynamicMethods = { ctx -> for(domainClass in applicati...
Grails DSL for ORM class Customer {   static transients = ["networth"]  static mapping = {      id column: ‘customer_id’  ...
Grails Controllers -o  Accessing request/responseo  Databinding  n  b.properties = params  n  new B(params)o  …       4/...
Agendao  Evolution of programming languageso  Favorite Groovy featureso  The frustration of using Groovyo  Scala: expressi...
Getting complex Groovy code towork can be frustratingo  Dynamic language = less information   for IDE:  n    Limited comp...
Groovy fans say "write unit tests“BUT…                                                                                    ...
Unit tests dont always catch errors  void testPollStatus_discoveringNewServer() {       mockEC2RequestExecutor.demand.exec...
The trouble with duck typingo  Interface between components not   defined in a single placeo  It is scattered throughout c...
The outcome: fear of change                                Did my tests                                catch all          ...
Agendao  Evolution of programming languageso  Favorite Groovy featureso  The frustration of using Groovyo  Scala: expressi...
Distilling a language                                                                                  Builders           ...
Scala – a modern (2003) staticlanguageo  Object-oriented   n  Pure object-oriented language   n  All values are objects ...
The good newso  Fully interoperable with Javao  Interactive shello  Rich, extensible languageo  Closureso  Good XML proces...
Scala command line    4/3/11   Copyright (c) 2011 Chris Richardson. All rights reserved.                                  ...
Simple exampleobject StringFunctions {    def reverseSentence(sentence : String) = sentence.split(" ").reverse.mkString(" ...
Collection literals example@Testclass ScalaCollectionExamplesTest {@Test def listExample() = {   val myList = List(1, 2, 3...
Closure example@Testclass ScalaCollectionExamplesTest {    @Test    def testMapList() = {      val myList = List(1, 2, 3) ...
Defining new control constructs 1class ExampleControlConstructExampleTest {def withOutputStream[T](f : File)(body : InputS...
Defining new control constructs 2                                               By-name parameter var assertsEnabled = fal...
Pattern matchingcase class Organization(name: String,     industry: Industry.Value, revenue: Double, assets: Double, liabi...
XML generation@Testclass ScalaXmlExampleTest {  @Test  def xmlLiterals() {   val now = new Date()   val loanRequestor =   ...
XML parsingclass ScalaXmlExampleTest {  @Test  def xmlProcessing() {   val doc = xml.XML.loadString(docAsString)   assertE...
DSL Exampleclass OrganizationDslTest {  val o : Organization = (Organization                       called "Bernie Madoff &...
Named arguments and default valueso  Arguments can be namedo  Parameters can have default valueso  Benefits:  n  Clearer ...
Constructing object hierarchies  object ExampleSwingApp extends SimpleGUIApplication {      def top = new MainFrame {     ...
Pimping existing classesscala> 5.times { println("Hello") }<console>:6: error: value times is not a member of Int      5.t...
Implicit parameters 1@Testdef implicitParamsImplicitVar { implicit val defaultValue = 8    def m(i : Int) (implicit j : In...
Implicit parameters 2scala> implicit def toInt : Int = 5toInt: Intscala> def m(i : Int) (implicit j : Int) = i * jm: (i: I...
Null References                                        My Billion Dollar                                            mistak...
Use Options instead of null…var x : Option[Int] = Some(5)var y : Option[Int] = Nonevar z : Option[Int] = Some(7)assertEqua...
… more optionsassertEquals(Some(7), x.map(_ + 2))assertEquals(None, y.map(_ + 2))assertEquals(None, x.filter(_ == 2))asser...
Traitso  Consist of members  n  methods  n  fields  n  typeso  The members can be abstracto  Multiple traits can be mix...
RESTful WS using Spring MVC and  Scalao  Handling HTTP request                                          Photo management  ...
Pattern matching HTTP Requests  o  Match against       n  URL – represented as a List       n  Method       n  …  o  Re...
The Extractorobject Request {   def unapply(request : HttpServletRequest)        : Option[ (List[String], String, RequestB...
Package as WSEndpointstrait WsEndpoint extends PartialFunction[HttpServletRequest, Node] {    def isDefinedAt(request : Ht...
Integrate with Spring MVC 1@Componentclass WsEndpointHandlerMapping extends HandlerMapping {@Autowireddef setApplicationCo...
Integrate with Spring MVC 2@Componentclass WsEndpointHandlerAdapter extends HandlerAdapter { override def supports(handler...
Scala and Spring DIo  Scala and Spring DI play togethero  @Component on Scala classes workso  @Autowired fields:  n  Anno...
Agendao  Evolution of programming languageso  Favorite Groovy featureso  The frustration of using Groovyo  Scala: expressi...
Really bad newso  Scala IDEs are ok and slowly   improving BUT have a really really   long way to go compared to Javao  Li...
More bad news…o  Expressiveness comes from complex   language featureso  Generics are better than Java but still   complex...
…more bad newso  Lift is not Grails (or Rails)o  A subset of the Scala community has   a functional programming background...
Summaryo  The Java Language has stagnated and   need to be replacedo  Dynamic languages are one optiono  But many benefits...
Summary – Pessimistic viewo  Languages used by mainstream   developers have improved   substantiallyo  But are those langu...
Final thoughtso  Learn some languages including   Haskello  Watch the 50 in 50 presentation by   Guy Steele and Dick Gabri...
The end                                    Twitter:                                    @crichardson                       ...
Upcoming SlideShare
Loading in...5
×

In pursuit of expressivity: Groovy and Scala compared

9,765

Published on

Thirty years ago the famous computer scientist Tony Hoare said “I have regarded it as the highest goal of programming language design to enable good ideas to be elegantly expressed”. His comment sums up what has been driving the evolution of programming languages: the desire to create increasingly expressive languages. In this talk you will learn about two modern JVM languages that strive to be expressive in very different ways. We will talk about Groovy, which is a dynamically-typed language, and Scala, which is a statically-typed language. You will learn about the key features of each language as well as their benefits and the drawbacks.

Published in: Technology
1 Comment
12 Likes
Statistics
Notes
  • Slide 74: you don't need to define and annotate setters. Just use @(Autowired @beanSetter)
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total Views
9,765
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
0
Comments
1
Likes
12
Embeds 0
No embeds

No notes for slide

In pursuit of expressivity: Groovy and Scala compared

  1. 1. In pursuit of expressivity:Groovy and Scala compared Chris Richardson Author of POJOs in Action Founder of CloudFoundry.com chris@chrisrichardson.net @crichardson
  2. 2. Overall presentation goal Examine the good, the bad and the ugly aspects of developing with Groovy and Scala 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 2
  3. 3. About Chris •  Grew up in England and live in Oakland, CA •  Over 25+ years of software development experience including 14 years of Java •  Speaker at JavaOne, SpringOne, NFJS, JavaPolis, Spring Experience, etc. •  Organize the Oakland JUG ( http://bit.ly/ebjava) and the Groovy Grails meetup (http://bit.ly/oakgrails) http://www.theregister.co.uk/2009/08/19/springsource_cloud_foundry/ 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 3
  4. 4. Agendao  Evolution of programming languageso  Favorite Groovy featureso  The frustration of using Groovyo  Scala: expressiveness and compile- time checkingo  The trouble with Scala 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 4
  5. 5. Lots of programming languages This site lists 8512 languages, complete with 17837 bibliographic records featuring 11064 extracts from those references. It is in effect a family tree of languages with 5445 links, making it not only the biggest programming language family tree around, but also one of the largest idea-genealogical projects undertaken. http://hopl.murdoch.edu.au/ 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 5
  6. 6. The Elite v. The MassesThe Elite Mainstreamo  Lisp o  Thought Lisp and n  Invented in the 1960s Smalltalk were: n  Dynamic functional n  Weird (Too different language from Algol) n  Dynamic object-oriented n  Too resource hungry language (mid-1980s) (probably were for theo  Smalltalk time) n  Invented in the 1970s o  So the mainstream used: n  Dynamic object-oriented Pascal, C, C++, …. language o  Not so safe, manualo  Safe, garbage collection, memory management, rich, … primitive, … 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 6
  7. 7. LISP/CLOS – an early (late 1980s)dynamic language (defclass Account () ((account-id :accessor account-id :initarg :account-id) (balance :accessor account-balance :initarg :balance)) Develop by adding and ) changing program elements in a running VM (defmethod debit ((Account account) amount) (decf (account-balance account) amount)) (defmethod credit ((Account account) amount) (incf (account-balance account) amount)) CL-USER 5 > (setq a (make-instance account :account-id "abc123" :balance 10.0)) #<ACCOUNT 200C05AF> CL-USER 6 > (describe a) #<ACCOUNT 200C05AF> is an ACCOUNT ACCOUNT-ID "abc123" BALANCE 10.0 CL-USER 7 > (debit a 5) 5.0 CL-USER 8 > (describe a) #<ACCOUNT 200C05AF> is an ACCOUNT ACCOUNT-ID "abc123" BALANCE 5.0 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. 7
  8. 8. … a very dynamic language (defclass Account () ((account-id :accessor account-id :initarg :account-id) Existing instances (balance :accessor account-balance :initarg :balance) are updated when (description :accessor account-description :initarg :description)) the class is redefined ) CL-USER 9 > (describe a) #<ACCOUNT 2168DCBF> is an ACCOUNT ACCOUNT-ID "abc123" BALANCE 10.0 DESCRIPTION #<unbound slot> CL-USER 10 > (setf (account-description a) "checking account") "checking account" CL-USER 11 > (describe a) #<ACCOUNT 2168DCBF> is an ACCOUNT ACCOUNT-ID "abc123" BALANCE 10.0 DESCRIPTION "checking account" 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. 8
  9. 9. Along came Javao  Provided the masses with: n  Garbage collection n  Safety, reliability and securityo  And 10+ years passed… 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 9
  10. 10. Ruby on Rails woke up the Javacommunityo  Ruby on Rails: n  Significantly more productive n  Simplicity of Convention over Configurationo  Motivated the Java community to improve: frameworks such as Spring improved considerablyo  And… 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 10
  11. 11. …Highlighted Problems with Javao  Tedious collection processingo  Painful object construction code n  No literals for collections n  Need to use Builders for creating hierarchieso  Tedious XML processingo  Types: n  Verbose declarations n  Generics are complicatedo  Fixed set of control constructso  Limited support for DSLs =>o  Reopened the debate about programming languageso  Dynamic languages became interesting again 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 11
  12. 12. Dynamic languages on the JVMo  JRuby n  http://jruby.codehaus.org n  Ruby on the JVMo  Jython n  http://www.jython.org/Project n  Python on the JVMo  Clojure n  http://clojure.org/ n  Functional programming language n  Software Transactional Memory n  …o  Groovy n  http://groovy.codehaus.org/ n  Java-compatible, dynamic language 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 12
  13. 13. Small but growing 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 13
  14. 14. Static languages on the JVM o  (Java) o  Fortress o  Gosu o  Scala o  …http://www.is-research.de/info/vmlanguages/?s=static 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 14
  15. 15. Scala and Gosu adoption – Smallerbut growing 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 15
  16. 16. Agendao  Evolution of programming languageso  Favorite Groovy featureso  The frustration of using Groovyo  Scala: expressiveness and compile- time checkingo  The trouble with Scala 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 16
  17. 17. About Groovyo  Object-oriented, dynamic languageo  Made popular by the Grails framework: n  Rails-like productivity n  Using robust Java frameworks including Spring and Hibernate 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 17
  18. 18. The good newso  Easy to learn n  Designed to be Java compatible n  Interactive Shello  Great support for DSLso  Closures: n  Easy collection processing n  New control constructso  Property/method missing mechanismo  Good XML handlingo  Meta-classes for dynamically defining new program elements => foundation for Grails 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 18
  19. 19. Intentionally compatible with Javao  Groovy objects are Java objectso  Groovy collections are Java collectionso  Groovy can call Java n  e.g. leverage all those Java librarieso  Java can call Groovy, e.g. Groovy objects can be: n  Spring beans n  Hibernate objectso  Easy to write a module of a project Groovy => Easy to incrementally adopt 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 19
  20. 20. Groovy can look like Javaimport javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;class EC2RequestExecutor { Java-like syntaxLog logger = LogFactory.getLog(getClass()) public String calculateRFC2104HMAC(String data, String key) { try { SecretKeySpec signingKey = new SecretKeySpec(key.getBytes("UTF8"), HMAC_SHA1_ALGORITHM) Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM) mac.init(signingKey) byte[] rawHmac = mac.doFinal(data.getBytes()) return new String(Base64.encodeBase64(rawHmac)) } catch (Exception e) { throw new RuntimeException("Failed to generate HMAC : ", e) }} 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 20
  21. 21. Groovy is concise and expressivedef configureAsMaster() { writeFile fileName: "/etc/my.cnf", templateName: "/templates/master.my.cnf" restartService "mysqld" exec command: "mysql -u root", templateName: "/templates/createSchema.sql", No parens templateArgs: [schemaSpec: schemaSpec] Keyword parameters executeSchemaScripts() } class TomcatServer { tomcatServer.contexts No get…() def getContexts() { webApps.context } } 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 21
  22. 22. An interactive shell Great for experimentation and learning 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 22
  23. 23. Literals for lists and mapsdef myList = ["a", "b", "c"]def params = [Action: RunInstances, MinCount: n.toString(), MaxCount: n.toString(), ImageId: awsProperties."imageId.${instanceType}", KeyName: awsProperties.keyName, InstanceType: instanceType] + extraParamsdef response = requestor.executeRequest(params) 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 23
  24. 24. GStringso  Templating mechanismo  Embedded Groovy expressionso  Multi-line stringsdef schemaScript = """ DROP SCHEMA IF EXISTS ${schemaSpec.name}; CREATE SCHEMA ${schemaSpec.name}; """ 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 24
  25. 25. Closures – collection processing public EC2Server findInstance(String instanceId) { def server = servers.find {instanceId == it.instanceId} if (server) return server else throw new RuntimeException(….) }assertEquals(["aa", "bb", "cc"], ["a", "b", "c"].collect { elem -> elem + elem }Simplified collection processingNo ugly anonymous inner classes 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 25
  26. 26. Closures – new control structurespublic class Ssh {def withTunnel(String publicDnsName, int localPort, int remotePort, Closure closure) { SshConnection sshConnection = makeSshConnection(publicDnsName); try { sshConnection.connect() … return closure.call() } finally { sshConnection.close() } }}class EC2 {String snapshotEbsVolume(String hostName, EbsVolume ebsVolume, String schemaName) { int localPort = PortUtil.allocatePort() def result = ssh.withTunnel(hostName, localPort, 3306) { … } return (String)result }} 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 26
  27. 27. Closures detailsgroovy:000> x = { println z }===> groovysh_evaluate$_run_closure1@658ba380groovy:000> x.delegate = [z: 99]===> Foo@564a5320groovy:000> x.call() Used to resolve99 unbound methods and properties===> null For example, Builders set the delegate 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 27
  28. 28. Simple reusable codeinterface Quackable { void quack(); Java:} complexity ofclass QuackableContainer<T extends Quackable> genericsvoid add(T element) { element.quack(); …}…}class QuackableContainer { Groovy: just assume thatvoid add(element) { there is a quack() method element.quack() …} 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 28
  29. 29. Method Missingpublic class ClassWithMissingMethods { def methodMissing(String name, args) { Closure method = makeMethodImplementation(name) if (method) { method(args) } else { throw new MissingMethodException(name, getClass(), args) } } def makeMethodImplementation(String name) { …. }} def foo = new ClassWithMissingMethods() foo.nonExistentMethod() 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 29
  30. 30. Groovy metaclassespublic class StringMetaclassExampleTest extends GroovyTestCase { void testAddMethodToString() { String.metaClass.doubleString = { -> delegate + delegate } String.metaClass.static.makePowerString = { String s, int n -> def result = s n.times { result = result.doubleString() } result } assertEquals "JavaZoneJavaZone", "JavaZone".doubleString() assertEquals "OsloOsloOsloOslo", String.makePowerString("Oslo", 2) }} Runtime definition of program elements The foundation of many powerful features 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 30
  31. 31. XML and GPath expressions <RunInstancesResponse> … <instancesSet> <item> <instanceId>i-4ef21327</instanceId> <imageId>ami-3795705e</imageId> <instanceState> <code>0</code>def client = new HttpClient() <name>pending</name>… </instanceState>def responseStream = <dnsName/> … getMethod.getResponseBodyAsStream() </RunInstancesResponse>def parser = new XmlParser(false, false)def response = parser.parseText(responseStream)def newServers = response.instancesSet.item.collect { new EC2Server(this, awsProperties, ssh, it.instanceId.text(), it.instanceState.name.text())} 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 31
  32. 32. Metaclasses enhance JDK classesgroovy:000> new File("/Users/cer/.bashrc").text===> export PATH=/Users/cer/tools/apache-maven-3.0/bin:$PATHgroovy:000> l = [1,2,3]===> [1, 2, 3]groovy:000> l.getClass()===> class java.util.ArrayListgroovy:000> l.getClass().metaClass.foo = { delegate.size }===> groovysh_evaluate$_run_closure1@13a66c87groovy:000> l.foo()===> 3 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 32
  33. 33. Buildersdef report(String path, hosts, cpuCount, threadCount) { def builder = new groovy.xml.MarkupBuilder(new OutputStreamWriter(new FileOutputStream(path))) builder.performanceReport { cpus cpuCount threads threadCount hosts.entrySet().each {hostName, metric -> host { name hostName <performanceReport> cpuUtil metric.getAverageBusy() <cpus>1</cpus> } <threads>10</threads> } <host> requests { timing.sort{ a, b-> a.key <=> b.key}.each{ requestName, metric-> <name>database</name> request { <cpuUtil>3.27</cpuUtil> name requestName </host> art metric.average() <host> errors metric.errorPercentage() <name>tomcat0</name> } } <cpuUtil>94.32</cpuUtil> } </host> def durationValue = (endTime – startTime)/1000.0 … duration durationValue <duration>557.943</duration> def tpsValue = transactionCount/ durationValue <tps>10.753786677133686</tps> tps tpsValue art averageResponseTime() <art>916.6578333333</art> } </performanceReport> } 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 33
  34. 34. Grails plugins use metaclasseso  Key part of the Grails pluginso  Plugins can dynamically add methods, e.g. GORM persistence methodso  Injected methods are closures that have access to the Spring application context n  Less need for traditional dependency injection n  Alternative to AOP static crosscutting or (non-POJO) inheritance 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 34
  35. 35. Grails/GORM persistence methods class Customer { Implemented using String name metaclasses and method } missing Customer c = new Customer("John Doe") if (!c.save()) fail "validation failed: ${c.errors}" Customer c2 = Customer.get(c.id) c2.delete() assertNull Customer.get(c.id) def customers = Customer.findAllByName(“Fred”) 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 35
  36. 36. Commentable plugin exampleclass CommentableGrailsPlugin { def doWithDynamicMethods = { ctx -> for(domainClass in application.domainClasses) { if(Commentable.class.isAssignableFrom(domainClass.clazz)) { domainClass.clazz.metaClass { static { getRecentComments {-> … } } addComment { poster, String text -> } getComments = {-> }…} 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 36
  37. 37. Grails DSL for ORM class Customer { static transients = ["networth"] static mapping = { id column: ‘customer_id’ Closures table ‘crc_customer’ columns { } name column: ‘customer_name’ Method } missing def getNetworth() { … } } ... 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 37
  38. 38. Grails Controllers -o  Accessing request/responseo  Databinding n  b.properties = params n  new B(params)o  … 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 38
  39. 39. Agendao  Evolution of programming languageso  Favorite Groovy featureso  The frustration of using Groovyo  Scala: expressiveness and compile- time checkingo  The trouble with Scala 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 39
  40. 40. Getting complex Groovy code towork can be frustratingo  Dynamic language = less information for IDE: n  Limited compile-time checking n  Limited refactorings n  Limited completion n  No todo list of errors 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 40
  41. 41. Groovy fans say "write unit tests“BUT… Groovy When you have typos versus Java 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 41
  42. 42. Unit tests dont always catch errors void testPollStatus_discoveringNewServer() { mockEC2RequestExecutor.demand.executeRequest {params -> …. } def mockEC2Server = new MockFor(EC2Server.class) …. mockEC2Server.use { mockEC2RequestExecutor.use { ec2 = new EC2(awsProperties) ec2.pollStatus() public class EC2 { assertEquals 1, ec2.servers.size() } public pollStatus() { } def params = [Action: } DescribeInstances] def p = requestor.executeRequest(params)class EC2RequestExecutor { … } public Node executeEc2Request(Map …parameters) { } Method signature changes are … often missed} Slide 42 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved.
  43. 43. The trouble with duck typingo  Interface between components not defined in a single placeo  It is scattered throughout callerso  Difficult to understando  Difficult to change 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 43
  44. 44. The outcome: fear of change Did my tests catch all the obvious errors? 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 44
  45. 45. Agendao  Evolution of programming languageso  Favorite Groovy featureso  The frustration of using Groovyo  Scala: expressiveness and compile-time checkingo  The trouble with Scala 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 45
  46. 46. Distilling a language Builders Dynamic methods and properties Gpath-based XML handling Dynamic features Static features Closures Groovy Literals for collections GStrings 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 46
  47. 47. Scala – a modern (2003) staticlanguageo  Object-oriented n  Pure object-oriented language n  All values are objects “I can honestly say if someone had n  Class-based shown me the Programming in Scala book by by Martin Odersky,o  Functional Lex Spoon & Bill Venners back in n  Functions are values 2003 Id probably have never created Groovy.” n  Higher-order functions n  Currying James Strachan, Creator of Groovy http://macstrac.blogspot.com/o  Statically typed 2009/04/scala-as-long-term- n  Expressive replacement-for.html n  Type inferenceo  Extensible to support domain specific languages n  Methods as infix and postfix operators n  Automatic closure construction 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 47
  48. 48. The good newso  Fully interoperable with Javao  Interactive shello  Rich, extensible languageo  Closureso  Good XML processingo  Named arguments and default parameter valueso  Option class avoids null referenceso  Traits provide “multiple inheritance” 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 48
  49. 49. Scala command line 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 49
  50. 50. Simple exampleobject StringFunctions { def reverseSentence(sentence : String) = sentence.split(" ").reverse.mkString(" ")}import org.junit._import Assert._@Testclass StringFunctionsTest { @Test def testReverseSentence() = { val input = "Hello New York" val expected = "York New Hello" assertEquals(expected, StringFunctions.reverseSentence(input)) }} 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 50
  51. 51. Collection literals example@Testclass ScalaCollectionExamplesTest {@Test def listExample() = { val myList = List(1, 2, 3) assertEquals(3, myList.length) assertEquals(List(0, 1, 2, 3), 0::myList) assertEquals(List(2, 3), myList.tail) assertEquals(1, myList.head) } @Test def testMapExampleList() : Unit = { val myMap = Map( "x" -> 1, "y" -> 2, "z" -> 3) assertEquals(1, myMap("x")) }} 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 51
  52. 52. Closure example@Testclass ScalaCollectionExamplesTest { @Test def testMapList() = { val myList = List(1, 2, 3) assertEquals(List(2,4,6), myList.map ( x => x * 2)) assertEquals(List(2,4,6), myList.map ( _ * 2)) } @Test def testFilterList() = { val myList = List(1, 2, 3) assertEquals(List(1, 3), myList.filter( _ % 2 == 1)); }} 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 52
  53. 53. Defining new control constructs 1class ExampleControlConstructExampleTest {def withOutputStream[T](f : File)(body : InputStream => T) = { val fis = new FileInputStream(f) try { body(fis) } finally { fis.close } } @Test def withOpenFileExample { withOutputStream(new File("/Users/cer/.bashrc")) {fis => println(fis.available) } } 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 53
  54. 54. Defining new control constructs 2 By-name parameter var assertsEnabled = false def myAssert(message : String, assertion : => Boolean) { if (assertsEnabled) { if (!assertion) throw new RuntimeException(message) } } @Test def assertionsDisabled = { myAssert("never", { println("you will not see me") ; false }) } 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 54
  55. 55. Pattern matchingcase class Organization(name: String, industry: Industry.Value, revenue: Double, assets: Double, liabilities: Double) {}object Industry extends Enumeration { val Banking, GreenEnergy, IT, Other = Value}class LoanApprovalPolicy { def isLoanApproved(organization : Organization) = organization match { case Organization(_, Industry.GreenEnergy, _, _, _) => true case Organization(_, Industry.Banking, _, assets, liabilities) if liabilities < assets * 1.5 => true case Organization(_, Industry.Banking, _, _, _) => false case Organization(_, _, _, assets, liabilities) if assets > liabilities => true case _ => false }} 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 55
  56. 56. XML generation@Testclass ScalaXmlExampleTest { @Test def xmlLiterals() { val now = new Date() val loanRequestor = new Organization("Community Bank, Inc", Industry.Banking, 10, 10, 5) val doc = <loanRequest> <time>{now.getTime()}</time> <requester>{loanRequestor.name}</requester> <industry>{loanRequestor.industry}</industry> <revenue>{loanRequestor.revenue}</revenue> <assets>{loanRequestor.assets}</assets> <liabilities>{loanRequestor.liabilities}</liabilities> </loanRequest> val docAsString : String = doc.toString() println(docAsString) } 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 56
  57. 57. XML parsingclass ScalaXmlExampleTest { @Test def xmlProcessing() { val doc = xml.XML.loadString(docAsString) assertEquals ("Community Bank, Inc", (doc "requester").text) doc match { case <loanRequest>{children @ _* }</loanRequest> => for (x <- children if !x.isInstanceOf[scala.xml.Text]) { processChildren(x) } } } def processChildren(node : scala.xml.Node ) = { node match { case <time>{value}</time> => println(value.text) case <requester>{value}</requester> => println(value.text) … } } 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 57
  58. 58. DSL Exampleclass OrganizationDslTest { val o : Organization = (Organization called "Bernie Madoff & Associates" in Industry.Banking withRevenuesOf (10 million) withAssetsOf (10 billion) withLiabilitiesOf (30 billion))} object Organization { def called(name : String) = new OrganizationBuilder(name) class OrganizationBuilder(name : String) { var industry : Industry.Value = null def in(industry : Industry.Value) = { this.industry = industry; this } def withRevenuesOf(…) = … … def make()= new Organization(name, industry, revenue, assets, liabilities) } implicit def organizationBuilderToOrganization(builder : OrganizationBuilder) = builder.make } 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 58
  59. 59. Named arguments and default valueso  Arguments can be namedo  Parameters can have default valueso  Benefits: n  Clearer code – Booleans aren’t so evil n  Avoids confusing overloaded methods/ constructors n  Less need for the Builder patterndef foo(x: Int = 10, y: Int = 20) = x * yfoo() should be(200)foo(y = 30, x = 50) should be(1500)foo(x = 50) should be(1000) 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 59
  60. 60. Constructing object hierarchies object ExampleSwingApp extends SimpleGUIApplication { def top = new MainFrame { title = "Example Swing App" Defines method declared abstract in superclass val button = new Button { text = "press" } Sets property contents = button var count = 0 Statements/ listenTo(button) reactions += { expressions that case ButtonClicked(b) => are executed count = count + 1 Console.println(count); b.text = "press: " + count Nesting of new Class { } } } mirrors object hierarchy } 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 60
  61. 61. Pimping existing classesscala> 5.times { println("Hello") }<console>:6: error: value times is not a member of Int 5.times { println("Hello") } ^scala> class IntWithTimes(n: Int) { | def times(body: => Unit) = for (x <- 1 to n) body | }defined class IntWithTimesscala> implicit def toIntWithTimes(n: Int) = new IntWithTimes(n)toIntWithTimes: (n: Int)IntWithTimesscala> 5.times { println("Hello") }HelloHelloHello Implicit conversionHelloHello 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 61
  62. 62. Implicit parameters 1@Testdef implicitParamsImplicitVar { implicit val defaultValue = 8 def m(i : Int) (implicit j : Int) = i * j assertEquals(48, m(6)) assertEquals(42, m(6)(7))} 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 62
  63. 63. Implicit parameters 2scala> implicit def toInt : Int = 5toInt: Intscala> def m(i : Int) (implicit j : Int) = i * jm: (i: Int)(implicit j: Int)Intscala> m(6)res6: Int = 30scala> m(6)(7)res7: Int = 42 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 63
  64. 64. Null References My Billion Dollar mistake 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 64
  65. 65. Use Options instead of null…var x : Option[Int] = Some(5)var y : Option[Int] = Nonevar z : Option[Int] = Some(7)assertEquals(5, x.get)try { y.get fail } catch { case _ : NoSuchElementException => }assertEquals(5, x.getOrElse(10))assertEquals(10, y.getOrElse(10)) 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 65
  66. 66. … more optionsassertEquals(Some(7), x.map(_ + 2))assertEquals(None, y.map(_ + 2))assertEquals(None, x.filter(_ == 2))assertEquals(Some(5), x.filter(_ == 5))assertEquals(Some(35), for (a <- x ; b <- z) yield a * b) 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 66
  67. 67. Traitso  Consist of members n  methods n  fields n  typeso  The members can be abstracto  Multiple traits can be mixed into a class n  Alternative to multiple inheritance n  Class must define abstract memberso  Uses: n  Modularizing applications n  Enriching interfaces n  Decorating classes 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 67
  68. 68. RESTful WS using Spring MVC and Scalao  Handling HTTP request Photo management n  Extract values from URL n  Invoke appropriate handler application n  Generate response (XML)o  Sounds like a job for Scalas GET /album n  Pattern matching GET /album/<albumId> n  XML support POST /album … <album> <id>6699</id>GET /album/6699 <photos>…</photos> … </album> 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 68
  69. 69. Pattern matching HTTP Requests o  Match against n  URL – represented as a List n  Method n  … o  Returns XMLrequest match {case Request(List("album"), "GET", _, _) => listAlbumscase Request(List("album", albumId), "GET", _, _) => findAlbum(albumId)} def findAlbum(albumId : String) = { def album = albumService.findAlbum(albumId) <album> <id>{album.getId()}</id> <photos>…</photos> … </album> } 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 69
  70. 70. The Extractorobject Request { def unapply(request : HttpServletRequest) : Option[ (List[String], String, RequestBody, Binder)] ={ val path = List.fromArray(request.getPathInfo().split("/")).tail Some(path, request.getMethod, new RequestBody(request), new Binder(request)) }} 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 70
  71. 71. Package as WSEndpointstrait WsEndpoint extends PartialFunction[HttpServletRequest, Node] { def isDefinedAt(request : HttpServletRequest) = wsDispatchRules.isDefinedAt(request) def apply(request : HttpServletRequest) = wsDispatchRules(request) protected def wsDispatchRules : PartialFunction[HttpServletRequest, Node]} @Component class AlbumWsEndpoint extends WsEndpoint { @Autowired def setAlbumService(albumService : AlbumService) = … def wsDispatchRules = { case Request(List("album", albumId), "GET", _, _) => findAlbum(albumId) … } def findAlbum(albumId : String) = { def album = albumService.findAlbum(albumId) <album>…</album> } 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 71
  72. 72. Integrate with Spring MVC 1@Componentclass WsEndpointHandlerMapping extends HandlerMapping {@Autowireddef setApplicationContext(applicationContext : ApplicationContext) { this.applicationContext = applicationContext}def endpoints = …applicationContext.getBeansOfType(classOf[WsEndpoint])…override def getHandler(request : HttpServletRequest) : HandlerExecutionChain = { val endpointForRequest = endpoints.find( _.isDefinedAt(request)) endpointForRequest match { case Some(endpoint) => new HandlerExecutionChain(endpoint) case None => null } } Maps HTTP request to WSEndpoint 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 72
  73. 73. Integrate with Spring MVC 2@Componentclass WsEndpointHandlerAdapter extends HandlerAdapter { override def supports(handler : Object) = { handler.isInstanceOf[WsEndpoint] } override def handle(request : HttpServletRequest , response : HttpServletResponse , handler : Object ) : ModelAndView = { val endpoint = handler.asInstanceOf[WsEndpoint] val node = endpoint(request) response.setContentType("text/xml") response.getWriter.print(node.toString) null } Invokes WSEndpoint and generates HTTP response 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 73
  74. 74. Scala and Spring DIo  Scala and Spring DI play togethero  @Component on Scala classes workso  @Autowired fields: n  Annotation ends up on field and generated methods è fail n  Need to define and annotate setters 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 74
  75. 75. Agendao  Evolution of programming languageso  Favorite Groovy featureso  The frustration of using Groovyo  Scala: expressiveness and compile- time checkingo  The trouble with Scala 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 75
  76. 76. Really bad newso  Scala IDEs are ok and slowly improving BUT have a really really long way to go compared to Javao  Limited refactoring => painful to maintain code quality? 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 76
  77. 77. More bad news…o  Expressiveness comes from complex language featureso  Generics are better than Java but still complex BUTo  The investment in learning these features is repaid with every application you write 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 77
  78. 78. …more bad newso  Lift is not Grails (or Rails)o  A subset of the Scala community has a functional programming background => Obsessed with their Monadso  Implicit conversions make it possible to write “incomprehensible” codeo  Scala Collections != Java Collections n  BUT Implicit conversions simplify interoperability 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 78
  79. 79. Summaryo  The Java Language has stagnated and need to be replacedo  Dynamic languages are one optiono  But many benefits of those languages are due to good language designo  Scala = expressiveness + static typingo  But Grails derives much of its power from the dynamic features of Groovyo  Therefore, choose the right tool: n  Web application è Use Groovy and Grails n  Complex business logic/middleware è Consider Scala 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 79
  80. 80. Summary – Pessimistic viewo  Languages used by mainstream developers have improved substantiallyo  But are those languages that much better than the 25+ year old “ivory tower” languages: LISP, Smalltalk, ML, … ? 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 80
  81. 81. Final thoughtso  Learn some languages including Haskello  Watch the 50 in 50 presentation by Guy Steele and Dick Gabriel: http://blog.jaoo.dk/2008/11/21/art- and-code-obscure-or-beautiful-code/"Those who cannot remember the past are condemned to repeat it” http://en.wikipedia.org/wiki/George_Santayana 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 81
  82. 82. The end Twitter: @crichardson Send email: chris@chrisrichardson.net 4/3/11 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 82

×