Age is not an int

32
Name Chris Marshall @oxbow_lakes GSA Capital Partners LLP Jan 2015 Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority. Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

Transcript of Age is not an int

Name

Chris Marshall @oxbow_lakes

GSA Capital Partners LLPJan 2015

Private & Confidential. Not for distribution.

GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

Age is not an Int

Mathematics Degree

Working in financial software since 1999

• Smalltalk for ~6 months

• Java thereafter

• Scala since Dec 2008

JP Morgan for 6 years

• ~200,000 employees

GSA Capital for 8+ years

• Quant hedge fund

• ~130 employees

Backgroundwho am i

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261 3

Low-latency links & feeds

• Up to 2,000,000 trades /day

• 108 market events / day

Historic / Current Market Data

• Listing changes (e.g. SUNW.O becomes JAVA.O becomes ORCL.O)

• News Events

Backtesting / Execution Framework

Everything Else

• This is where CORE come in

• What are our positions? What is our P&L? What is our VaR?

• Are our trades reconciled?

• Reporting (brokers, regulators, administrators)

GSAWhat do we do? Roughly half the company are technologists

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261 4

GSA are not a software company

5

This talk

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

<dibblego> this question generalises to "use types"

<dibblego> how do I know my Int is a valid age?

<dibblego> well how indeed? how did you even come to that conclusion?

<dibblego> well, because age returns Int

<dibblego> stop doing that!

<dibblego> Age returns a value between 0 and MAX_AGE

<dibblego> oh, then you want a type for that

<dibblego> but what about my Int!

<dibblego> there was never an Int

<dibblego> but I want to use it as an Int!

<dibblego> so do that

<dibblego> but it is clumsy and annoying to convert all the time!

<dibblego> so use libraries

<dibblego> which library?

<dibblego> well, in this case, lenses

6

#scalaz IRC channel

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

Want to talk about the use of types in the programs we write

For those of us who work in statically-typed languages

Types

which we write ourselves

provided by the language itself

That the structure of our entire program can be constructed as a type

7

This talk

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

public interface Comparable<T> {

public int compareTo(T o);

}

Representing a 3-valued type with a 232 valued one

8

In java.lang: not a good start

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

/**

* Returns the percentage tracking error between

* this portfolio and the reference portfolio

*/

public double getTrackingError(String ref)

/**

* Returns the price that this trade was executed at

*/

public BigDecimal getPrice()

9

So you go away and write this...

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

Originally devised as a way of making code which was wrong look wrong

http://www.joelonsoftware.com/articles/Wrong.html

That is: “if you see xl = cb, well, blow the Bad Code Whistle, that is obviously wrong code, because even

though xl and cb are both integers, it’s completely crazy to set a horizontal offset in pixels to a count of

bytes.”

Why not make code which was wrong NOT EVEN COMPILE?

WHY NOT USE TYPES?

10

Hungarian notation

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

class LimitOrder(stock: String, price: Double, quantity: Int)

val cf = Double.compare(o1.price, o2.quantity) //OH NOES!

class LimitOrder(stock: Stock, price: Price, quantity: Quantity)

11

Stringly typed

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

case class Percentage(units: BigDecimal)

/**

* Returns the percentage tracking error between this

* portfolio and the reference portfolio

*/

public Percentage getTrackingError(Portfolio ref)

12

So: write some types

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

case class Money(currency: Currency, amount: BigDecimal)

/**

* Returns the price that this trade was executed at

*/

public Money getPrice()

13

...and some more

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

Java has failed us

This is not meant to be a rant about Java

The same is true of plenty of languages out there

4 different type systems

Primitive types

Reference types

Exception types

Annotation types

Creating classes is expensive and painful

Creating TYPES is expensive and painful

14

Java

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

public final class Money {

private final Currency currency;private final BigDecimal amount;

private Money(Currency currency, BigDecimal monetaryAmount) {currency_ = currency;amount = monetaryAmount;

}

public boolean equals(Object o) {if (this == o) {

return true;}if (o == null || getClass() != o.getClass()) {

return false;}

final Money money = (Money) o;

if (!currency.equals(money.currency)) {return false;

}if (!amount.equals(money.amount)) {

return false;}

return true;}

public int hashCode() {int result;result = currency.hashCode();result = 29 * result + amount.hashCode();return result;

}

}

15

Compare

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

case class Money (

currency: Currency,

amount: BigDecimal

)

A modern IDE takes away the task of writing all those lines of code!

I counter-counter-thrust

It’s unreadable

It’s brittle (when you modify the class, you need to remember to change the equals/hashCode)

If it’s a public class, you need to go & create a file for it

It’s a rubbish counter-argument

16

Counter-arguments

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

public class Price {

private final Money value

public Price(Money value) {

this.value = value;

}

public boolean equals(Object o) {

...

I lost the will to live at this point

case class Price(val value: Money) extends AnyVal

sealed trait Price

Money @@ Price

17

A type wrapping a single value!

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

type SessionStarts = Instant

type SessionEnds = Instant

case class MultipleSessions(sessions: SortedMap[SessionStarts, SessionEnds] {

def afterFirstOpen(i: Instant)

= if (sessions.isEmpty) false else i >= sessions(sessions.firstKey)

}

case class SessionStarts(val i: Instant) extends AnyVal

case class SessionEnds(val i: Instant) extends AnyVal

case class MultipleSessions(sessions: SortedMap[SessionStarts, SessionEnds] {

def afterFirstOpen(i: Instant)

= if (sessions.isEmpty) false else SessionStarts(i) >= sessions(sessions.firstKey)

//DOES NOT COMPILE

= if (sessions.isEmpty) false else SessionStarts(i) >= sessions.firstKey

\o/ \o/ \o/

}

18

Fails to follow own advice

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

Java 8 has added Optional<T> to indicate the possible absence of a value

Haskell Maybe

Scala Option[T]

Except they have totally hobbled it as a type

It is not serializable – you cannot use it in your domain model

It does not have

Optional<T> orElse(Optional<T> that)

19

Nullability

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

Scalaz has a disjunction type

def function(in: Input): Exception \/ Output

20

Exceptions

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

The lack of basic types: Pair<A, B>

This means that you don’t see methods in Java interfaces like this:

interface Collection<T> {

Pair<Collection<T>, Collection<T>> partition(Predicate<? super T> p)

...

}

• ...or you see them represented terribly

public class BigDecimal {

public BigDecimal[] divideAndRemainder(BigDecimal d)

...

}

21

Hobbled APIs

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

Can we construct our whole program as a type?

What does our program do?

It handles errors

It reads from some configuration

It writes to some log

It manages state transitions

It produces a result

It performs side-effects

ReaderWriterStateT and EitherT

22

Where are we going next?

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

type R = MyProps; type W = Unit; type S = MyState; type E = MyError

type RWST_[A] = RWST[IO, R, W, S, A]

type Program[A] = EitherT[RWST_, E, A]

def pure[A](a: => A): Program[A]

= EitherT.right(RWST[IO, R, W, S, A]((r, s) => (s, (), a)))

def asks[A](f: R => A): Program[A]

= EitherT.right(RWST[IO, R, W, S, A]((r, s) => (s, (), f(r))))

def log(msg: => String): Program[Unit]

= EitherT.right(RWST[IO, R, W, S, Unit](

(r, s) => (s, println(msg), ())))

23

Monad transformer stacks

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

for {

txnsGsa <- queryGsaTransactions(global.date).map(_.values.toStream)

rates <- fxRates(global.date)

results <- global.configs.toStream traverseU { implicit config =>

for {

txnsPB <- queryAggregatePBDropCopies

gsaAgg = aggregateGsaTransactions(txnsGsa)

gsaTotal = gsaAgg.aggregate

alerts <- thresholdBreaches(txnsPB, gsaTotal)

} yield (alerts, gsaTotal - txnsPB.total)

}

} yield results

24

Non Farm Payrolls

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

Immutability

we have no mutation anywhere

Referential transparency

Easy to reason about our functions and re-use them

We can see at a glance what is going on

is there IO happening in order to get hold of this value?

Could an error occur?

Surprisingly readable

Please don’t attempt to read it though!

This talk is on SlideShare if you want to look in detail later

25

Example

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

26Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

lazy val program =for {_ <- fromTryCatch(ProductUniverse.setUniverseProvider(new CoreUniverseProvider))_ <- log(s"About to run the program with: [${args mkString " "}]")dd <- date_ <- log(s"Running for carry date [$dd]")ps <- positions(dd)_ <- log(f"Found ${ps.size}%,d positions in DI1 futures")cc <- //Only try and get marks and D1 if there *are* positions

ps.nonEmpty ?? (for {ms <- marks(dd)_ <- log(f"Found ${ms.size}%,d marks on DI1 futures")d1 <- d1Rate(dd)_ <- log(s"D1 rate is $d1")xx <- either(costs(dd, ps.values.toStream, ms)(d1))

} yield xx)_ <- log(s"Costs for positions are: $cc")fs <- //Must run the furnace section regardless of whether we now have costs

furnaceInsertOrUpdate(cc, dd)rs <- {import scala.concurrent.duration._fromTryCatch(Await.result(fs, atMost = 5.minutes))

}_ <- log(f"Created ${rs.size} furnace events")

} yield ()

“Programming is not math”

When you start thinking about types you should start thinking about how you can PROVE things

about your program

For example, you might prove that it is impossible to compare a price with a quantity

You might prove that it is impossible to create a trade from two orders to buy a stock

27

Curry Howard

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

Make use of types at the low-level

To make certain classes of error impossible

To make your intent clearer

That Java puts barriers in the way for this purpose

But that is not a reason not to do it

Nor a reason to eschew Java

That general types are important too

The lack of them will affect the programs you can write

That a language can affect how you think about types

Type parameters are not the enemy

Abstractions are only possible/useful if the language is rich enough to support their use

That if you let types pervade your programs

Your programs can be better!

28

Epilogue

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

It’s not just scala

C C++ C# Scala Matlab Python Java Q FPGA

Plenty of dissenting voices!

29

Technology at GSA

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

30Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261

Contact us

Private & Confidential. Not for distribution. GSA Capital Partners LLP is authorised and regulated by the Financial Services Authority.

Registered in England & Wales. Stratton House, 5 Stratton Street, London, W1J 8LA. Number OC309261 31

GSA Capital Partners LLP

[email protected]

T +44 (0)20 7959 8850

London Office

Stratton House

5 Stratton Street

London W1J 8LA

T +44 (0)20 7959 8800

F +44 (0)20 7959 8845

New York Office

1140 Ave of the Americas

9th Floor

New York NY 10036