communityoneeast 09 - dynamic languages: the next big thing for the jvm or an evolutionary dead end?
Post on 22-Oct-2014
3.464 Views
Preview:
DESCRIPTION
TRANSCRIPT
Dynamic Languages: the Dynamic Languages: the next big thing for the JVM or an evolutionary dead end?an evolutionary dead end?
Chris RichardsonAuthor of POJOs in Action
Founder of Cloud Tools and Cloud FoundryyChris Richardson Consulting, Inc
www.chrisrichardson.netwww.chrisrichardson.net
Overall presentation goalp g
Dynamic languages have many benefits But
Static languages which have the Static languages, which have the safety net of compile-time
checking can be just as expressive checking, can be just as expressive
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 24/8/2009
About ChrisAbout Chris• Grew up in England and live in Oakland, CA• Over 20+ years of software development
experience including 12 years of Javaexperience including 12 years of Java• Author of POJOs in Action• Speaker at JavaOne, SpringOne, NFJS,
JavaPolis, Spring Experience, etc.• Chair of the eBIG Java SIG in Oakland • Chair of the eBIG Java SIG in Oakland
(www.ebig.org)• Run the Groovy/Grails meetup
(http://java.meetup.com/161)• Run a consulting and training company that u a co su t g a d t a g co pa y t at
helps organizations reduce development costs and increase effectiveness
• Founder of Cloud Tools, an open-source project for deploying Java applications on Amazon EC2: http://code google com/p/cloudtoolshttp://code.google.com/p/cloudtools
• Founder of a startup that provides outsourced, automated, and Java-centric datacenter management on the cloud: www.cloudfoundry.comy
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 34/8/2009
Agendag
The fall and rise of dynamic languagesFavorite Groovy featuresThe frustration of using GroovyScala: expressiveness and compile-p ptime checking
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 44/8/2009
Dynamic vs. static languages
Dynamic (run-time) Static (compile-time)Dynamic (run-time)Types associated with values rather than
Static (compile-time)Types associated with variables
variablesAbility to define new program elements at
Compile-time checking of language elements and types program elements at
runtimeNot a new idea:
elements and types Not a new idea either:
Lisp – 1958!SmallTalk - 1980
Algol 60
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 5
anObject.someMethod(someArgs)
4/8/2009
LISP/CLOS – an early (late 1980s) dynamic languagey g g
(defclass Account ()((account-id :accessor account-id :initarg :account-id)(balance :accessor account-balance :initarg :balance))
)Develop by adding and changing program )
(defmethod debit ((Account account) amount) (decf (account-balance account) amount))
(defmethod credit ((Account account) amount)(incf (account balance account) amount))
g g p gelements in a running VM
(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)CL-USER 6 > (describe a)
#<ACCOUNT 200C05AF> is an ACCOUNTACCOUNT-ID "abc123"BALANCE 10.0
CL USER 7 > (debit a 5)CL-USER 7 > (debit a 5)5.0
CL-USER 8 > (describe a)
#<ACCOUNT 200C05AF> is an ACCOUNTACCOUNT ID " b 123"
4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved. 6
ACCOUNT-ID "abc123"BALANCE 5.0
… a very dynamic languagey y g g
(defclass Account ()( ()((account-id :accessor account-id :initarg :account-id)(balance :accessor account-balance :initarg :balance)(description :accessor account-description :initarg :description))
)
Existing instances are updated when the class is redefined
CL-USER 9 > (describe a)
#<ACCOUNT 2168DCBF> is an ACCOUNTACCOUNT-ID "abc123"BALANCE 10.0DESCRIPTION #<unbound slot>DESCRIPTION #<unbound slot>
CL-USER 10 > (setf (account-description a) "checking account")"checking account"
CL-USER 11 > (describe a)
#<ACCOUNT 2168DCBF> is an ACCOUNTACCOUNT-ID "abc123"BALANCE 10.0DESCRIPTION "checking account"
4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved. 7
Ruby on Rails woke up Javay p
Ruby on Rails:Significantly more productiveSimplicity of Convention over C fi tiConfiguration
Motivated the Java community to iimproveReopened the debate about
i lprogramming languages
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 84/8/2009
Dynamic languages on the JVMy g gJRuby
http://jruby.codehaus.orgp //j y gRuby on the JVM
Jythonhttp://www.jython.org/Projectp // jy g/ jPython on the JVM
Clojurehttp://clojure.org/p j gFunctional programming languageSoftware Transactional Memory…
Groovyhttp://groovy.codehaus.org/Java-compatible, dynamic language
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 94/8/2009
Agendag
The fall and rise of dynamic languagesFavorite Groovy featuresThe frustration of using GroovyScala: expressiveness and compile-p ptime checking
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 124/8/2009
About Groovyy
Object-oriented, dynamic languageJava compatibleRuns on the JVMMade popular by the Grails framework:
Rails-like productivityUsing robust Java frameworks including g gSpring and Hibernate
Slide 13Copyright (c) 2009 Chris Richardson. All rights reserved.4/8/2009
Things I like: Java compatibleg p
import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;
class EC2RequestExecutor {
Log logger = LogFactory.getLog(getClass())
Java-like syntaxUse Java libraries
public String calculateRFC2104HMAC(String data, String key) {try {SecretKeySpec signingKey = new SecretKeySpec(key.getBytes("UTF8"),
HMAC_SHA1_ALGORITHM)M M tI t (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)
}}
Slide 144/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.
Groovy is concise and expressivey p
def configureAsMaster() {writeFile fileName: "/etc/my.cnf", templateName: "/templates/master.my.cnf"
restartService "mysqld"
exec command: "mysql -u root", templateName: "/templates/createSchema.sql", No parenstemplateName: /templates/createSchema.sql , templateArgs: [schemaSpec: schemaSpec]
executeSchemaScripts()}
No parensKeyword parameters
class TomcatServer { tomcatServer.contextsN t ()
{def getContexts() {
webApps.context}
}
No get…()
Slide 154/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.
Literals for lists and mapsp
def myList = [“a”, “b”, “c”]
def params = ['Action': 'RunInstances','MinCount': n.toString(), 'MaxCount': n.toString(),' ImageId': awsProperties."imageId.${instanceType}", 'KeyName': awsProperties.keyName,' InstanceType': instanceType] + extraParams
def response = requestor executeRequest(params)def response = requestor.executeRequest(params)
Slide 164/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.
GStringsg
def schemaScript = """DROP SCHEMA IF EXISTS ${schemaSpec.name};CREATE SCHEMA ${schemaSpec.name};
"""
Slide 174/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.
Closures
public EC2Server findInstance(String instanceId) {d f fi d {i t Id it i t Id}def server = servers.find {instanceId == it.instanceId}if (server)return server
else throw new RuntimeException( )else throw new RuntimeException(….)}
Simplified collection processing
Slide 184/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.
Closures – new control structurespublic class Ssh {
public Object withTunnel(String publicDnsName, int localPort, int remotePort, Closure closure) {p j ( g p , , , ) {SshConnection sshConnection = makeSshConnection(publicDnsName);try {
sshConnection.connect()…return closure.call()
} fi ll {} 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
}
}
Slide 194/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.
}
An interactive shell
Great for experimentation and learning
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 204/8/2009
Simple reusable codep
interface Quackable {void quack();
Java: l it f
q ();}
class QuackableContainer<T extends Quackable>
complexity of generics
void add(T element) {element.quack();…
}}…}
class QuackableContainer { Groovy: just assume that c ass Quac ab eCo ta e {
void add(T element) {element.quack()…
Groovy: just assume that there is a quack() method
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 21
}
4/8/2009
Groovy metaclassesy
public class StringMetaclassExampleTest extends GroovyTestCase {
void testAddMethodToString() {String.metaClass.doubleString = { -> delegate + delegate }String.metaClass.static.makePowerString = { String s, int n ->
def result = sn.times { result = result.doubleString() }result
}assertEquals "CommunityOne EastCommunityOne East",
"CommunityOne East" doubleString()CommunityOne East .doubleString()assertEquals "NewYorkNewYorkNewYorkNewYork",
String.makePowerString("NewYork", 2)}
}
Runtime definition of program elements
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 224/8/2009
p g
Method Missingg
public class ClassWithMissingMethods {
Object methodMissing(String name, args) {Closure method = makeMethodImplementation(name)if (method) {
method(args)method(args)} else {
throw new MissingMethodException(name, getClass(), args)}
}
def makeMethodImplementation(String name) {….
}
}
def foo = new ClassWithMissingMethods()
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 234/8/2009
g ()foo.nonExistentMethod()
XML and GPath expressionsp<RunInstancesResponse>…<instancesSet>
<item><instanceId>i-4ef21327</instanceId><imageId>ami-3795705e</imageId><instanceState>
<code>0</code>def client = new HttpClient()…def responseStream =
getMethod getResponseBodyAsStream()
<code>0</code><name>pending</name>
</instanceState><dnsName/>
…getMethod.getResponseBodyAsStream()def parser = new XmlParser(false, false)def response = parser.parseText(responseStream)
def newServers = response instancesSet.item collect {
</RunInstancesResponse>
def newServers response.instancesSet.item.collect {new EC2Server(this, awsProperties, ssh,
it.instanceId.text(), it.instanceState.name.text())
}
Slide 24Copyright (c) 2009 Chris Richardson. All rights reserved.4/8/2009
}
Buildersdef report(String path, hosts, cpuCount, threadCount) {
def builder = new groovy.xml.MarkupBuilder(new OutputStreamWriter(new FileOutputStream(path))) builder.performanceReport {builder.performanceReport {cpus cpuCountthreads threadCounthosts.entrySet().each { hostEntry ->host {name hostEntry.keycpuUtil hostEntry value getAverageBusy()
<performanceReport><cpus>1</cpus>cpuUtil hostEntry.value.getAverageBusy()
}}requests {
timings.entrySet().sort{ a, b-> a.key <=> b.key}.each{ pair ->request {name pair key
<cpus>1</cpus><threads>10</threads><host>
<name>database</name><cpuUtil>3.27</cpuUtil>
</host>name pair.keyart pair.value.average()errors pair.value.errorPercentage()}
}}d f d ti V l ((fl t)( dTi t tTi ))/1000 0
</host><host>
<name>tomcat0</name><cpuUtil>94.32</cpuUtil>
</host>
def durationValue = ((float)(endTime - startTime))/1000.0duration durationValuedef tpsValue = transactionCount/ durationValuetps tpsValueart averageResponseTime()
}
…<duration>557.943</duration>
<tps>10.753786677133686</tps><art>916.6578333333</art>
</performanceReport>
}
Slide 254/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.
Grails/GORM persistence methods/ p
class Customer {String name
Implemented using metaclasses and method g
}
C t C t ("J h D ")
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”)
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 26
def customers = Customer.findAllByName( Fred )
4/8/2009
Agendag
The fall and rise of dynamic languagesFavorite Groovy featuresThe frustration of using GroovyScala: expressiveness and compile-p ptime checking
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 274/8/2009
Getting Groovy code to work can be frustratingg
Dynamic language = less information for IDE:
Limited compile-time checkingLimited refactoringsLimited completion
Slide 284/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.
Groovy fans say "write unit tests“ BUT…
Groovy
versus
When you have typos
Java
Slide 294/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.
Unit tests don't always catch errorsy
void testPollStatus_discoveringNewServer() {mockEC2RequestExecutor.demand.executeRequest {params ->….
}def mockEC2Server = new MockFor(EC2Server.class)….mockEC2Server.use {mockEC2Server.use {
mockEC2RequestExecutor.use {ec2 = new EC2(awsProperties)ec2.pollStatus()assertEquals 1, ec2.servers.size()
}
public class EC2 {
}}
}
public pollStatus() {def params = ['Action':
'DescribeInstances']def p = requestor executeRequest(params)
class EC2RequestExecutor {
public Node executeEc2Request(Map parameters) {
requestor.executeRequest(params)…
}…} Method signature changes are
ft i d…}
often missed
Slide 304/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.
The trouble with duck typingyp g
Interface between components not defined in a single placeIt is scattered throughout callerDifficult to understandDifficult to changeg
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 314/8/2009
The outcome: fear of changeg
Did my tests Did my tests catch all the obvious errors?the obvious errors?
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 324/8/2009
Writing Java becomes frustratingg g
Importing the obvious, e.g. java.utilTedious collection manipulationPainful XML processingp gRepetitive type declarations
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 334/8/2009
Agendag
The fall and rise of dynamic languagesFavorite Groovy featuresThe frustration of using GroovyScala: expressiveness and pcompile-time checking
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 344/8/2009
Distilling a languageg g g
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 354/8/2009
Scala – a modern (2003) static languageg g
Object-oriented Pure object-oriented languageAll values are objectsClass-basedTraits support "multiple inheritance"
FunctionalFunctionalFunctions are valuesHigher-order functionsCurrying
Statically typedExpressiveType inference
E t ibl t t d i ifi lExtensible to support domain specific languagesMethods as infix and postfix operatorsAutomatic closure construction
Fully interoperable with JavaFully interoperable with Java
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 364/8/2009
Simple examplep p
object StringFunctions {
def reverseSentence(sentence : String) = sentence.split(" ").reverse.mkString(" ")
}
import org.junit._import Assert._
@Testclass StringFunctionsTest {
@Testdef testReverseSentence() = {def testReverseSentence() {val input = "Hello New York"val expected = "York New Hello"assertEquals(expected, StringFunctions.reverseSentence(input))
}}
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 37
}
4/8/2009
Collection literals examplep@Testclass ScalaCollectionExamplesTest {
@Testdef listExample() = {val myList = List(1, 2, 3)assertEquals(3, myList.length)assertEquals(List(0 1 2 3) 0::myList) assertEquals(List(0, 1, 2, 3), 0::myList) assertEquals(List(2, 3), myList.tail) assertEquals(1, myList.head)
}
@Testdef testMapExampleList() : Unit = {val myMap = Map( "x" -> 1, "y" -> 2, "z" -> 3) assertEquals(1, myMap("x"))
}}}
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 384/8/2009
Closure examplep
@Test@Testclass ScalaCollectionExamplesTest {
@Testdef testMapList() = {p () {val myList = List(1, 2, 3) assertEquals(List(2,4,6), myList.map ( x => x * 2))assertEquals(List(2,4,6), myList.map ( _ * 2))
}
@Testdef testFilterList() = {val myList = List(1, 2, 3) assertEquals(List(1, 3), myList.filter( _ % 2 == 1));
}
}
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 394/8/2009
Pattern matchinggcase 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, _, _, _) => truecase Organization(_, Industry.Banking, _, assets, liabilities)
if liabilities < assets * 1.5 => true O i ti ( I d t B ki ) f lcase Organization(_, Industry.Banking, _, _, _) => false
case Organization(_, _, _, assets, liabilities) if assets > liabilities => truecase _ => false
}
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 40
}
4/8/2009
XML generationg@Testclass ScalaXmlExampleTest {
@Testdef 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><requester>{loanRequestor.name}</requester><industry>{loanRequestor.industry}</industry><revenue>{loanRequestor.revenue}</revenue><assets>{loanRequestor.assets}</assets><liabilities>{loanRequestor.liabilities}</liabilities>
</l R t></loanRequest>
val docAsString : String = doc.toString()println(docAsString)
}
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 41
}
4/8/2009
XML parsingp gclass ScalaXmlExampleTest {
@Test@Testdef xmlProcessing() {val doc = xml.XML.loadString(docAsString)assertEquals ("Community Bank, Inc", (doc \ "requester").text)
node match { case <loanRequest>{children @ _* }</loanRequest> => for (x <- children if !x.isInstanceOf[scala.xml.Text]) {processChildren(x)
}}}
}
def processChildren(node : scala.xml.Node ) = {d t h { node match {
case <time>{value}</time> => println(value.text) case <requester>{value}</requester> => println(value.text) …
}
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 42
}}
4/8/2009
DSL Examplepclass OrganizationDslTest {
val o : Organization = (Organization called "Bernie Madoff & Associates" called Bernie Madoff & Associates in Industry.BankingwithRevenuesOf (10 million) withAssetsOf (10 billion) withLiabilitiesOf (30 billion))
} object Organization {def called(name : String) = new OrganizationBuilder(name)
class OrganizationBuilder(name : String) {g ( g) {var industry : Industry.Value = nulldef in(industry : Industry.Value) = { this.industry = industry; this }def withRevenuesOf(…) = … …def make()= new Organization(name industry revenue assets liabilities)def make()= new Organization(name, industry, revenue, assets, liabilities)
}
implicit def organizationBuilderToOrganization(builder : OrganizationBuilder) = builder.make
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 43
}
4/8/2009
Constructing object hierarchiesg j
object ExampleSwingApp extends SimpleGUIApplication {
def top = new MainFrame {title = "Example Swing App"
val button = new Button {text = "press"text press
}
contents = button
t 0 var count = 0 listenTo(button)reactions += {case ButtonClicked(b) =>count = count + 1Console.println(count);b.text = "press: " + count
}}
4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 44
}
Traits
Consist of membersmethodsfieldstypes
The members can be abstractMultiple traits can be mixed into a class
Alternative to multiple inheritanceClass must define abstract members
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 464/8/2009
Dependency injection in Scalap y j
Dependency injection = component definition and compositionTraditional approach
Metadata: XML, annotationsFramework: Spring, Guice, EJB3
Scala: use traits and other language features
4/8/2009 Slide 47Copyright (c) 2009 Chris Richardson. All rights reserved.
Dependency injection –Spring/Java examplep g/ p
@Component("organizationRepository")class OrganizationRepositoryImpl extends OrganizationRepository {
Names a component and class OrganizationRepositoryImpl extends OrganizationRepository {
…}
pspecifies it's implementation
@Component("loanProcessingService")class LoanProcessingServiceImpl extends LoanProcessingService{
@Autowiredprivate OrganizationRepository organizationRepository;
void processLoan( ) {
Expresses a dependency
void processLoan(….) {}
…}
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 484/8/2009
Dependency injection - repositoryp y j p y
trait OrganizationRepositoryComponent {
val organizationRepository : OrganizationRepository
Names a component val organizationRepository : OrganizationRepository
trait OrganizationRepository {def findByName(name : String) : Organization
}
pand defines it's interface
}
trait OrganizationRepositoryComponentImpl extends OrganizationRepositoryComponent {
Specifies the implementation
trait OrganizationRepositoryComponentImpl extends OrganizationRepositoryComponent {
val organizationRepository = new OrganizationRepositoryImpl()
class OrganizationRepositoryImpl extends OrganizationRepository {d f fi dB N ( S i ) {def findByName(name : String) = {… Access the database here…
}}
}
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 49
}
4/8/2009
Dependency injection - servicep y jtrait LoanProcessingServiceComponent { val loanProcessingService : LoanProcessingServicetrait LoanProcessingService {
Expresses a dependencytrait LoanProcessingService {
def processLoan(organizationName : String )}
}trait LoanProcessingServiceComponentImpl extends LoanProcessingServiceComponent
dependency
{ this : OrganizationRepositoryComponent =>
val loanProcessingService = new LoanProcessingServiceImpl()val policy = new LoanApprovalPolicy()
class LoanProcessingServiceImpl extends LoanProcessingService {
def processLoan(organizationName : String ) = {val organization = organizationRepository.findByName(organizationName)if ( li i L A d( i i )) {if (policy.isLoanApproved(organization)) {// process the loan
} else {throw new LoanRequestRejectedException()
….
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 50
….}
4/8/2009
Dependency injection - applicationp y j pp
object LoanProcessingApplicationextends LoanProcessingServiceComponentImplwith OrganizationRepositoryComponentImpl {
}
LoanProcessingApplication.loanProcessingService.processLoan("Green Co")
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 514/8/2009
Dependency injection – testingp y j g
class LoanProcessingApplicationTest {
trait OrganizationRepositoryComponentStub extends OrganizationRepositoryComponent {val organizationRepository = new OrganizationRepositoryStubImpl() class OrganizationRepositoryStubImpl extends OrganizationRepository {
def findByName(name : String) = {name match {name match {case "Bernie Madoff & Associates" => new Organization(…)…
}}
}}}
object LoanProcessingApplicationWithStub extends LoanProcessingServiceComponentImpl with OrganizationRepositoryComponentStub {g p p g p y p {
}
@Testdef testProcessLoanOk() = {
LoanProcessingApplicationWithStub loanProcessingService processLoan("Green Co")
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 52
LoanProcessingApplicationWithStub.loanProcessingService.processLoan( Green Co )}
4/8/2009
The bad news about Scala
IDEs are rough around the edgesExpressiveness comes from complex language featuresGenerics are better than Java but still complex
BUTThe investment in learning these The investment in learning these features is repaid with every application you writepp y
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 534/8/2009
Summaryy
Today’s interest in dynamic languages is natural reaction to Java
Not evolving sufficientlyShowing its age
But many benefits of those languages are due to good language designScala = expressiveness + static typing
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 544/8/2009
Final thoughtsg
Download or contribute to Cloud Tools today :y
www.cloudtools.org
Checkout Cloud Foundry:
www cloudfoundry comwww.cloudfoundry.com
Buy my book ☺
Send email:
chris@chrisrichardson.net
Visit my website:
www.chrisrichardson.net
Talk to me about consulting and training
Phone: 510 904 9832
Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 554/8/2009
top related