Note that your code is not type-safe. It panics when instantiated with a type that does not use a pointer receiver: https://go.dev/play/p/eHUKtXvgwAu ISTM that being more type-safe would be an advantage here.
On Sat, Dec 30, 2023 at 8:47 PM Mazen Harake <mazen.har...@gmail.com> wrote: > @Alex, > > Oh, and I should point out that I actually went with what you mentioned in > your 1st point, I was just curious if it was possible to do it the other > way. > > On Saturday 30 December 2023 at 20:36:07 UTC+1 Mazen Harake wrote: > >> Cheers @Axel for the input. I think I worked it out though. >> >> The bad thing is that it involves reflection but considering that it >> greatly simplifies the code base I would argue that it is good enough for >> now. >> >> First, regarding your 2nd point of passing buf as a parameter to Decode() >> instead of through a field. The examples I gave are made up to resemble the >> actual situation to simplify it but what actually happens is that each >> message has a "BaseMessage" struct. When receiving some payload the common >> parts of the message (such as the length, type and checksums) are always >> decoded into base message, then depending on the type the specific message >> type is created and the rest of the bytes are decoded according to what >> that message expects. >> >> Anyway... this is the solution I came up with (for internet searching >> completeness sake): >> >> func DecodeMessage[T Decoder](bm *BaseMessage) (T, bool) { >> var mT T >> m := reflect.New(reflect.TypeOf(mT).Elem()).Interface().(T) >> d := Decoder(m) >> ok := d.Decode( bm ) >> return d.(T), ok >> } >> >> This function is then called with the following code example: >> >> transactionMsg, ok := DecodeMessage [*TransactionMessage](baseMsg) >> >> Cheers >> >> >> On Friday 29 December 2023 at 23:17:47 UTC+1 Axel Wagner wrote: >> >> 1. Note that you can just write `NewMessage(&MessageA{}, buf)` in your >> example, as the type can be inferred. >> 2. You can use a constraint on a pointer-receiver to somewhat simplify >> that: https://go.dev/play/p/pEu02Bn9t3f >> That is not *quite* what you are asking for. It is not actually possible >> to really do what you want, because there is no way to express a constraint >> that "the type needs to have a `Buf []byte` field, which would be needed to >> make your `m := &MessageAStruct{Buf: b}` work. But there isn't really a >> reason to pass the buffer as a field anyways, in my opinion - passing it as >> a parameter to `Decode` seems far more logical. >> >> On Fri, Dec 29, 2023 at 8:52 PM Mazen Harake <mazen....@gmail.com> wrote: >> >> Hi all, >> >> Assume I have a tcp server with incoming tcp packets which can be decoded >> in differently depending on some headers in that packet. >> >> Each message that comes in has a struct associated with it which can be >> created with the traditionale NewX..(buf []byte ...). After creating the >> object (or inside the constructor, doesn't matter) the Decode() function is >> called to interpret the bytes and assign all the fields of the struct. >> >> This works fine. But is it possible to eliminate all the 200+ functions >> that do the same thing but use a generic function instead? >> >> So instead of this: >> >> func NewMessageA(buf []byte) *MessageAStruct { >> m := &MessageAStruct{ >> Buf: buf, >> } >> m.Decode() >> return m >> } >> >> msg := NewMessageA(buf) >> >> I would rather do something like this: >> >> msg := NewMessage[A](buf) >> >> and I would've wanted to do something like this in the generic function >> >> func NewMessage[T](buf []byte) *T { >> // ... something? >> // call Decode() >> // return *T >> } >> >> I can do it by creating an interface called Decodable and then passing >> the the type and the "empty" object to the generic function but it feels >> clumsy and weird somehow and I probably wouldn't gain very much. E.g. >> >> func NewMessage[T Decodable](t T, buf []byte) T { >> t.Decode(buf) >> return t >> } >> >> and I would call it like this >> >> msg := NewMessage[*MessageA](&MessageA{}, buf) >> >> The most likely answer is "You shouldn't do it like that", which would be >> a completely fine and acceptable answer, but *can* you achieve this? >> >> Cheers >> >> -- >> You received this message because you are subscribed to the Google Groups >> "golang-nuts" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to golang-nuts...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/golang-nuts/5dc5715c-aad9-431f-8ea0-9c89db46d873n%40googlegroups.com >> <https://groups.google.com/d/msgid/golang-nuts/5dc5715c-aad9-431f-8ea0-9c89db46d873n%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> >> -- > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to golang-nuts+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/golang-nuts/8149b0ed-0846-4634-8503-899a05ea8a25n%40googlegroups.com > <https://groups.google.com/d/msgid/golang-nuts/8149b0ed-0846-4634-8503-899a05ea8a25n%40googlegroups.com?utm_medium=email&utm_source=footer> > . > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAEkBMfFi6cF48ayVYyg6mcREisP5SB6fd87A%2Bsy-XMA6B0fZEw%40mail.gmail.com.