the feel of scala - dewapurnama | just another wordpress ... · pdf file the feel of scala...

48
www.devoxx.com The Feel of Scala Bill Venners President Artima, Inc. www.artima.com

Upload: duongdan

Post on 28-Mar-2018

223 views

Category:

Documents


3 download

TRANSCRIPT

www.devoxx.com

The Feel of Scala

Bill VennersPresidentArtima, Inc.www.artima.com

www.devoxx.com

Overall Presentation Goal

Give you a feel for what Scala programming is like, by showing Scala solutions to real problems.

www.devoxx.com

Run the Artima Developer website

An old Java guy, who chose Scala for Artima's next language

Coauthored Programming in Scala

Primary developer of ScalaTest

Enough about me

3

www.devoxx.com

The verbosity of Java code addsaccidental complexity to my software.

My Problem

www.devoxx.com

Scala lets me...

use and design libraries that enableclearer, more concise code.

www.devoxx.com

Can enhance Java

But can only add; can't subtract

Scala adds to and subtracts from Java

Not source compatible with Java language

But has seamless binary compatibility with JVM

What about Java?

6

www.devoxx.com

More concise; no type annotations

Can add new methods to existing classes

Can pass objects that share no common supertype to a method, which treats them uniformly

What about JRuby, Jython, and Groovy?

7

www.devoxx.com

More concise; no type annotations

Can add new methods to existing classes

Can pass objects that share no common supertype to a method, which treats them uniformly

Dynamic

8

Staticvs.deterministic refactoring

fewer tests needed

documentation

code completion

performance, on JVM

www.devoxx.com

More concise; fewer type annotations

Can effectively add new methods to existing classes

Can pass objects that share no common supertype to a method, which treats them uniformly

Scala gives me...

9

deterministic refactoring

fewer tests needed

documentation

code completion

performance, on JVM

www.devoxx.com

import scala.io.Source

def widthOfLength(s: String) = s.length.toString.length

if (args.length > 0)

val lines = Source.fromFile(args(0)).getLines.toList

val longestLine = lines.reduceLeft( (a, b) => if (a.length > b.length) a else b ) val maxWidth = widthOfLength(longestLine)

for (line <- lines) val numSpaces = maxWidth - widthOfLength(line) val padding = " " * numSpaces print(padding + line.length +" | "+ line) else Console.err.println("Please enter filename")

www.devoxx.com

if (x == BigInteger.ZERO) BigInteger.ONEelse x.multiply(factorial(x.subtract(BigInteger.ONE)))

if (x == 0) 1 else x * factorial(x - 1) def factorial(x: BigInt): BigInt =

def factorial(x: BigInteger): BigInteger =

versus

www.devoxx.com

Every value is an object;Every operation a method call

map.containsKey('a') map containsKey 'a'

factorial(x - 1)factorial(x.-(1))

www.devoxx.com

map.should have_key('a')

Hamcrest matchers (Java)

RSpec matchers (Ruby)

assertThat(map, hasKey('a'));

In dynamic languages, open classes let you add new methods to existing classes and objects.

www.devoxx.com

Scala's implicit conversions lets you appear to add new methods to existing classes.

map should have key ('a')

ScalaTest matchers (Scala)

www.devoxx.com

map should have

map.should(have)

map should have key ('a')

map.should(have).key('a')

1 + 2 - 3

(1).+(2).-(3)

www.devoxx.com17

A wrapper class (in Java)

public class Wrapper private Object payload; public Wrapper(Object payload) this.payload = payload; public void should(HaveWord c) // ...

should(HaveWord)

Wrapper

Object

www.devoxx.com18

A conversion method (in Java)

public static Wrapper wrap(Object obj) return new Wrapper(obj);

should(HaveWord)

map.should(have) // ERROR

wrap(map).should(have)

www.devoxx.com19

An implicit conversion method (in Scala)

implicit def wrap(o: Any) = new Wrapper(o)

class Wrapper(payload: Any) def should(HaveWord c) // ...

www.devoxx.com

map should have key ('a')

map.should(have).key('a')

wrap(map).should(have).key('a')

1

2

3

www.devoxx.com21

ScalaTest matchers

map should have key ('a')

collection should contain element (1.0)

collection should have size (17)

string must equal ("done")

array must have length (9)

www.devoxx.com

Scala:

assert(result == 17)

JUnit:

assertEquals(17, result);

www.devoxx.com

Scala:

assert(result == 17)

JUnit:

assertEquals(17, result);

ScalaTest:

assert(result === 17)

www.devoxx.com26

Which is actual? Which is expected?

assertEquals(animalShelter.getCat(), myKitty);

www.devoxx.com27

A trick question

JUnit:

assertEquals(expected, actual);

TestNG:

assertEquals(actual, expected);

www.devoxx.com28

A basic control abstraction in Scala

JUnit:

assertEquals(expected, actual);

TestNG:

assertEquals(expected, actual);

ScalaTest:

expect(myKitty) animalShelter.getCat()

www.devoxx.com

DEMO

Curly braces and parens

Currying

By-name parameters

Expect in action

www.devoxx.com30

Testing for thrown exceptions (JUnit)

JUnit 3:String s = "hi”;try s.charAt(-1); fail();catch (StringIndexOutOfBoundsException e) // Expected, so continue

JUnit 4:@Test(expected=StringIndexOutOfBoundsException.class)public void testPassingANegativeToCharAt() s.charAt(-1);

www.devoxx.com31

Testing for thrown exceptions (ScalaTest)

intercept[StringIndexOutOfBoundsException] s.charAt(-1)

www.devoxx.com

DEMO

Intercept in action

Test methods with Suite and TestNGSuite

Test functions with FunSuite

BDD with Spec

www.devoxx.com33

The need to test private methods

expect("'c'") FailureMessages.decorateToStringValue('c')

www.devoxx.com34

Symbol literals in Scala

'decorateToStringValue

"'decorateToStringValue"

Symbol

www.devoxx.com35

Testing with invokePrivate (ScalaTest)

val decorateToStringValue = PrivateMethod[String]('decorateToStringValue)

expect("\"Howdy!\"") FailureMessages invokePrivate decorateToStringValue("Howdy!")expect("'c'") FailureMessages invokePrivate decorateToStringValue('c')expect("1") FailureMessages invokePrivate decorateToStringValue(1)expect("true") FailureMessages invokePrivate decorateToStringValue(true)

www.devoxx.com37

Type checking in matchers

Map("hi" -> 1) should have key ("hi")

Map(1 -> "hi") should have key ("hi")

MatcherSpec.scala:1089: error: type mismatch; found : java.lang.String("hi") required: Int Map(1 -> "hi") should have key ("hi") ^

www.devoxx.com38

What should I require about the type of object?

object should have length (7)

www.devoxx.com39

object should have length (7)

Duck typing lets you pass objects that have the same structure, but no common supertypes.

www.devoxx.com40

object should have length (7)

Duck typing lets you pass objects that have the same structure, but no common supertypes.

public final int length;

public int length();

public int getLength();

Array:

String:

Document:

www.devoxx.com41

View bounds and the can-be-treated-as relationship

LengthWrapper« trait »

TextArrayLengthWrapper StringLengthWrapper DocumentLengthWrapper

Array String Document

def length: Int

can be treated ascan be treated ascan be treated as

is a is a is a

www.devoxx.com42

string should have length (7)

Object can be any type that can be treated as a LengthWrapper

array should have length (7)

document should have length (7)

www.devoxx.com

length() - Method in class java.io.FileReturns the length of the file denoted by this abstract pathname.length - Variable in exception java.io.OptionalDataExceptionThe number of bytes of primitive data available to be read in the current buffer.length() - Method in class java.io.RandomAccessFileReturns the length of this file.length() - Method in interface java.lang.CharSequenceReturns the length of this character sequence.length() - Method in class java.lang.StringReturns the length of this string.length() - Method in class java.lang.StringBufferlength() - Method in class java.nio.CharBufferReturns the length of this character buffer.length() - Method in class java.nio.charset.CoderResultReturns the length of the erroneous input described by this object (optional operation).length() - Method in interface java.sql.BlobReturns the number of bytes in the BLOB value designated by this Blob object.length() - Method in interface java.sql.ClobRetrieves the number of characters in the CLOB value designated by this Clob object.length() - Method in class java.util.BitSeReturns the "logical size" of this BitSet: the index of the highest set bit in the BitSetplus one.length() - Method in class java.util.concurrent.atomic.AtomicIntegerArrayReturns the length of the array.length() - Method in class java.util.concurrent.atomic.AtomicLongArrayReturns the length of the array.length() - Method in class java.util.concurrent.atomic.AtomicReferenceArrayReturns the length of the array.length() - Method in class javax.imageio.stream.FileCacheImageOutputStreamlength() - Method in class javax.swing.text.GapContentReturns the length of the content.length() - Method in class javax.swing.text.StringContentReturns the length of the content.length() - Method in class org.omg.CORBA.TypeCodeReturns the number of elements in the type described by this TypeCode object.length() - Method in class javax.imageio.stream.FileImageInputStreamReturns the length of the underlying file, or -1 if it is unknown.length() - Method in class javax.imageio.stream.FileImageOutputStreamlength() - Method in interface javax.imageio.stream.ImageInputStreamReturns the total length of the stream, if known.length() - Method in class javax.imageio.stream.ImageInputStreamImplReturns -1L to indicate that the stream has unknown length.length() - Method in class javax.imageio.stream.MemoryCacheImageOutputStreamlength - Variable in class javax.sound.midi.MidiMessageThe number of bytes in the MIDI message, including the status byte and any data bytes.

length() - Method in class javax.sql.rowset.serial.SerialBlobRetrieves the number of bytes in this SerialBlob object's array of bytes.length() - Method in class javax.sql.rowset.serial.SerialClobRetrieves the number of characters in this SerialClob object's array of characters.length() - Method in interface javax.swing.text.AbstractDocument.ContentCurrent length of the sequence of character content.length() - Method in class javax.swing.text.GapContentReturns the length of the content.length() - Method in class javax.swing.text.StringContentReturns the length of the content.length() - Method in class org.omg.CORBA.TypeCodeReturns the number of elements in the type described by this TypeCode object.getLength() - Method in class java.net.DatagramPacketReturns the length of the data to be sent or the length of the data received.getLength() - Method in class java.text.BidiReturn the length of text in the line.getLength() - Method in class javax.imageio.metadata.IIOMetadataNodegetLength() - Method in class javax.imageio.stream.IIOByteBufferReturns the length of the data of interest within the byte array returned by getData.getLength() - Method in class javax.sound.midi.MidiMessageObtains the total length of the MIDI message in bytes.getLength() - Method in interface javax.swing.event.DocumentEventReturns the length of the change.getLength() - Method in class javax.swing.text.AbstractDocument.DefaultDocumentEventReturns the length of the change.getLength() - Method in class javax.swing.text.AbstractDocumentReturns the length of the data.getLength() - Method in class javax.swing.text.DefaultStyledDocument.ElementSpecGets the length.getLength() - Method in interface javax.swing.text.DocumentReturns number of characters of content currently in the document.getLength() - Method in interface org.w3c.dom.CharacterDataThe number of 16-bit units that are available through data and the substringData method below.getLength() - Method in interface org.w3c.dom.DOMImplementationListThe number of DOMImplementations in the list.getLength() - Method in interface org.w3c.dom.DOMStringListThe number of DOMStrings in the list.getLength() - Method in interface org.w3c.dom.NamedNodeMapThe number of nodes in this map.getLength() - Method in interface org.w3c.dom.NameListThe number of pairs (name and namespaceURI) in the list.getLength() - Method in interface org.w3c.dom.NodeListThe number of nodes in the list.getLength() - Method in interface org.xml.sax.AttributesReturn the number of attributes in the list.getLength() - Method in class org.xml.sax.helpers.AttributeListImpl

www.devoxx.com44

Structural types in Scala

LengthWrapper« trait »

TextLengthFieldWrapper LengthMethodWrapper GetLengthMethodWrapper

def getLength(): Int

def length: Int

can be treated ascan be treated ascan be treated as

def length(): Int val length: Int

is a is a is a

www.devoxx.com45

string should have length (7)array should have length (7)document should have length (7)file should have length (7)blob should have length (7)atomicIntegerArray should have length (7)gapContent should have length (7)midiMessage should have length (7)datagramPacket should have length (7)iioByteBuffer should have length (7)documentEvent should have length (7)characterData should have length (7)nodeList should have length (7)attributes should have length (7)yourNewClass should have length (7)

Object can be any type that can be treated as a LengthWrapper

www.devoxx.com

DEMO

testing length

optional type systems

www.devoxx.com

More concise; fewer type annotations

Can effectively add new methods to existing classes

Can pass objects that share no common supertype to a method, which treats them uniformly

47

deterministic refactoring

fewer tests needed

documentation

code completion

performance, on JVM

Summary: Scala decreases the cost and increases the benefit of static typing.

www.devoxx.com

Programming in Scala is available in the Devoxx bookstore.