question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Deprecate upickle-pprint

See original GitHub issue

These two libraries have had a good run over the last 3 years, but many of their original motivations for existing have since disappeared, and other parts of their design haven’t work out over time.

Automatic, deep compile-time derivation

The current implementation, in the derive/ subproject, is probably a dead end in terms of engineering: it is a rats nest of complexity that works ok for what it does now, but nobody understands how it works, and it is almost impossible to fix the existing bugs without causing regressions (i.e. the code is a total disaster).

This results in bugs like https://github.com/lihaoyi/Ammonite/issues/575, https://github.com/lihaoyi/upickle-pprint/issues/196, https://github.com/lihaoyi/upickle-pprint/issues/182, and may others that are beyond my ability to fix.

For JSON serialization, a partial workaround is to declare implicit read-writers in every case class’s companion objects via implicit val rw = upickle.default.macroRW[MyClass]. This helps avoid the nasty/buggy deep derivation logic entirely, and is something I have adopted in all my own projects. We could make this easier with a macro annotation, but fundamentally if we’re giving up on automatic deep compile-time derivation, we could just use something like https://github.com/playframework/play-json instead.

If we want to try a more principled approach to compile-time derivation, we should probably use Shapeless instead of doing it ourselves. In that case, we could also just use https://github.com/circe/circe which seems to work out of the box., or https://github.com/julienrf/play-json-derived-codecs

For pretty-printing, my main use case is for Ammonite on the JVM. In that case, using runtime/Java reflection is probably the right thing to do.

Scala-js Compatibility

uPickle was the first, and at the time only, cross-JS/JVM serialization library. Since then there have been countless others, including new ones like https://github.com/circe/circe and existing ones like https://github.com/playframework/play-json which have picked up cross-platform support.

Those other libraries are better maintained and more featureful, so since uPickle is no longer the only one with Scala.js support, we should probably focus our efforts/maintenance/contributions on one of the others.

I don’t really use PPrint much on Scala.js, so a Java-reflection-based PPrint that doesn’t support Scala.js isn’t an issue for me.

Simple API

Part of uPickle’s benefits is the simple API for serializing things:

import upickle.default._

write(1)                          ==> "1"

write(Seq(1, 2, 3))               ==> "[1,2,3]"

read[Seq[Int]]("[1, 2, 3]")       ==> List(1, 2, 3)

write((1, "omg", true))           ==> """[1,"omg",true]"""

And for looking things up:

json(8)("real").value == -9876.54321

Play-Json more or less already does the same thing:

@ Json.stringify(Json.toJson(1))
res4: String = "1"
@ Json.stringify(Json.toJson(Seq(1, 2, 3)))
res5: String = "[1,2,3]"
@ Json.fromJson[Seq[Int]](Json.parse("[1,2,3]"))
res6: play.api.libs.json.JsResult[Seq[Int]] = JsSuccess(List(1, 2, 3), )

While the API is more verbose, it should be trivial to add a helper function to simplify it. Other things, like tuples not being supported:

@ Json.stringify(Json.toJson((1, "omg", true)))
cmd7.sc:1: No Json serializer found for type (Int, String, Boolean). Try to implement an implicit Writes or Format for this type.
val res7 = Json.stringify(Json.toJson((1, "omg", true)))
                                     ^
Compilation Failed

Should also be easy to add.

Similarly, play-json has a somewhat inconsistent .apply/\ based API, but that can also be fixed relatively easily to provide the same lookup-syntax that uPickle currently has:

Overall, play-json is probably similar enough to uPickle at this point, with the new Scala.js support, that it might be easier to start from it as a base and port the simple API on top of it, rather than trying to wrangle uPickle’s internals into a simpler state. I’m not familiar enough with Circe to say whether or not it’s the same, but likely they solved many of the same problems, and it may also be easier to prettify circe rather than cleaning up uPickle’s internals

Additional Features

It would be nice to provide things like:

  • Streaming reading/writing of JSON from e.g. java.io.{Input,Output}Streams
  • “deep” xpath-style lookup, a better syntax for creating JSON fragments
  • Better error messages for parsing and validation

These are all things that Circe/Play-Json provide to varying degrees, and it would be nice if we could leverage that rather than re-implementing all the same stuff in uPickle


Overall, uPickle and PPrint have had a good run over the last 3 years, but I think the design of these two libraries is probably a dead end. The best way forward is probably to port all the syntactic niceties over to play-json, whether upstream or as a fork, and implementing a Java-reflection-based pretty-printer for use in Ammonite.

Things that would make play-json work as a mostly-drop-in replacement for uPickle:

There may be a few others, but it’s a relatively short list that would make play-json work for 99% of uPickle’s use cases

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:13
  • Comments:11 (7 by maintainers)

github_iconTop GitHub Comments

3reactions
MasseGuillaumecommented, May 12, 2017

@lihaoyi well first off thank you for this amazing library. I use it in Scalakata and in Scastie for instrumentation rendering for both value (pprint) and type (tprint).

TPrint have no other alternative. If you want, I can extract it from this repository and maintain it.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How and When to Deprecate APIs - Oracle Help Center
Starting with J2SE 5.0, you deprecate a class, method, or field by using the @Deprecated annotation. Additionally, you can use the @deprecated Javadoc...
Read more >
Tutorial — Deprecated 1.2.14 documentation - Read the Docs
In this tutorial, we will use the Deprecated Library to mark pieces of codes as deprecated. We will also see what's happened when...
Read more >
Java @Deprecated Annotation - Baeldung
In this quick tutorial, we'll have a look at deprecated APIs in Java and how to use the @Deprecated annotation.
Read more >
How to properly deprecate - DEV Community ‍ ‍
Make a plan to only remove the item from your next major version (i.e. x. · In your next patch version (i.e. 1.1....
Read more >
npm-deprecate
This command will update the npm registry entry for a package, providing a deprecation warning to all who attempt to install it. It...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found