Instantly share code, notes, and snippets.


Circe 1.0 planning

Big-picture questions

  • When do we release 1.0?
  • How long do we support 1.0?
  • How soon do we start 2.0?

Scala Exchange 2017

Travis Brown, A tour of Typelevel by way of Circe, 90 minutes

In this workshop we will introduce concepts from a range of Typelevel (and Typelevel-adjacent) projects—from Cats to Shapeless to Monocle to fs2—while coming up with practical solutions to JSON processing problems with Circe.

View Qux.scala
// Before
import io.circe.Decoder
case class Qux(a: Int, b: String)
val decodeQuxMonadic: Decoder[Qux] = Decoder.instance { c =>
for {
a <- c.get[Int]("a")
b <- c.get[String]("b")
View YourTweetsAreTooLong.scala
import cats.implicits._
import scala.collection.JavaConverters._
import scala.concurrent.{Await, Future}
import scala.concurrent.duration.Duration
import twitter4j._, twitter4j.conf.ConfigurationBuilder
object YourTweetsAreTooLong {
private type PagingState = (Long, Option[Long])
View fp-example.scala
import cats.implicits._, fastparse.all._
case class Result(bindings: Map[String, String], values: List[String])
val token: Parser[String] = P(CharIn('a' to 'z')).rep.!
val binding: Parser[Map[String, String]] = (token ~ " = " ~ token ~ "\n").map {
case (k, v) => Map(k -> v)
View parsing.scala
def parseLong(input: CharSequence, start: Int, end: Int): Long = {
var negative: Boolean = false
var i: Int = start
var result: Long = 0L
if (input.charAt(start) == '-') {
negative = true
i += 1

This release includes several changes that are not binary compatible with previous Jawn releases. Most importantly, all of the methods on Facade that previously took String arguments now take the more general CharSequence (#83). This change is intended to support parsers that provide facades with slices into the input string, which can reduce allocations since it means that strings don't have to be instantiated unnecessarily. All of the parsers provided by Jawn itself simply use strings, though, which offers reasonable performance without the risk of delaying the garbage collection of large input strings.

In most cases if you are implementing a facade, you can migrate your code to this release by replacing String with CharSequence in your method signatures and calling toString (which will be a no-op) on these CharSequence values in your implementations.

Another breaking change is that these two methods in Facade have been replaced (#80):

  def jnum(s: String): J
  def jint(s: Strin
View PatternMatchingHack.scala
sealed trait Foo[F[_], A]
case class Bar[F[_], A](f: F[A]) extends Foo[F, A]
case class Baz[F[_], A](f: F[A]) extends Foo[F, String]
sealed trait Qux[F[_], A] {
def value: F[A]
def stuff: F[String]
trait Arr[F[_], G[_]] {
View queens.scala
class Nil
class Cons[X, Xs]
class First[List] { type X }
object First {
type Aux[List, X0] = First[List] { type X = X0 }
implicit val nilFirst: Aux[Nil, Nil] = ???
implicit def consFirst[X0, Xs]: Aux[Cons[X0, Xs], X0] = ???
View foldMapM.scala
import cats.{ Applicative, Eval, Foldable, Monoid }, cats.implicits._
def foldMapM[F[_]: Foldable, G[_]: Applicative, A, B: Monoid](fa: F[A])(f: A => G[B]): G[B] =
fa.foldRight(Eval.always(Monoid[B].empty.pure[G]))((a, acc) => f(a).map2Eval(acc)(_ |+| _)).value
def sumIfSmall(s: Stream[Int]) = foldMapM(s) {
case n if n < 100 => Right(n)
case n => Left(n)