Skip to content

Instantly share code, notes, and snippets.

@larsrh
Last active July 22, 2016 07:50
Show Gist options
  • Save larsrh/3e2d3789abc0a35b7dce7275b50ba816 to your computer and use it in GitHub Desktop.
Save larsrh/3e2d3789abc0a35b7dce7275b50ba816 to your computer and use it in GitHub Desktop.
safe head/tail on lists using covariance
// Initial idea courtesy of @dwijnand
// Improved by @fthomas
sealed trait List[+T] {
def head: Option[T]
}
final case class Cons[T](h: T, t: List[T]) extends List[T] {
val head: Some[T] = Some(h)
}
final case object Nil extends List[Nothing] {
val head = None
}
// scala> Cons(1, Nil).head.x
// res0: Int = 1
// scala> Nil.head
// res1: None.type = None
@Blaisorblade
Copy link

Blaisorblade commented Jul 13, 2016

s/Cons(1, Nil).head.x/Cons(1, Nil).head.get/ maybe? But cool.

@larsrh
Copy link
Author

larsrh commented Jul 13, 2016

No, not get. That would defeat the purpose. Here's how Some is defined:

case class Some[T](x: T) extends Option[T]

@fthomas
Copy link

fthomas commented Jul 13, 2016

This can be made even simpler:

scala> :paste
// Entering paste mode (ctrl-D to finish)

sealed trait List[+T] {
  def head: Option[T]
}

final case class Cons[T](h: T, t: List[T]) extends List[T] {
  val head: Some[T] = Some(h)
}

final case object Nil extends List[Nothing] {
  val head = None
}

// Exiting paste mode, now interpreting.

defined trait List
defined class Cons
defined object Nil

scala> Cons(1, Nil).head.x
res0: Int = 1

scala> Nil.head
res1: None.type = None

@dwijnand
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment