Context
Writing a URL Query Parameter parser for Go language library
Problem
Only structs have a form of inheritance in Go, that I am aware of. One can use the reflect package to discern the kind of an entity, i.e. it's fundamental storage class within the type system, and one can probe the type of said element. So I can discern that the entity is of Kind string, and Type Title, as an arbitrary example, assuming something like this exists:
type Title string
Better, for structs, I can use anonymous members to gain a limited type of inheritance:
type Foo struct { name string }
func (f Foo) Hello() string { return f.name; }
type Bar struct { Foo }
func main() {
b := Bar{ Foo{"Simon"} }
fmt.Println(b.Hello())
}
The point being, Go allows me to extend a Foo as Bar but inherit / reuse Foo functions at least for the portion that is a Foo.
However, for a non-struct type - I am unaware as to how to approach this problem for an encoding/decoding library similar to json or xml - where I want to be able to decode query params into a struct's members, and crucially, be able to support user-defined types without requiring that every one of them defines a specialized decoder or encoder for my purposes, so long as they're derivatives of a type that supports an interface that I can utilize.
In the concrete, I would like to support user-defined types that are stored as a Google uuid.UUID, or a time.Time (or time.Duration would be useful as well).
Here's a simplistic example:
type TransactionID uuid.UUID
As declared, this inherits zero behaviors of uuid.UUID, and I'm not sure if, or how, to use reflect to intentionally make this happen in my encoder/decoder library?
Go itself won't provide any sort of inheritance or relationship between them. My TransactionID is NOT a uuid.UUID, but they share the same Kind - a [16]byte array, and to the best of my current knowledge, that is all they share.
This is my conundrum
How to allow a user defined type that I wish to support w/o requiring my users now define those same encoder or decoder functions for their type that I've already defined for the "fundamental" type?
Some More Context
My decoder library makes this interface available:
// Parser is an interface for types that RequestParser can parse from a URL parameter
type Parser interface {
ParseParameter(value string) error
}
And I have defined a specialized extension for uuid.UUID and time.Time and a few other useful non-struct types to decode them from query parameter strings. If the entity type I'm decoding into is literally a uuid.UUID or a time.Time and not a user-defined type based on those, then things work properly. Similarly, user aliases work because they're not genuine new types.
Aliases are too limited for my purposes - they do no provide any meaningful distinction from the aliased type, which severely limits their actual utility. I will not respond to suggestions that require their use instead. Thank you.
UPDATE
Ideally, a user should be able to define TransactionID for their purpose and I would like to know that it is a "kind of" UUID and hence - by default - use a UUID parser.
It is already trivially possible for a user to define:
func (id *TransactionID) ParseParameter(value string) (err error) {
id_, err := uuid.Parse(value)
if err != nil {
return
}
*id = TransactionID(id_)
return
}
This will force my decoder to choose their well-defined interface - and decode the input exactly as they wish for their type.
What I wish - is to have a way to know that their type is a derivative type of ____ what?, and if I have a parser for a ____ what - then -- in the absence of a user-defined ParseParameter -- use my default supplied smart one (which knows that a [16]byte is not the same thing as a UUID, and understands more sophisticated ways to decode a UUID).
Addendum
I will expand this question and provide more details as I get thoughtful and useful responses. I'm not sure at this point what else I might provide?
Thank you for taking the time to thoughtfully respond, should you choose to do so.