A small downside, maybe:
What if one has a reuse of the same structural type in several places of another type, like:
enum T = A { i : Int, f : Float} | B { i : Int, f : Float} deriving JSON
Under the scheme as described, this would probably create twice the same code for serializing an i and an f, once for the A variant and once for the B variant.
The only way to avoid this code duplication would seem to be to introduce a shared name explicitly:
type P = { i : Int, f : Float} deriving JSON
enum T = A P | B P deriving JSON
In contrast, with instance resolution a la type classes like in Haskell, no extra precautions by the programmer are needed to ensure that
data T = A (Int, Float) | B (Int, Float) deriving JSON
does not create duplicate code for serializing an
(Int, Float) pair. That would be guaranteed automatically, since by the design of the type class mechanism there cannot even exist more than one instance of the type class for
(Int, Float).
But probably this issue is not all too dramatic. Replacing
enum T = A { i : Int, f : Float} | B { i : Int, f : Float} deriving JSON
by
type P = { i : Int, f : Float} deriving JSON
enum T = A P | B P deriving JSON
might be a worthwhile refactoring for other reasons anyway.