Hi,
We are trying to navigate how to serialize stuff in sbt. I haven't
discussed this too much with others, it's just my initial problem
statement / ideas.
There are several distinct cases I know of.
1. currently sbt uses sbinary for caching
https://github.com/sbt/sbt/blob/0.13/cache/src/main/scala/sbt/Cache.scala
2. we are using play-json in sbt-remote-control for the client-server protocol
3. we are using play-json in sbt-remote-control for serializing task
results over the wire; the serializers are registered via a
registeredFormats key that is (in essence) a list of
(Manifest[T],Format[T])
4. other future uses (serializing an event log?)
We want to move these sbt-remote-control APIs (or something based on
them) into sbt itself:
https://github.com/sbt/sbt-remote-control/blob/master/commons/ui-interface/src/main/scala/sbt/UI.scala
Note the use of play-json's Writes type to send events:
https://github.com/sbt/sbt-remote-control/blob/master/commons/ui-interface/src/main/scala/sbt/UI.scala#L16
play-json is going to make a mess here; it has a bunch of transitive
dependencies that could interfere with sbt plugins, plus play depends
on sbt, so it will be a circular dependency (and also since sbt has a
frozen ABI, we might end up having play-json X.Y in play X.Y+1 -
awkward!).
scala pickling does not have a frozen ABI yet (right?) so if we pulled
it into sbt we'd be stuck on a prerelease of it for the duration of
0.13.x, which would cause trouble if anyone used the final release
inside the sbt classloader.
dependencies are just kind of a problem for sbt, since they all get
version-locked and keep people from using any other version of that
dependency in an sbt plugin.
Ideally we might have a serialization API like pickling's that
supports both binary and JSON, since for some of the use cases the
binary efficiency would be useful.
Here is a strawman suggestion for what to do:
* via shameless cut-and-paste of existing apache-licensed libs,
create a minimal sbt-specific interface to serialization
* in this interface, have the equivalent of play-json's implicit
Reads and Writes, but instead of reading and writing an AST, use
pickling-style streaming Builder and Reader:
https://github.com/scala/pickling/blob/0.9.x/core/src/main/scala/pickling/PBuilderReader.scala
--
You received this message because you are subscribed to the Google Groups "sbt-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sbt-dev+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/sbt-dev/CAFLqJky06-rx64ANQ4nhHYqcCw1ms0in1xQOKY-MiiXocneFcQ%40mail.gmail.com.
--
You received this message because you are subscribed to the Google Groups "sbt-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sbt-dev+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/sbt-dev/CAA3p8zCr-KcGezP%2BGuy-bLLc-UD1Rbi23ehqqiWQ93zQtU6JeA%40mail.gmail.com.
case class Foo(x: Int, y: Option[Int])object Hello extends App {import scala.pickling._import json._val obj = """{"x": 1}""".unpickle[Foo]}
java.util.NoSuchElementException: key not found: yat scala.collection.MapLike$class.default(MapLike.scala:228)at scala.collection.AbstractMap.default(Map.scala:58)at scala.collection.MapLike$class.apply(MapLike.scala:141)at scala.collection.AbstractMap.apply(Map.scala:58)at scala.pickling.json.JSONPickleReader.readField(JSONPickleFormat.scala:243)at scala.pickling.json.JSONPickleReader.readField(JSONPickleFormat.scala:166)at hello.Hello$HelloFooUnpickler2$2$.unpickle(hello.scala:10)
Havoc
--
You received this message because you are subscribed to the Google Groups "sbt-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sbt-dev+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/sbt-dev/CAA3p8zAYByPHqfxZcnJR%3D-Agt2Dif%2BasqLxYW56rRmsxJQnfBg%40mail.gmail.com.
The example you gave is about *removing* a field, not adding one.
In my mind this is kind of an implementation detail of the
JSON unpickler that needs to be changed for our purposes, rather than
anything fundamental; doesn't it seem like we could fix this with a
pretty simple patch, to allow Option fields to be missing?
I feel like this is more about how we use the tools; for example, do
we have a separate DTO, or just the original sbt types?
The mail I sent yesterday about
https://github.com/sbt/sbt-remote-control/blob/master/server/src/main/scala/sbt/server/SbtToProtocolUtils.scala
makes this issue very concrete, no?
When you add field "y" to sbt.Foo you would update to map sbt.Foo to
protocol.Foo2
Older peers expecting just the "x" field simply ignore the "y" field.
It *is* important that the deserializer for Foo ignores unknown
fields; this rules out some binary encoding possibilities, for
example.
package hellocase class Foo(x: Int)case class Foo2(x: Int)
object Hello extends App {import scala.pickling._import json._
val pkl = Foo(1).pickleval obj = pkl.value.unpickle[Foo2]}
java.lang.ClassCastException: hello.Foo cannot be cast to hello.Foo2at hello.Hello$delayedInit$body.apply(hello.scala:10)at scala.Function0$class.apply$mcV$sp(Function0.scala:40)at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)at scala.App$$anonfun$main$1.apply(App.scala:71)at scala.App$$anonfun$main$1.apply(App.scala:71)at scala.collection.immutable.List.foreach(List.scala:318)at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:32)at scala.App$class.main(App.scala:71)
Anyway, right now sbt-remote-control does have this mapping layer from
native type to protocol (DTO) type. We allow registering conversions
from native to protocol:
https://github.com/sbt/sbt-remote-control/blob/master/commons/ui-interface/src/main/scala/sbt/UI.scala#L98
Jim discovered yesterday a case where this gets a bit ugly, which is
if you have:
package protocol {
case class Foo(x: Int)
case class Bar(foo: Foo, something: Int)
}
package sbt {
case class Foo(x: Int)
case class Bar(x: Foo, something: Int)
}
the issue is that to do a macro-generated serializer for sbt.Bar, it
needs a serializer for sbt.Foo, but we only have a serializer for
protocol.Foo. I think the clean solution for this may be to have an
explicit typeclass for "protocolizable" which, given type S, can give
you type P which has a Writes[P] available. However, I'm not sure that
actually works without blowing scala's mind in some way. We need to
think about this one.
Now, we do not *have* to do these two parallel type trees. We could
explore solutions that keep one or the other.
Option 1, keep only protocol:
Option 2, keep only the native sbt types:
Let's call Option 3 keeping both types, as sbt-remote-control does now.
An advantage of having two separate sets of types (DTO and sbt native)
is that protocol breaks actually show up as compile errors, or at
least they often would.
A disadvantage is complexity / duplication.
Trying to split up some issues, not sure what we are discussing necessarily ;-)
Pickling's current JSON pickler is too picky
===
It looks like pickling's current JSON pickler does not do what we
want, but I think this is easy to address; play-json DOES do what we
want already, with a very similar API.
case classes in the protocol._ (DTO) jar
===
If we use case classes for protocol._ then we have to introduce a new
case class when we want to add an optional field, rather than adding
the field to the existing case class - this is for ABI reasons rather
than serialization reasons. We could solve that by using traits (or
whatever) instead of case classes in protocol._, at the expense of
making protocol._ a little more annoying for us to implement and a
little harder for people to use.
We could quickly sketch out how we'd do it, maybe the contrast is
doing extensions from 1.0 to 1.1 this way:
final case class Foo(x: Int)
final case class Foo2(x: Int, y: Option[Int]) // @since 1.1
vs.
sealed trait Foo {
def x: Int
def y: Option[Int] // @since 1.1
}
object Foo { /* manually do apply and unapply and stuff? not really
sure what the details are */ }
final class EvictionWarningOptions private[sbt] (val configurations: Seq[Configuration],val warnScalaVersionEviction: Boolean,val warnDirectEvictions: Boolean,val warnTransitiveEvictions: Boolean,val showCallers: Boolean,val guessCompatible: Function1[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean]) {private[sbt] def configStrings = configurations map { _.name }def withConfigurations(configurations: Seq[Configuration]): EvictionWarningOptions =copy(configurations = configurations)....private[sbt] def copy(configurations: Seq[Configuration] = configurations,warnScalaVersionEviction: Boolean = warnScalaVersionEviction,warnDirectEvictions: Boolean = warnDirectEvictions,warnTransitiveEvictions: Boolean = warnTransitiveEvictions,showCallers: Boolean = showCallers,guessCompatible: Function1[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean] = guessCompatible): EvictionWarningOptions =new EvictionWarningOptions(configurations = configurations,warnScalaVersionEviction = warnScalaVersionEviction,warnDirectEvictions = warnDirectEvictions,warnTransitiveEvictions = warnTransitiveEvictions,showCallers = showCallers,guessCompatible = guessCompatible)}
package hellofinal class Foo private[hello] (val x: String, val y: Option[Int]) {def copy(x: String, y: Option[Int]): Foo =new Foo(x = x, y = y)}object Foo {def apply(x: String): Foo = new Foo(x, None)def apply(x: String, y: Option[Int]) = new Foo(x, y)def unapply(foo: Foo): Option[(String, Option[Int])] =Some((foo.x, foo.y))
}object Hello extends App {import scala.pickling._import json._
val pkl = Foo("hello").pickleprintln(pkl.value)}
There's the obvious practical issue here that the existing
serialization macros in pickling and play-json don't support traits,
but I think we could solve that.
Detail question about the trait version: isn't there only one unapply
allowed? So once we add a field, anyone who wants to use that field
has to use `case foo: Foo => ` instead of `case Foo(x,y) =>` - it's OK
I guess.
=> Suggested path forward here: I'm open to the
hand-roll-a-non-case-class-thing trait version, but I haven't worked
out what it looks like in detail enough to know that it in fact helps
us. So I'd probably want to do that next (explore details). The
question I'd want to answer by working out the details is whether
keeping the same type name when adding fields is enough of a win vs.
whatever the extra complexity turns out to be.
> I've been hoping someone would write a pseudo-case-class generator that's
> aware of API evolution e.g. generate hashCode and def this based on 1.0
> interface, but provide extra fields for apply and unapply on 1.1 interface.
> An ideal option 1 would be a set of pseudo-case-classes and associated type
> class instances based on series of json files marked with version number.
Is this even a serialization-specific problem? maybe we want to go
ahead and start generating types like this everywhere in sbt that's
tempted to use a case class?
Is there a schema description language / schema files?
===
If the goal is to have both a file with case classes and a file with a
schema in some schema description language, then you can generate
either from the other, conceptually. The one thing that's clearly bad
is to write them BOTH by hand, because then they can be out of sync.
Whether to have two layers or one
===
=> Suggested path forward: What I'm leaning toward saying here is that
we have a jar with some plain old data types shared between client and
server; sometimes we use these directly; sometimes we have to convert
sbt's native types to them. So we have two layers but only actually
duplicate the layers when we need to
--
You received this message because you are subscribed to the Google Groups "sbt-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sbt-dev+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/sbt-dev/CAA3p8zAEjCaJaz5EKx4zMTNux1U8di-Nvc2QwYnyeDms5gZv4w%40mail.gmail.com.
On Tue, Sep 23, 2014 at 5:42 PM, Havoc Pennington <havoc.pe...@typesafe.com> wrote:Trying to split up some issues, not sure what we are discussing necessarily ;-)Good idea. We can wrap up some topics.Pickling's current JSON pickler is too picky
===
It looks like pickling's current JSON pickler does not do what we
want, but I think this is easy to address; play-json DOES do what we
want already, with a very similar API.Why do we like pickler so much? The chief motivation is that it uses macros to auto serialize simple case classes.My argument is that using serializer for long-term caching and restful API is not a good fit, because json needs to be the king, not case classes. Especially if we are thinking about requiring plugin authors to adopt the protocol, we need to make json the king.
Detail question about the trait version: isn't there only one unapply
allowed? So once we add a field, anyone who wants to use that field
has to use `case foo: Foo => ` instead of `case Foo(x,y) =>` - it's OK
I guess.Yes.=> Suggested path forward here: I'm open to the
hand-roll-a-non-case-class-thing trait version, but I haven't worked
out what it looks like in detail enough to know that it in fact helps
us. So I'd probably want to do that next (explore details). The
question I'd want to answer by working out the details is whether
keeping the same type name when adding fields is enough of a win vs.
whatever the extra complexity turns out to be.To me, the ability to grow API while remaining bincompat is really important.We need to keep the same name so we're not constantly mapping between DTO <-> hand-rolled entity classes.
> I've been hoping someone would write a pseudo-case-class generator that's
> aware of API evolution e.g. generate hashCode and def this based on 1.0
> interface, but provide extra fields for apply and unapply on 1.1 interface.
> An ideal option 1 would be a set of pseudo-case-classes and associated type
> class instances based on series of json files marked with version number.
Is this even a serialization-specific problem? maybe we want to go
ahead and start generating types like this everywhere in sbt that's
tempted to use a case class?There's a general wishes/needs for pseudo case classes, at least in my head.But if we are making json the king, and generating DTOs anyway, it makes sense to piggyback growable ABI agenda.I'm totally for start making pseudo case class generator.
Is there a schema description language / schema files?
===
If the goal is to have both a file with case classes and a file with a
schema in some schema description language, then you can generate
either from the other, conceptually. The one thing that's clearly bad
is to write them BOTH by hand, because then they can be out of sync.Sort of. There's schema, DTO classes, and the marshaling/unmarshaling code.If we decide json is the king, then we start out with generating/inferring json schema, and then from there we generate both DTO and marshaling typeclass instances. For that we would need to write such tools ourselves.In the interim, I'm ok with manually writing both Json parsing code and pseudo case classes because at least I would have control over exactly what Json it's going to emit.
Whether to have two layers or one
===
=> Suggested path forward: What I'm leaning toward saying here is that
we have a jar with some plain old data types shared between client and
server; sometimes we use these directly; sometimes we have to convert
sbt's native types to them. So we have two layers but only actually
duplicate the layers when we need toAgreed. Once we have DTO and stable protocol these could be shared on both client and server side.In some cases we could even enrich-my-library the DTO to append methods without copying data.
Hey guys,
Let me respond to two specific points in this discussion, and a more general point about the architecture of pickling.
scala pickling does not have a frozen ABI yet (right?) so if we pulled
it into sbt we'd be stuck on a prerelease of it for the duration of
0.13.x, which would cause trouble if anyone used the final release
inside the sbt classloader.
We can work with you here. The ABI that we currently have is for the most part frozen – we've been working with it while integrating pickling into Spark and never needed to change the API, and thus the corresponding ABI *could have been frozen*. In just now revisiting the PickleFormat API, the only thing we'd like to change is to remove any remaining hard-coded references to macros (there are two, and they seem to be have snuck in there by accident). We'll open a PR shortly with this fixed. Based on this streamlined API, a frozen ABI will follow.
In the above, you also express concern over depending on a prerelease version. Databricks requires a final release for their integration with Spark by November 3rd. 0.8.0 is the current version of pickling. The changeset that we're sitting on that's targeted to go into 0.9.0 is enormous, and we're in a state where we can and should cut a 0.9.0 release ASAP (e.g., many of our users have moved from 0.8.0 to 0.9.0 SNAPSHOTs again). Thus, what we can do is this: we can cut a 0.9.0 release this week, and any of the larger/breaking changes that sbt needs, including pickler contravariance, we can put into 0.10.0. We could release 0.10.0 as soon as it covers all your immediate needs (like the two issues related to lightweight protocol evolution that Havoc pointed out), within the next few weeks. FYI, we'll also have another release, possibly 0.11.0, around November 3rd for Spark/Databricks.
- if a field is missing, set optional fields to None instead of throwing
- don't put the class name in the serialization; require a class to
be provided when unpickling, and if that class expects the same fields
as the pickled class, it works
Issue (a) should indeed be a simple fix in our JSON pickle format (note: in pickling, "format" denotes JSON/binary/XML/.., unlike play-json). In fact, we could enable this generally (meaning without creating a separate "flexible" JSON pickle format), since code relying on all fields to exist continues to work without changes in behavior; we'd simply allow more JSON to be unpickled successfully. (JSONPickleFormat should be configured to throw an exception when encountering a missing field.)
Issue (b) should not be too difficult to support either. When unpickling, we already require specifying the target type, for example. Here, the questions are more about what's the most desirable solution, and how to support certain binary encoding schemes that elide information such as field names. The required functionality could be something that *some* pickle formats support, but that *not all* pickle formats are required to support. For the regular JSON pickle format, this should be simple. For binary, one could easily create a new pickle format that pickles all field names, and which can have the exact same unpickling logic as the JSON pickle format.
My argument is that using serializer for long-term caching and restful API is not a good fit, because json needs to be the king, not case classes. Especially if we are thinking about requiring plugin authors to adopt the protocol, we need to make json the king.
A point of pickling that's been missing a bit from this discussion is that *you* have control of the format (i.e., the JSON/binary that gets put on the wire). And you can also control how things are serialized. Thus, if you need JSON reading/writing to be made more powerful/flexible, you can fork/provide your own pickle format that is more focused on schema evolution, say (though, below we explain how we can/will address the specific issues Havoc summarized also for the generic formats that we ship).
The great thing about all of this is that you are in complete control of the bits and pieces of serialization that are important to you – look at Scala/pickling as a tool that does two things that *are decoupled* (the whole planet sees these things as being baked together, thanks to Java serialization). There are two parts of serializing any object: (1) there's all the important/complicated analysis similar to what the JVM's serialization does to figure out the "shape" of user-defined types, including all of the tricky ways that objects can be constructed. (2) There's the actual act of actually packing all of that data into a byte array or other data representation. In Java, Kryo, and every other serialization framework that comes to mind, (1) and (2) are baked together. In Scala/pickling, we separate these two things, and for (2) we give you an API to control how pickles are assembled. That means that you get to piggyback on all of that static analysis that took us now more than a year to get right.
So the TLDR is this: rather than needing to fork the entire framework, why not just do as intended and fork the JSON format? You can get almost everything that you require in doing so, and anything that needs additional support from the framework, we can add for you.
Also of note; we're happy to give you guys the keys to the repo, so you can make changes as you require them – we don't want to be in a position where we're frustrating gatekeepers of any kind for you. in general, Philipp and I would be happy to help realize features you require or help with bugfixes as they arrive. We have the same agreement with Databricks/Spark.
Reasons why it's good to reuse pickling rather than forking it. Two reasons, in order of importance. (1) It's better for the ecosystem. As compared to other communities, important Scala open source projects have set a standard for not really working well with each other, and instead shipping forked/patched versions of each others' libs. Giving pickling a shot and depending on it as usual would give us a chance to try a new way of managing open source projects – openness of project direction (let it develop based on the community's needs) by giving important users like sbt and Spark commit rights. This is inspired by how Spark has developed and is developing (note, it's the largest Scala project to the best of my knowledge in terms of contributors >90 per month https://www.openhub.net/p/apache-spark). (2) It's good for pickling. Your needs are shared by others, so a lot of people would benefit by us better supporting sbt. Further, in many cases, adding support for some of the stuff you guys require isn't even difficult for us.
Will post again when we make a pickling PR which addresses the ABI issue above.
Cheers,
Heather
Hi,
Re: pickling, assuming we strip it down to only our needed API, some
known differences from play-json are:
* no AST; uses "streaming" instead (see
https://github.com/scala/pickling/blob/0.9.x/core/src/main/scala/pickling/PBuilderReader.scala
)
* abstracts binary vs. json
* may already be able to pickle non-case-classes (Eugene you just
said it could do the private-constructor class right)
Havoc
Another minor issue is that we do use the JsValue AST in a couple of
places to basically tunnel protocol through the protocol:
scala> import rapture.core._, rapture.json._import rapture.core._import rapture.json._scala> import jsonParsers.scalaJson._import jsonParsers.scalaJson._scala> import strategy.throwExceptionsimport strategy.throwExceptionsscala> val json = json"""{| "fruits": {| "apples": [{ "name": "Cox" }, { "name": "Braeburn" }],| "pears": [{ "name": "Conference" }]| }| }"""json: rapture.json.Json ={"fruits": {"apples": [{"name": "Cox"},{"name": "Braeburn"}],"pears": [{"name": "Conference"}]}}scala> json.fruits.applesres0: rapture.json.Json =[{"name": "Cox"},{"name": "Braeburn"}]scala> case class Apple(name: String)defined class Applescala> json.fruits.apples.as[List[Apple]]res1: List[Apple] = List(Apple(Cox), Apple(Braeburn))
On Tue, Sep 23, 2014 at 6:39 PM, eugene yokota <eed3...@gmail.com> wrote:On Tue, Sep 23, 2014 at 5:42 PM, Havoc Pennington <havoc.pe...@typesafe.com> wrote:Trying to split up some issues, not sure what we are discussing necessarily ;-)Good idea. We can wrap up some topics.Pickling's current JSON pickler is too picky
===
It looks like pickling's current JSON pickler does not do what we
want, but I think this is easy to address; play-json DOES do what we
want already, with a very similar API.Why do we like pickler so much? The chief motivation is that it uses macros to auto serialize simple case classes.My argument is that using serializer for long-term caching and restful API is not a good fit, because json needs to be the king, not case classes. Especially if we are thinking about requiring plugin authors to adopt the protocol, we need to make json the king.In sbt, types are the king, JSON is merely a convenient serializers/end-of-the-world concept.
The Goals/Requirements we should have in serialization:
- End user serialization is dead simple (i.e. users CAN make custom tasks with custom return types, and we can enforce serializers on all of these)
- Minor protocol adjustments should be convenient. I should be able to make "intuitive" compatible changes to the case class to evolve an API and not break clients. This means, if I'm using v1.0 of a plugin in a client, and the build has v1.0.1, my client should *semantically* work, possibly with not as much functionality.
- NON-REQUIREMENT: Major protocol adjustments (these should literally be new types). Upon failure to load, a cache should be INVALIDATED. Similarly, when sending messages and the message doesn't meet an expected format, you should error with incompatible. Instead, we need to work in some notion of "protocol level" where we can move up/down a protocol version inside the server so we adapt to the protocol a client supports. These should LITERALLY be different types (possibly the same names, but different packages) with adaptors between them.
- A protocol escape hatch: If we are unable to deserialize a message into a type, we can give it to the client in raw JSON as an escape hatch, but ideally this doesn't happen often.
- Java Binary compatibility should be maintained on the *Scala API* for the underlying protocol types/classes/traits/objects.
- The ability to efficiently serialize over time (cache to disk) a value *OR* serialize over location (send to client) a value. (Hence JSON vs. binary representation as a goal).
=> Suggested path forward here: I'm open to the
hand-roll-a-non-case-class-thing trait version, but I haven't worked
out what it looks like in detail enough to know that it in fact helps
us. So I'd probably want to do that next (explore details). The
question I'd want to answer by working out the details is whether
keeping the same type name when adding fields is enough of a win vs.
whatever the extra complexity turns out to be.To me, the ability to grow API while remaining bincompat is really important.We need to keep the same name so we're not constantly mapping between DTO <-> hand-rolled entity classes.Ideally the fact there's a DTO can mostly be hidden (or automated) and we only care when we need to that they exist.
There's a general wishes/needs for pseudo case classes, at least in my head.But if we are making json the king, and generating DTOs anyway, it makes sense to piggyback growable ABI agenda.I'm totally for start making pseudo case class generator.I agree on growable ABI. Sounds like we may need our own API which resembles the best in others? Is this what you're suggesting?
Is there a schema description language / schema files?
===
If the goal is to have both a file with case classes and a file with a
schema in some schema description language, then you can generate
either from the other, conceptually. The one thing that's clearly bad
is to write them BOTH by hand, because then they can be out of sync.Sort of. There's schema, DTO classes, and the marshaling/unmarshaling code.If we decide json is the king, then we start out with generating/inferring json schema, and then from there we generate both DTO and marshaling typeclass instances. For that we would need to write such tools ourselves.In the interim, I'm ok with manually writing both Json parsing code and pseudo case classes because at least I would have control over exactly what Json it's going to emit.In the interim this is ok, but I don't think the end user experience will be good enough.
On Wednesday, September 24, 2014 4:05:56 PM UTC+2, Havoc Pennington wrote:Hi,
Re: pickling, assuming we strip it down to only our needed API, some
known differences from play-json are:
* no AST; uses "streaming" instead (see
https://github.com/scala/pickling/blob/0.9.x/core/src/main/scala/pickling/PBuilderReader.scala
)
* abstracts binary vs. json
* may already be able to pickle non-case-classes (Eugene you just
said it could do the private-constructor class right)I'm not sure where Eugene got the impression that "the chief motivation (of pickling) is that it uses macros to auto serialize simple case classes". That's quite far from the truth (maybe you're confusing pickling with Salat?)
In the above, you also express concern over depending on a prerelease version. Databricks requires a final release for their integration with Spark by November 3rd. 0.8.0 is the current version of pickling. The changeset that we're sitting on that's targeted to go into 0.9.0 is enormous, and we're in a state where we can and should cut a 0.9.0 release ASAP (e.g., many of our users have moved from 0.8.0 to 0.9.0 SNAPSHOTs again). Thus, what we can do is this: we can cut a 0.9.0 release this week, and any of the larger/breaking changes that sbt needs, including pickler contravariance, we can put into 0.10.0. We could release 0.10.0 as soon as it covers all your immediate needs (like the two issues related to lightweight protocol evolution that Havoc pointed out), within the next few weeks. FYI, we'll also have another release, possibly 0.11.0, around November 3rd for Spark/Databricks.
My argument is that using serializer for long-term caching and restful API is not a good fit, because json needs to be the king, not case classes. Especially if we are thinking about requiring plugin authors to adopt the protocol, we need to make json the king.A point of pickling that's been missing a bit from this discussion is that *you* have control of the format (i.e., the JSON/binary that gets put on the wire). And you can also control how things are serialized. Thus, if you need JSON reading/writing to be made more powerful/flexible, you can fork/provide your own pickle format that is more focused on schema evolution, say (though, below we explain how we can/will address the specific issues Havoc summarized also for the generic formats that we ship).
So the TLDR is this: rather than needing to fork the entire framework, why not just do as intended and fork the JSON format? You can get almost everything that you require in doing so, and anything that needs additional support from the framework, we can add for you.
On Wed, Sep 24, 2014 at 10:19 AM, Heather Miller
<heather....@gmail.com> wrote:
>> minor detail, with pickling it wouldn't be raw JSON but rather some
>> kind of opaque blob.
>
>
> Not sure what makes you think so? How is this the case? (I could be
> confused/missing context)
The reason I say it wouldn't be raw JSON in pickling is that I'm
assuming (hoping, really) that a JSON AST is "out of scope" for the
main pickling API.
final case class TaskEvent(taskId: Long, name: String, serialized:
MyInventedOpaqueUnpickleable) extends Event
Just curious which bells and whistles do you have in mind?
BTW scalajs interop could actually be interesting, you could make a browser-based sbt client that way.
To view this discussion on the web visit https://groups.google.com/d/msgid/sbt-dev/CAA3p8zDesaqcP15YtHfvDMzGwVc9MKtMujg4WFw1gp20FNGRKw%40mail.gmail.com.
Just curious which bells and whistles do you have in mind?
BTW scalajs interop could actually be interesting, you could make a browser-based sbt client that way.