# Null is not an Option
# Either are NPEs
## Me
* Charles O'Farrell
* Atlassian
* [@charlesofarrell](http://twitter.com/charlesofarrell)
## What's wrong with this code?
```java
public Foo someMethod()
someMethod().doSomething()
```
## Look again
```java
@Nullable
public Foo someMethod()
someMethod().doSomething()
```
## By the power of Greyskull
```java
public Nullable<Foo> someMethod()
// Won't compile
someMethod().doSomething()
```
## Introducing Option
```scala
sealed abstract class Option[A]
case class Some[+A](x: A) extends Option[A]
case object None extends Option[Nothing]
```
- Collection with none or one element
## Revenge of the null
```java
Map<String, Conflict> conflicts = ...
InternalChange change = parseChange(line);
Conflict conflict = conflicts.get(change.getPath());
if (conflict == null) {
conflict = conflicts.get(change.getSrcPath());
}
if (conflict != null) {
change = builder.conflict(conflict).build();
}
```
## java.util.Map
```java
class Map<K, V> {
@Nullable
V get(K key)
}
```
## Scala Map
```scala
class Map[K, V] {
Option[V] get(K key)
}
```
## More Options
```scala
trait Option[A] {
def isEmpty: Boolean
def isDefined: Boolean
def get: A // throws NoSuchElementException
}
```
## Option as null
```scala
val conflicts: Map[String, Conflict] = ...
var change: InternalChange = parseChange(line)
var conflict: Option[Conflict] = conflicts.get(change.getPath)
if (conflict.isEmpty) {
conflict = conflicts.get(change.getSrcPath)
}
if (conflict.isDefined) {
change = builder.conflict(conflict.get).build
}
```
## Option as null
* Already better than null
* Type-safety vs documentation
* Developers have to stop and think
* But, get is ugly...
## Use Option or else
```scala
abstract class Option[A] {
def orElse[B >: A](alternative: => Option[B]): Option[B]
}
```
Note "`: =>`" is evaluated lazily
## Composing Option
```scala
val conflictOption: Option[Conflict] =
conflicts.get(change.getPath)
.orElse(conflicts.get(change.getSrcPath))
for (conflict <- conflictOption) {
change = builder.conflict(conflict).build
}
```
## Seems familiar
```js
var value = map['a'] || map['b'] || 'c'
```
```Scala
val value: Option[String] = map.get("a").orElse(map.get("b")).orElse(Some("c"))
```
## Get or else
```scala
abstract class Option[A] {
def getOrElse[B >: A](default: => B): B
}
```
## Seems familiar (part 2)
```js
var value = map['a'] || map['b'] || 'c'
```
```scala
val value: String = map.get("a").orElse(map.get("b")).getOrElse("c")
```
## Seen this before?
```java
InetSocketAddress socketAddress = session.getIoSession().getRemoteAddress();
if (socketAddress != null) {
InetAddress inetAddress = socketAddress.getAddress();
if (inetAddress != null) {
remoteAddress = inetAddress.getHostAddress();
}
}
```
## Not a null in sight
```scala
val remoteAddress: Option[String] = for {
socketAddress <- session.getIoSession.getRemoteAddress
inetAddress <- socketAddress.getAddress
} yield inetAddress.getHostAddress
```
## Is Option a better null?
- Type safety
- Just a collection
- Can filter/map/concat/etc
- Composition!
## Another example
```java
public ModelAndView browseFilePath() {
Repository repository = getRepository(projectKey, repoSlug);
if (repository == null) {
return handleEmptyRepo();
}
Branch defaultBranch = getDefaultBranch(repository);
if (defaultBranch == null) {
return handleNoDefaultBranch(repository);
}
return doSomething(defaultBranch);
}
```
## What do we want?
```scal
def browseFilePath: ModelAndView = {
doSomething(getRepositoryAndBranch)
}
def diffFilePath: ModelAndView = {
doSomethingElse(getRepositoryAndBranch)
}
```
## Could we use Option?
```scala
def getRepository: Option[Repository]
def getDefaultBranch: Option[Branch]
```
## Could we use Option?
```scala
def browseFilePath: Option[ModelAndView] = {
for {
repository <- getRepository(projectKey, repoSlug)
defaultBranch <- getDefaultBranch(repository)
} yield doSomething(defaultBranch)
// TODO What about handleEmptyRepo or handleNoDefaultBranch?
}
```
## Could we use Option?
* In short - no!
## Use Exceptions?
```java
public Repository getRepository() throws ModelAndViewException {
Repository repository = repositoryService.findBySlug(projectKey, repoSlug);
if (repository == null) {
throw new ModelAndViewException(handleEmptyRepo());
}
return repository;
}
```
```java
public Branch getRepositoryAndBranch() throws ModelAndViewException {
Repository repository = getRepository(projectKey, repoSlug);
return getDefaultBranch(repository);
}
```
## I take Exception to that
```java
public ModelAndView browseFilePath() {
try {
return doSomething(getRepositoryAndBranch());
} catch (ModelAndViewException e) {
return e.getModelAndView();
}
}
```
```java
public ModelAndView diffFilePath() {
try {
return doSomethingElse(getRepositoryAndBranch());
} catch (ModelAndViewException e) {
return e.getModelAndView();
}
}
```
## What is this really saying?
```java
Repository getRepository() throws ModelAndViewException
```
Can this be expressed as a function - only one return type?
Return _either_ ModelAndView or Repository
```scala
def getRepository: Either[ModelAndView, Repository]
```
## Either
```scala
sealed abstract class Either[+L, +R]
case class Left[+L, +R](a: L) extends Either[L, R]
case class Right[+L, +R](b: R) extends Either[L, R]
```
## Either as exceptions
```scala
def getRepository: Either[ModelAndView, Repository] = {
val repository: Option[Repository] = repositoryService.findBySlug(projectKey, repoSlug)
repository.map(value => Right(value)).getOrElse(Left(handleEmptyRepo))
}
```
## To the Right
```scala
class Option[+A] {
def toRight[L](left: => L): Either[L, A]
}
```
## To the Right
```scala
def getRepository: Either[ModelAndView, Repository] = {
repositoryService.findBySlug(projectKey, repoSlug).toRight(Left(handleEmptyRepo))
}
```
## Either Projection
```scala
sealed abstract class Either[+L, +R] {
def left: Projection[L]
def right: Projection[R]
}
class Projection[A] {
def get: A // throws NoSuchElementException
}
```
## Either to the rescue
```scala
def getRepositoryAndBranch: Either[ModelAndView, Branch] = for {
repository <- getRepository(projectKey, repoSlug).right
branch <- getDefaultBranch(repository).right
} yield branch
```
## Are we there yet?
```scala
def browseFilePath = {
for (branch <- getRepositoryAndBranch.right) yield doSomething(branch)
}
def diffFilePath = {
for (branch <- getRepositoryAndBranch.right) yield doSomethingElse(branch)
}
```
## Not quite
```scala
def browseFilePath: Either[ModelAndView, ModelAndView] = ...
```
```scala
object Either {
implicit def e2m[A](x: Either[A, A]): MergeableEither[A] = new MergeableEither(x)
class MergeableEither[A](x: Either[A, A]) {
def merge: A
}
}
```
## Either
- Like checked exceptions
- But just a return value
## Question
- How does for comprehension work?
## From before
```scala
def getRepositoryAndBranch: Either[ModelAndView, Branch] = {
repository <- getRepository(projectKey, repoSlug).right
branch <- getDefaultBranch(repository).right
} yield branch
```
## Syntactic Sugar
```scala
def getRepositoryAndBranch: Either[ModelAndView, Branch] = {
getRepository(projectKey, repoSlug).right
.flatMap(repository => getDefaultBranch(repository)).right
.map(branch => branch)
}
```
## Down the rabbit hole
```scala
class RightProjection[L, R] {
def map[Y](f: R => Y): Either[L, R]
def flatMap[LL >: L, Y](f: R => Either[LL, Y]): Either[LL, Y]
}
```
## Syntactic Sugar
```scala
def browseFilePath = {
getRepositoryAndBranch.right.map(doSomething).merge
}
```
## From before
```scala
val remoteAddress: Option[String] = for {
socketAddress <- session.getIoSession.getRemoteAddress
inetAddress <- socketAddress.getAddress
} yield inetAddress.getHostAddress
```
## Even more Options
```scala
abstract class Option[A] {
def map[B](f: A => B): Option[B]
def flatMap[B](f: A => Option[B]): Option[B]
}
```
## Syntactic Sugar
```scala
session.getIoSession.getRemoteAddress
.flatMap(socketAddress => socketAddress.getAddress)
.map(inetAddress => inetAddress.getHostAddress)
```
## Abstract all the things
```scala
abstract class Option[A] {
def map[B](f: A => B): Option[B]
def flatMap[B](f: A => Option[B]): Option[B]
}
```
```scala
class RightProjection[L, R] {
def map[Y](f: R => Y): Either[L, R]
def flatMap[LL >: L, Y](f: R => Either[LL, Y]): Either[LL, Y]
}
```
## What shall we call it?
```scala
trait WarmFuzzyThing[A] {
def map[B](f: A => B): WarmFuzzyThing[B]
def flatMap[B](f: A => WarmFuzzyThing[B]): WarmFuzzyThing[B]
}
```
## Monad!
```scala
trait Monad[A] {
def map[B](f: A => B): Monad[B]
def flatMap[B](f: A => Monad[B]): Monad[B]
}
```
Actually not quite...
## Mo Monad
```scala
trait Monad[M[_]] {
def map[A, B](fa: M[A], f: A => B): M[B]
def flatMap[A, B](fa: M[A], f: A => M[B]): M[B]
}
```
## Monads are out there

## Question
- Can we get rid of those pesky 'rights'?
## Biased
[Tony Morris](https://groups.google.com/d/msg/scala-debate/K6wv6KphJK0/l8i0SSw6NlIJ)
> Some history. I wrote scala.Either.
> Originally, it was Right-biased. A peer convinced me to remove the bias [...].
> I have since regretted it.
## Shit just got real
```scala
import scalaz._
import Scalaz._
```
## Right-biased Either
```scala
sealed trait \/[+L, +R]
object \/ {
def left[L, R](l: L) = -\/(l)
def right[L, R](r: R) = \/-(r)
}
```
## Ascii Madness
```scala
def getRepository: \/[Model, Repository]
```
Same as:
```scala
def getRepository: Model \/ Repository
```
## \o/
```scala
def getRepositoryAndBranch: ModelAndView \/ Branch = for {
repository <- getRepository(projectKey, repoSlug)
branch <- getDefaultBranch(repository)
} yield branch
```
```scala
def browseFilePath = {
getRepositoryAndBranch.map(doSomething).merge
}
```
## Other uses?
- What about validating forms?
## Validation
```scala
def validateUsername(username: String): Exception \/ String
def validateEmail(email: String): Exception \/ String
```
```scala
val user: Exception \/ User = for {
username <- validateUsername(request.get("username"))
email <- validateEmail(request.get("email"))
} yield createUser(username, email)
```
## What about multiple errors?
- Hmm, we want something a little different...
- List[Exception] \/ User
## Validation
```scala
sealed trait Validation[+E, +A]
case class Success[E, A](a: A) extends Validation[E, A]
case class Failure[E, A](e: E) extends Validation[E, A]
type ValidationNEL[+E, +X] = Validation[NonEmptyList[E], X]
```
## Validation in action
```scala
def validateEmail(email: String): ValidationNEL[Exception, String] = {
if (email.contains("@")) {
email.success
} else {
(new RuntimeException("Bad email")).failureNel
}
}
```
## Question
- How will we compose them?
## Applicative Builder
```scala
def createUser(username: String, email: String): User
```
```scala
val validations: ValidationNEL[Exception, User] =
(validateUsername(username) |@| validateEmail(email))(createUser)
```
## Back to Option
```scala
def createUser(username: String, email: String): User
```
```scala
val user: Option[User] = (map.get("username") |@| map.get("email"))(createUser)
```
## The Macaulay Culkin Operator

## Further Reading
- [Scala Typeclassopedia](http://marakana.com/s/scala_typeclassopedia_with_john_kodumal_of_atlassian_video,1198/index.html)
- [Learning Scalaz](http://eed3si9n.com/learning-scalaz-day7)