Do newtypes have the same JSON encoding as their wrapped types?

newtype Foo = Foo Bar
data Bar = Bar Int

Foo and Bar have the same runtime representation, but does that translate to JSON? Will Foo be JSON encoded as data Foo = Foo Bar or as Bar?

No, newtypes are not special in LF and therefore also not special in the JSON encoding. They create a record type with a single field for the wrapped type. By default the field is named unpack but you can change it, e.g.,

newtype F = F { notunpack : Int }

If that record type is present at the LF level, does newtype still provide a zero-overhead abstraction?

No newtypes are equivalent to defining the record type yourself so they do have overhead. The only advantage of using a newtype is that you can autoderive some typeclass instances from the underlying type via generalized newtype deriving.

@cocreature I’m 100% certain that you explained it before, but what’s the limitation to always unwrapping newtype’s during compilation?

I don’t think there is a fundamental reason why we couldn’t unwrap them. It’s more a design decision: They are separate types in Daml, so we want them to be separate types on the ledger API and therefore also separate types in Daml-LF.

Now that doesn’t imply that they cannot be identical at runtime to improve costs (after all that’s how things work in Haskell). That just never seemed like an optimization worth doing so far but maybe that’ll change in the future.

1 Like

Thank you.

As @asarpeshkar perhaps anticipated, even should we make this optimization, we wouldn’t necessarily be forced to apply it to the JSON representation, or the ledger API representation, as well. Those would be separate questions to answer at that time, though I imagine we might want the JSON API and gRPC representations to be aligned, if not with the interpreter’s representation.