I recently came across some code:
val, ok := i.(SomeInterface)
if ok {
val.Method()
}
The above is Go, and attempts to cast to an interface and then runs the method for that interface against the struct if it is, if not it doesn't bother. I'm not really fussed on the specifics of how Go works, but the more general idea.
I've not really seen this idea in practice, and the idea is simple but powerful when working with generics. I have a gut feeling that this is bad, but having it available is really handy.
My specific use case is that I'm writing some firestore parsing code, which takes a doc and creates a object out of it. Firestore has a helpful 'dataTo' method that will parse it to the struct doing your typical field matching etc. BUT for some structs I need the ref to the doc, which I want something like object.Ref = document.Ref
. My choices seem limited:
- I accept the bloat and make all structs implement the interface to set the ID and make my generic function take that type, but then have a bunch of structs with useless stuff.
- Provide two functions, one that handles this case and one that does not, and support both functions, which is a bit of duplication.
Faced with the above, this little statement seems nice and neat, and honestly safe. I can check if it implements a 'SetRef' interface and if it does, use it and set the ref on the struct.
I have done some research and come across upcasting and downcasting in the OO world, and I believe this is very similar to upcasting, but I'm not sure if it strictly is, as I'm sort of asking 'is it this superclass' rather than 'I know it's this superclass, I'll cast to it' which seems like an important distinction.
Am I seeing ghosts in the closet here?