To me this example, even though good at explaining reflection and generics is also a good example of creating the kind of abstractions that Go wants to avoid by being very explicit, little to no “magic” (as in hiding complexity or functionality). Also see Go proverbs such as “Clear is better than clever.” and “Reflection is never clear.”
I was actually surprised go had reflection at all, especially given how much they fought against generic typing
I think it’s main use case that is also idiomatic is tags to serializers. There’s also other uses of course, but not all of them are not considered idiomatic.
Given that their website for over a decade said that they might add generics at a later point saying they fought against it seems like a stretch.
Straightforward introduction, but it makes me nervous that there’s still only one User type, so the type system would happily allow inserting an unencrypted User into the database. I’d feel much safer with UserPlaintext and UserEncrypted structs to design my APIs around.
Yeah, I don’t think this problem really fits with generics at all. I would write a function EncryptFields(s any) and then in User, have a MarshalJSON method that copies the user, calls EncryptFields on the copy, and then calls json.Marshall with a method-less type plainUser User like json.Marshal((*plainUser)(&encryptedUser)).
type plainUser User
I’m really not sold on this approach, but I’m not sure if it’s because I just don’t like the opacity of whether a field is going to be encrypted, or that there are plain text fields at all.
In my experience any time you have data where some fields need to be encrypted, in the long run you end up discovering the plaintext fields are privacy sensitive. E.g if you think some fields need to be encrypted, then you should just encrypt every field.