-
Notifications
You must be signed in to change notification settings - Fork 32
Open
Description
Proposal
This issue proposes that for the following JSON type definition:
{
"Thing": {
"discriminator": "type",
"mapping": {
"a": {
"properties": {}
},
"b": {
"properties": {}
},
"c": {
"properties": {}
}
}
}
}
jtd-codegen
should generate the following Go code:
type Thing struct {
Type string `json:"type"`
// Value can be the following types:
//
// - [A]
// - [B]
// - [C]
//
Value thingValue `json:"-"`
}
func (t *Thing) UnmarshalJSON(data []byte) error
func (t *Thing) MarshalJSON() ([]byte, error)
type thingValue interface {
isThing()
}
type ThingA struct{}
type ThingB struct{}
type ThingC struct{}
func (ThingA) isThing() {}
func (ThingB) isThing() {}
func (ThingC) isThing() {}
The user would consume the API like so:
var t Thing
switch v := t.Value.(type) {
case ThingA:
log.Println("thing contains type A")
case ThingB:
log.Println("thing contains type B")
case ThingC:
log.Println("thing contains type C")
default:
log.Println("thing contains unknown type")
}
If the user makes a mistake in the type-switch, the compiler will complain:
var t Thing
switch v := t.Value.(type) {
case ThingA:
log.Println("thing contains type A")
case string:
// does not even compile
}
This issue is an alternative to issue #49.
Rationale
Pros:
- Using interfaces instead of flat structs can sometimes takes up less space in
memory if the mapping is large. - The user can use type-switches to determine the type of the value, which is
more idiomatic and safer in Go than using a string field.
Cons:
- The magic field's name
Value
is not ideal. This is done because we can't
have custom marshalers and unmarshalers on an interface. - The magic field has an unexported type. Showing an unexported type in an
exported type is not ideal. - It's not explicit which types actually satisfy
TValue
outside a single
comment. This might be confusing to users.
nikole-dunixi
Metadata
Metadata
Assignees
Labels
No labels