Age is not an int
-
Upload
oxbowlakes -
Category
Technology
-
view
982 -
download
1
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
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
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