Re: [go-nuts] How to create a generic factory?

2023-12-31 Thread 'Axel Wagner' via golang-nuts
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  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  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
>> 
>> .
>>
>> --
> 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 discussio

Re: [go-nuts] How to create a generic factory?

2023-12-30 Thread Mazen Harake
@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  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
>  
> 
> .
>
>

-- 
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.


Re: [go-nuts] How to create a generic factory?

2023-12-30 Thread Mazen Harake
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  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
 

.

-- 
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/1021f10a-f45b-4491-9a5e-e585d91800f7n%40googlegroups.com.


Re: [go-nuts] How to create a generic factory?

2023-12-29 Thread 'Axel Wagner' via golang-nuts
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  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+unsubscr...@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
> 
> .
>

-- 
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/CAEkBMfH-NnvmvJ8h_EX2ZRcmyVH49P-VY7mYkPnPdr6Q-mxcww%40mail.gmail.com.


[go-nuts] How to create a generic factory?

2023-12-29 Thread Mazen Harake
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+unsubscr...@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.